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

namespace rjw
{
	[StaticConstructorOnStartup]
	public static class AddComp
	{
		static AddComp()
		{
			AddRJWComp();
		}

		/// <summary>
		/// This automatically adds the comp to all races on startup.
		/// </summary>
		public static void AddRJWComp()
		{
			foreach (ThingDef thingDef in DefDatabase<ThingDef>.AllDefs.Where(thingDef =>
					thingDef.race != null))
			{
				thingDef.comps.Add(new CompProperties_RJW());
				//Log.Message("AddRJWComp to race " + thingDef.label);
			}

			foreach (PawnKindDef pawnKindDef in DefDatabase<PawnKindDef>.AllDefs.Where(pawnKindDef => pawnKindDef.race.race != null))
			{
				RaceGroupDef raceGroupDef = null;
				if (RaceGroupDef_Helper.TryGetRaceGroupDef(pawnKindDef, out raceGroupDef))
				{
					//Log.Message("RaceGroupDef_Helper " + raceGroupDef.defName + " for " + pawnKindDef.race.defName);
					if (raceGroupDef.oviPregnancy)
					{
						if (pawnKindDef.race.comps.Any(x => x is CompProperties_EggLayer))
						{
							//Log.Message(pawnKindDef.race.defName + " was already egglayer");
						}
						else
						{
							CompProperties_EggLayer eggProps = OviHelper.GenerateEggLayerProperties(pawnKindDef, raceGroupDef);
							pawnKindDef.race.comps.Add(eggProps);
							//Log.Message(pawnKindDef.race.defName + " is now egglayer and lays " + eggProps.eggFertilizedDef.defName + " eggs");
						}
					}
				}
			}

			// For some reason eggs only grow if a pawn has a lifestage that is "milkable"
			// This might not be ideal...
			foreach (LifeStageDef lifeStage in DefDatabase<LifeStageDef>.AllDefs)
			{
				if (lifeStage.reproductive)
				{
					lifeStage.milkable = true;
				}
			}
		}
	}
}


code:
using Verse;

namespace rjw
{
	public class CompProperties_RJW : CompProperties
	{
		public CompProperties_RJW()
		{
			compClass = typeof(CompRJW);
		}
	}

	public class CompProperties_HediffBodyPart : HediffCompProperties
	{
		public CompProperties_HediffBodyPart()
		{
			compClass = typeof(CompHediffBodyPart);
		}
	}

	public class CompProperties_ThingBodyPart : CompProperties
	{
		public CompProperties_ThingBodyPart()
		{
			compClass = typeof(CompThingBodyPart);
		}
	}
}

repo_name: ElToro/rjw

license: mit


code:
using Psychology;
using SyrTraits;
using System.Text;
using Verse;
using RimWorld;
using Multiplayer.API;

namespace rjw
{
	public class CompRJW : ThingComp
	{
		/// <summary>
		/// Core comp for genitalia and sexuality tracking.
		/// </summary>
		public CompRJW()
		{
			orientation = Orientation.None;
			quirks = new StringBuilder();
		}

		public CompProperties_RJW Props => (CompProperties_RJW)props;
		public Orientation orientation;
		public StringBuilder quirks;
		public string quirksave; // Not the most elegant way to do this, but it minimizes the save bloat.
		public int NextHookupTick;

		// This automatically checks that genitalia has been added to all freshly spawned pawns.
		public override void PostSpawnSetup(bool respawningAfterLoad)
		{
			base.PostSpawnSetup(respawningAfterLoad);

			if (!(parent is Pawn pawn))
				return;

			if (pawn.kindDef.race.defName.Contains("AIRobot") // No genitalia/sexuality for roombas.
				|| pawn.kindDef.race.defName.Contains("AIPawn") // ...nor MAI.
				|| pawn.kindDef.race.defName.Contains("RPP_Bot")
				) return;

			// No genitalia
			//if (!pawn.RaceProps.body.AllParts.Exists(x => x.def == DefDatabase<BodyPartDef>.GetNamed("Genitals")))
			//	return;

			if (Comp(pawn).orientation == Orientation.None)
			{
				Sexualize(pawn);
				Sexualize(pawn, true);
			}

			//Log.Message("PostSpawnSetup for " + pawn?.Name);
		}

		public override void PostExposeData()
		{
			base.PostExposeData();
			if (!(parent is Pawn))
				return;

			// Saves the data.
			Scribe_Values.Look(ref orientation, "RJW_Orientation");
			Scribe_Values.Look(ref quirksave, "RJW_Quirks");
			Scribe_Values.Look(ref NextHookupTick, "RJW_NextHookupTick");

			//Log.Message("PostExposeData for " + pawn?.Name);

			// Restore quirk data from the truncated save version.
			quirks = new StringBuilder(quirksave);
		}

		public static CompRJW Comp(Pawn pawn)
		{
			// Call CompRJW.Comp(pawn).<method> to check sexuality, etc.
			return pawn.GetComp<CompRJW>();
		}

		public static void CopyPsychologySexuality(Pawn pawn)
		{
			try
			{
				int kinsey = pawn.TryGetComp<CompPsychology>().Sexuality.kinseyRating;
				//Orientation originalOrientation = Comp(pawn).orientation;

				if (!Genital_Helper.has_genitals(pawn) && pawn.kindDef.race.defName.ToLower().Contains("droid"))
					Comp(pawn).orientation = Orientation.Asexual;
				else if (kinsey == 0)
					Comp(pawn).orientation = Orientation.Heterosexual;
				else if (kinsey == 1)
					Comp(pawn).orientation = Orientation.MostlyHeterosexual;
				else if (kinsey == 2)
					Comp(pawn).orientation = Orientation.LeaningHeterosexual;
				else if (kinsey == 3)
					Comp(pawn).orientation = Orientation.Bisexual;
				else if (kinsey == 4)
					Comp(pawn).orientation = Orientation.LeaningHomosexual;
				else if (kinsey == 5)
					Comp(pawn).orientation = Orientation.MostlyHomosexual;
				else if (kinsey == 6)
					Comp(pawn).orientation = Orientation.Homosexual;
				else
					Comp(pawn).orientation = Orientation.Asexual;
				/*else
					Log.Error("RJW::ERRROR - unknown kinsey scale value: " + kinsey);/*

				/*if (Comp(pawn).orientation != originalOrientation)
					Log.Message("RJW + Psychology: Inherited pawn " + xxx.get_pawnname(pawn) + " sexuality from Psychology - " + Comp(pawn).orientation);*/
			}
			catch
			{
				if (!pawn.IsAnimal())
					ModLog.Warning("CopyPsychologySexuality " + pawn?.Name + ", def: " + pawn?.def?.defName + ", kindDef: " + pawn?.kindDef?.race.defName);
			}
		}

		public static void CopyIndividualitySexuality(Pawn pawn)
		{
			try
			{
				CompIndividuality.Sexuality individualitySexuality = pawn.TryGetComp<CompIndividuality>().sexuality;
				//Orientation originalOrientation = Comp(pawn).orientation;

				if (individualitySexuality == CompIndividuality.Sexuality.Asexual)
						Comp(pawn).orientation = Orientation.Asexual;
				else if (!Genital_Helper.has_genitals(pawn) && pawn.kindDef.race.defName.ToLower().Contains("droid"))
					Comp(pawn).orientation = Orientation.Asexual;
				else if (individualitySexuality == CompIndividuality.Sexuality.Straight)
					Comp(pawn).orientation = Orientation.Heterosexual;
				else if (individualitySexuality == CompIndividuality.Sexuality.Bisexual)
					Comp(pawn).orientation = Orientation.Bisexual;
				else if (individualitySexuality == CompIndividuality.Sexuality.Gay)
					Comp(pawn).orientation = Orientation.Homosexual;
				else
					Comp(pawn).orientation = Orientation.Asexual;

				/*if (Comp(pawn).orientation != originalOrientation)
					Log.Message("RJW + [SYR]Individuality: Inherited pawn " + xxx.get_pawnname(pawn) + " sexuality from Individuality - " + Comp(pawn).orientation);*/
			}
			catch
			{
				if (!pawn.IsAnimal())
					ModLog.Warning("CopyIndividualitySexuality " + pawn?.Name + ", def: " + pawn?.def?.defName + ", kindDef: " + pawn?.kindDef?.race.defName);
			}
		}

		[SyncMethod]
		public static void VanillaTraitCheck(Pawn pawn)
		{
			//Orientation originalOrientation = Comp(pawn).orientation;
			if (pawn.story.traits.HasTrait(TraitDefOf.Asexual))
				Comp(pawn).orientation = Orientation.Asexual;
			else if (!Genital_Helper.has_genitals(pawn) && pawn.kindDef.race.defName.ToLower().Contains("droid"))
				Comp(pawn).orientation = Orientation.Asexual;
			else if(pawn.story.traits.HasTrait(TraitDefOf.Gay))
				Comp(pawn).orientation = Orientation.Homosexual;
			else if (pawn.story.traits.HasTrait(TraitDefOf.Bisexual))
				Comp(pawn).orientation = Orientation.Bisexual;
			else
				Comp(pawn).orientation = Orientation.Heterosexual;
		}

		// The main method for adding genitalia and orientation.
		public void Sexualize(Pawn pawn, bool reroll = false)
		{
			if (reroll)
			{
				Comp(pawn).orientation = Orientation.None;

				if (xxx.has_quirk(pawn, "Fertile"))
				{
					Hediff fertility = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("IncreasedFertility"));
					if (fertility != null )
						pawn.health.RemoveHediff(fertility);
				}
				if (xxx.has_quirk(pawn, "Infertile"))
				{
					Hediff fertility = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("DecreasedFertility"));
					if (fertility != null)
						pawn.health.RemoveHediff(fertility);
				}
				quirks = new StringBuilder();
			}
			else if (Comp(pawn).orientation != Orientation.None)
				return;

			//roll random RJW orientation
			Comp(pawn).orientation = xxx.is_animal(pawn) ? RollAnimalOrientation(pawn) : RollOrientation(pawn);

			//Asexual nymp re-roll
			//if (xxx.is_nympho(pawn))
			//	while (Comp(pawn).orientation == Orientation.Asexual)
			//	{
			//		Comp(pawn).orientation = RollOrientation();
			//	}

			//Log.Message("Sexualizing pawn " + pawn?.Name + ", def: " + pawn?.def?.defName);

			if (!reroll)
				Sexualizer.sexualize_pawn(pawn);
			//Log.Message("Orientation for pawn " + pawn?.Name + " is " + orientation);

			if (xxx.has_traits(pawn) && Genital_Helper.has_genitals(pawn) && !(pawn.kindDef.race.defName.ToLower().Contains("droid") && !AndroidsCompatibility.IsAndroid(pawn)))
			{
				if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Vanilla)
					VanillaTraitCheck(pawn);
				if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Psychology)
					CopyPsychologySexuality(pawn);
				if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.SYRIndividuality)
					CopyIndividualitySexuality(pawn);
			}
			else if ((pawn.kindDef.race.defName.ToLower().Contains("droid") && !AndroidsCompatibility.IsAndroid(pawn)) || !Genital_Helper.has_genitals(pawn))
			{
				// Droids with no genitalia are set as asexual.
				// If player later adds genitalia to the droid, the droid 'sexuality' gets rerolled.
				Comp(pawn).orientation = Orientation.Asexual;
			}

			QuirkAdder.Generate(pawn);

			if (quirks.Length == 0)
			{
				quirks.Append("None");
				quirksave = quirks.ToString();
			}
		}

		[SyncMethod]
		public static bool CheckPreference(Pawn pawn, Pawn partner)
		{
			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Vanilla)
			{
				if (xxx.has_traits(pawn))
					VanillaTraitCheck(pawn);
				if (xxx.has_traits(partner))
					VanillaTraitCheck(partner);
			}
			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.SYRIndividuality)
			{
					CopyIndividualitySexuality(pawn);
					CopyIndividualitySexuality(partner);
			}
			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Psychology)
			{
				if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Psychology)
					CopyPsychologySexuality(pawn);
					CopyPsychologySexuality(partner);
			}

			//if (xxx.is_mechanoid(pawn))
			//	return false;

			Orientation ori = Orientation.None;
			try
			{
				ori = Comp(pawn).orientation;
			}
			catch
			{
				//ModLog.Message("Error, pawn:" + pawn + " doesn't have orientation comp, modded race?");
				return false;
			}

			if (ori == Orientation.Pansexual || ori == Orientation.Bisexual)
				return true;

			if (ori == Orientation.Asexual)
				return false;

			var pawnpartBPR = Genital_Helper.get_genitalsBPR(pawn);
			var pawnparts = Genital_Helper.get_PartsHediffList(pawn, pawnpartBPR);
			var pawn_has_vagina = Genital_Helper.has_vagina(pawn, pawnparts);
			var pawn_has_penis_fertile = Genital_Helper.has_penis_fertile(pawn, pawnparts);
			var pawn_has_penis_infertile = Genital_Helper.has_penis_infertile(pawn, pawnparts);

			var partnerpartBPR = Genital_Helper.get_genitalsBPR(partner);
			var partnerparts = Genital_Helper.get_PartsHediffList(partner, partnerpartBPR);
			var partner_has_vagina = Genital_Helper.has_vagina(partner, partnerparts);
			var partner_has_penis_fertile = Genital_Helper.has_penis_fertile(partner, partnerparts);
			var partner_has_penis_infertile = Genital_Helper.has_penis_infertile(partner, partnerparts);

			bool isHetero = (pawn_has_vagina && (partner_has_penis_fertile || partner_has_penis_infertile)) ||
						  (partner_has_vagina && (pawn_has_penis_fertile || pawn_has_penis_infertile));

			bool isHomo = (pawn_has_vagina && partner_has_vagina) ||
						   ((partner_has_penis_fertile || partner_has_penis_infertile) && (pawn_has_penis_fertile || pawn_has_penis_infertile));

			if (isHetero && isHomo)
			{
				// Oh you crazy futas.  We could probably do a check against the pawn's gender, but eh.  They've got so many parts available, they'll find something to do.
				return true;
			}

			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			switch (ori)
			{
				case Orientation.Heterosexual:
					return !isHomo;
				case Orientation.MostlyHeterosexual:
					return (!isHomo || Rand.Chance(0.2f));
				case Orientation.LeaningHeterosexual:
					return (!isHomo || Rand.Chance(0.6f));
				case Orientation.LeaningHomosexual:
					return (!isHetero || Rand.Chance(0.6f));
				case Orientation.MostlyHomosexual:
					return (!isHetero || Rand.Chance(0.2f));
				case Orientation.Homosexual:
					return !isHetero;
				default:
					ModLog.Error("ERROR - tried to check preference for undetermined sexuality.");
					return false;
			}
		}

		[SyncMethod]
		public Orientation RollOrientation(Pawn pawn)
		{
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			float random = Rand.Range(0f, 1f);
			float checkpoint = RJWPreferenceSettings.asexual_ratio / RJWPreferenceSettings.GetTotal();

			float checkpoint_pan = checkpoint + (RJWPreferenceSettings.pansexual_ratio / RJWPreferenceSettings.GetTotal());
			float checkpoint_het = checkpoint_pan + (RJWPreferenceSettings.heterosexual_ratio / RJWPreferenceSettings.GetTotal());
			float checkpoint_bi = checkpoint_het + (RJWPreferenceSettings.bisexual_ratio / RJWPreferenceSettings.GetTotal());
			float checkpoint_gay = checkpoint_bi + (RJWPreferenceSettings.homosexual_ratio / RJWPreferenceSettings.GetTotal());

			if (random < checkpoint || !Genital_Helper.has_genitals(pawn))
				return Orientation.Asexual;
			else if (random < checkpoint_pan)
				return Orientation.Pansexual;
			else if (random < checkpoint_het)
				return Orientation.Heterosexual;
			else if (random < checkpoint_het + ((checkpoint_bi - checkpoint_het) * 0.33f))
				return Orientation.MostlyHeterosexual;
			else if (random < checkpoint_het + ((checkpoint_bi - checkpoint_het) * 0.66f))
				return Orientation.LeaningHeterosexual;
			else if (random < checkpoint_bi)
				return Orientation.Bisexual;
			else if (random < checkpoint_bi + ((checkpoint_gay - checkpoint_bi) * 0.33f))
				return Orientation.LeaningHomosexual;
			else if (random < checkpoint_bi + ((checkpoint_gay - checkpoint_bi) * 0.66f))
				return Orientation.MostlyHomosexual;
			else
				return Orientation.Homosexual;
		}

		// Simpler system for animals, with most of them being heterosexual.
		// Don't want to disturb player breeding projects by adding too many gay animals.
		[SyncMethod]
		public Orientation RollAnimalOrientation(Pawn pawn)
		{
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			float random = Rand.Range(0f, 1f);

			if (random < 0.03f || !Genital_Helper.has_genitals(pawn))
				return Orientation.Asexual;
			else if (random < 0.85f)
				return Orientation.Heterosexual;
			else if (random < 0.96f)
				return Orientation.Bisexual;
			else
				return Orientation.Homosexual;
		}
	}
}


code:
using RimWorld;

namespace rjw
{
	public class CompRJWHatcher : CompHatcher
	{
	}
}


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

namespace rjw
{
	/// <summary>
	/// Comp for rjw hediff parts
	/// </summary>
	public class CompHediffBodyPart : HediffComp
	{
		public string Size => parent.CurStage?.label ?? "";
		public string RaceOwner = "Unknows species";		//base race when part created
		public string PreviousOwner = "Unknows";			//base race when part created
		public float SizeBase;								//base size when part created, someday alter by operation
		public float SizeOwner = 0;							//modifier of 1st owner race body size
		public float EffSize;								//SizeBase x SizeOwner = current size | hediff.severity
		public string FluidType = "";						//cummies/milk - insectjelly/honey etc
		public float FluidAmmount;							//amount of Milk/Ejaculation/Wetness
		public float FluidModifier = 1f;					//
		public string Eggs;									//for ovi eggs, maybe

		/// <summary>
		/// part size in labels
		/// </summary>

		//public override string CompLabelInBracketsExtra
		//{
		//	get
		//	{
		//		if (Size != "")
		//			return Size;

		//		return null;
		//	}
		//}

		/// <summary>
		/// save data
		/// </summary>
		public override void CompExposeData()
		{
			base.CompExposeData();
			Scribe_Values.Look(ref SizeBase, "SizeBase");
			Scribe_Values.Look(ref SizeOwner, "SizeOwner");
			Scribe_Values.Look(ref RaceOwner, "RaceOwner");
			Scribe_Values.Look(ref PreviousOwner, "PreviousOwner");
			Scribe_Values.Look(ref FluidType, "FluidType");
			Scribe_Values.Look(ref FluidAmmount, "FluidAmmount");
			Scribe_Values.Look(ref FluidModifier, "FluidModifier");
			Scribe_Values.Look(ref Eggs, "Eggs");
		}

		/// <summary>
		/// show part info in healthab
		/// </summary>
		public override string CompTipStringExtra
		{
			get
			{
				if (SizeOwner == 0)
				{
					ModLog.Warning(" " + xxx.get_pawnname(Pawn) + " part " + parent.def.defName + " is broken, resetting");
					initComp();
					updatesize();
					updatepartposition();
				}
				// In theory the tip should be a condensed form and the longer form should be elsewhere, but where?
				return GetTipString(RJWSettings.ShowRjwParts == RJWSettings.ShowParts.Extended).Join("\n");
			}
		}

		IEnumerable<string> GetTipString(bool extended)
		{
			//ModLog.Message(" CompTipStringExtra " + xxx.get_pawnname(Pawn) + " " + parent.def.defName);
			// TODO: Part type should be a property in the extension.
				//StringBuilder defstringBuilder = new StringBuilder();
			if (parent.def.defName.ToLower().Contains("breasts"))
			{
				return GetBreastTip(extended);
			}
			else if (parent.def.defName.ToLower().Contains("penis"))
			{
				return GetPenisTip(extended);
			}
			else if (parent.def.defName.ToLower().Contains("anus") || parent.def.defName.ToLower().Contains("vagina"))
			{
				return GetOrificeTip(extended);
			}
			else if (parent.def.defName.ToLower().Contains("ovi"))
			{
				return GetEggTip(extended);
			}

			return Enumerable.Empty<string>();
		}

		IEnumerable<string> GetEggTip(bool extended)
		{
			if (Eggs != "")
			{
				yield return "RJW_hediff_eggs".Translate(Eggs);
			}
		}

		IEnumerable<string> GetPenisTip(bool extended)
		{
			if (PartSizeExtension.TryGetLength(parent, out float length))
			{
				yield return "RJW_hediff_length".Translate(length.ToString("F1"));
			}

			if (!extended)
			{
				yield break;
			}

			if (PartSizeExtension.TryGetGirth(parent, out float girth))
			{
				yield return "RJW_hediff_girth".Translate(girth.ToString("F1"));
			}

			if (PartSizeExtension.TryGetPenisWeight(parent, out float weight))
			{
				yield return "RJW_hediff_weight".Translate(weight.ToString("F1"));
			}

			foreach (var line in GetFluidTip())
			{
				yield return line;
			}

			if (PartProps.TryGetProps(parent, out List<string> propslist))
			{
				yield return "Properties: " + propslist.ToCommaList();
			}
		}

		IEnumerable<string> GetOrificeTip(bool extended)
		{
			if (!extended)
			{
				yield break;
			}
				//defstringBuilder.Append(this.Def.description);
				//defstringBuilder.AppendLine("Cum: " + FluidType);
				//defstringBuilder.AppendLine("Ejaculation: " + (FluidAmmount * FluidModifier).ToString("F2") + "ml");

			// TODO: Should be scaled bigger than penis size either in xml or here.
			if (PartSizeExtension.TryGetLength(parent, out float length))
			{
				yield return "RJW_hediff_maxLength".Translate(length.ToString("F1"));
			}

			if (PartSizeExtension.TryGetGirth(parent, out float girth))
			{
				yield return "RJW_hediff_maxGirth".Translate(girth.ToString("F1"));
			}

			foreach (var line in GetFluidTip())
			{
				yield return line;
			}
		}

		IEnumerable<string> GetBreastTip(bool extended)
		{
			foreach (var line in GetBraSizeTip())
			{
				yield return line;
			}

			if (!extended)
			{
				yield break;
			}

			if (PartSizeExtension.TryGetCupSize(parent, out float size))
			{
				var cupSize = (int)size;

				if (cupSize > 0)
				{
					if (PartSizeExtension.TryGetOverbustSize(parent, out float overbust))
					{
						var underbust = PartSizeExtension.GetUnderbustSize(parent);
						yield return "RJW_hediff_underbust".Translate(underbust.ToString("F1"));
						yield return "RJW_hediff_overbust".Translate(overbust.ToString("F1"));
					}

					if (PartSizeExtension.TryGetBreastWeight(parent, out float weight))
					{
						yield return "RJW_hediff_weight".Translate(weight.ToString("F1"));
					}
				}
			}

			foreach (var line in GetFluidTip())
			{
				yield return line;
			}
		}

		IEnumerable<string> GetBraSizeTip()
		{
			if (PartSizeExtension.TryGetCupSize(parent, out float size))
			{
				var bandSize = PartSizeExtension.GetBandSize(parent);
				var cupSize = (int)size;

				if (cupSize > 0)
				{
					yield return "RJW_hediff_braSize".Translate(
						bandSize,
						cupSize,
						PartStagesDef.GetCupSizeLabel(cupSize));
				}
				else
				{
					yield return "RJW_hediff_braSizeNone".Translate();
				}
			}
		}

		IEnumerable<string> GetFluidTip()
		{
			if (FluidAmmount != 0 && FluidType != "")
			{
				yield return "RJW_hediff_fluidTypeFluidAmount".Translate(
					FluidType,
					(FluidAmmount * FluidModifier).ToString("F1"));
			}
		}

		//TODO: someday part(SizeOwner) change operations
		public void updatesize(float value = 0)
		{
			if (value == 0)
			{
				//Log.Message("CompHediffBodyPart::updatesize part size ( " + SizeOwner + " )");
				//Log.Message("CompHediffBodyPart::updatesize owner size ( " + parent.pawn.BodySize + " )");
				if (SizeOwner < parent.pawn.BodySize)
				{
					incsize();
				}
				else
				{
					decsize();
				}

			}
			else
			{
				if (value > 0)
					incsize(value);
				else
					decsize(value);
			}
		}

		//scale parts to bodysize
		public void incsize(float value = 0)
		{
			if (value < 0)
				return;
			if (value == 0)
			{
				value = (parent.pawn.BodySize - SizeOwner) / parent.pawn.BodySize;
			}
			if (value != 0)
			{
				//Log.Message(xxx.get_pawnname(pawn) + " updatesize " + parent.def.defName);
				//Log.Message("CompHediffBodyPart::updatesize - increase");
				//Log.Message("CompHediffBodyPart::updatesize( " + SizeOwner + " )");
				//Log.Message("CompHediffBodyPart::updatesize( " + parent.pawn.BodySize + " )");
				//Log.Message("CompHediffBodyPart::updatesize - value");
				//Log.Message("CompHediffBodyPart::updatesize( " + value + " )");
			}
			value = SizeBase * (1 + value);
			parent.Severity = value;
		}

		public void decsize(float value = 0)
		{
			if (value > 0)
				return;
			if (value == 0)
			{
				value = (SizeOwner - parent.pawn.BodySize) / SizeOwner;
			}
			if (value != 0)
			{
				//Log.Message(xxx.get_pawnname(pawn) + " updatesize " + parent.def.defName);
				//Log.Message("CompHediffBodyPart::updatesize - decrease");
				//Log.Message("CompHediffBodyPart::updatesize( " + SizeOwner + " )");
				//Log.Message("CompHediffBodyPart::updatesize( " + parent.pawn.BodySize + " )");
				//Log.Message("CompHediffBodyPart::updatesize - value");
				//Log.Message("CompHediffBodyPart::updatesize( " + value + " )");
			}
			value = SizeBase * (1 - value);
			if (value <= 0)
			{
				value = 0.01f;
			}
			parent.Severity = value;
		}

		[SyncMethod]
		public void updatepartposition()
		{
			var partBase = parent.def as HediffDef_PartBase;
			if (partBase != null)
			{
				if (parent.Part == null || partBase.DefaultBodyPart != "" && parent.Part.def.defName != partBase.DefaultBodyPart)
				{
					ModLog.Warning(" " + xxx.get_pawnname(Pawn) + " part " + parent.def.defName + " is in wrong BodyPart position, resetting to default");
					var bp = parent.pawn.RaceProps.body.AllParts.Find(x => x.def.defName.Contains(partBase.DefaultBodyPart));
					//if (pawn.IsColonist)
					//{
					//	Log.Message(xxx.get_pawnname(pawn) + " has broken hediffs, removing " + this.ToString());
					//	Log.Message(Part.ToString());
					//	Log.Message(bp.def.defName);
					//	Log.Message(partBase.DefaultBodyPart.ToString());
					//}
					parent.Part = bp;
				}
			}
		}

		/// <summary>
		/// fill comp data
		/// </summary>
		[SyncMethod]
		public void initComp(Pawn pawn = null, bool reroll = false)
		{
			if (pawn == null)
				pawn = parent.pawn;

			double value = Rand.Range(0.01f, 1);
			bool trap = false;
			if (reroll == true)
				value = SizeBase;
			{
				if (parent.def.defName.ToLower().Contains("breast"))
				{
					//FluidType = "Milk";
					FluidAmmount = 0;

					if (pawn != null)
					{
						if (pawn.gender == Gender.Male && RJWSettings.MaleTrap)
							if (pawn.Faction != null && !xxx.is_animal(pawn)) //null faction throws error
							{
								//natives/spacer futa
								float chance = (int)pawn.Faction.def.techLevel < 5 ? RJWSettings.futa_natives_chance : RJWSettings.futa_spacers_chance;
								//nymph futa gender
								chance = xxx.is_nympho(pawn) ? RJWSettings.futa_nymph_chance : chance;

								if (Rand.Chance(chance))
								{
									//make trap
									trap = true;
								}
							}

						if (pawn.gender == Gender.Male && !trap && reroll == false)
							value = 0.01f;

					}
				}
				else if (parent.def.defName.ToLower().Contains("penis") || parent.def.defName.ToLower().Contains("Ovipositorf") || parent.def.defName.ToLower().Contains("Ovipositorm"))
				{
					FluidAmmount = (float)value * pawn.RaceProps.baseBodySize * pawn.RaceProps.baseBodySize * 10 * 2 * Rand.Range(0.75f, 1.25f);
				}
				else if (parent.def.defName.ToLower().Contains("vagina"))
				{
					FluidAmmount = (float)value * pawn.RaceProps.baseBodySize * pawn.RaceProps.baseBodySize * 10 * Rand.Range(0.75f, 1.25f);
				}
				else if (parent.def.defName.ToLower().Contains("anus"))
				{
					FluidAmmount = 0;
				}
				else if (parent.def.defName.ToLower().Contains("tentacle"))
				{
					value *= 2;
					FluidAmmount = (float)value * pawn.RaceProps.baseBodySize * pawn.RaceProps.baseBodySize * 10 * 2 * Rand.Range(0.75f, 1.25f);
				}
				if (parent.def.defName.ToLower().Contains("ovi"))
				{
					Eggs = pawn?.kindDef?.label ?? "";
				}

				FluidType = (parent.def as HediffDef_PartBase).FluidType;
				SizeBase = (float)value;
				SizeOwner = pawn?.RaceProps?.baseBodySize ?? 1.0f;
				RaceOwner = pawn?.kindDef?.race.LabelCap ?? "RJW_hediff_unknownSpecies".Translate();
				PreviousOwner = xxx.get_pawnname(pawn);
				EffSize = SizeOwner*SizeBase;
				FluidModifier = 1f;
			}
		}
	}
}


code:
using RimWorld;

namespace rjw
{
	public class CompRJWProperties_Hatcher : CompProperties_Hatcher
	{
		public CompRJWProperties_Hatcher()
		{
			this.compClass = typeof(CompRJWHatcher);
		}
	}
}


code:
using System.Text;
using Verse;
using RimWorld;
using Multiplayer.API;

namespace rjw
{
	/// <summary>
	/// Comp for things
	/// </summary>
	public class CompThingBodyPart : ThingComp
	{
		/// <summary>
		/// Comp for rjw Thing parts.
		/// </summary>

		public string Size;										//eventually replace with below, maybe
		public float SizeBase;									//base size when part created, someday alter by operation
		public float SizeOwner = 0;								//modifier of 1st owner race body size
		public string RaceOwner = "Unknows species";			//race of 1st owner race
		public string PreviousOwner = "Unknown";				//erm
		public float EffSize;									//SizeBase x SizeOwner
		public string FluidType;								//cummies/milk - insectjelly/honey etc
		public float FluidAmmount;								//amount of Milk/Ejaculation/Wetness
		public float FluidModifier;								//
		public string Eggs;										//for ovi eggs, maybe

		/// <summary>
		/// Thing/part size in labels, init comp on select
		/// </summary>

		//public override string CompInspectStringExtra()
		//{
		//	if (Size != "")
		//		return Translator.Translate("Size") + ": " + Size;
		//	else
		//		return null;

		//	return base.CompInspectStringExtra();
		//}

		/// <summary>
		/// Thing/part size in label
		/// </summary>
		public override string TransformLabel(string label)
		{
			if (SizeOwner == 0)
				InitComp();

			if (Size != "")
				return label + " (" + Size + ")" + " (" + SizeOwner + ")";
			//this.parent.GetStatValue(StatDefOf.Nutrition);

			return label;
		}

		/// <summary>
		/// Thing/part description + comp description
		/// </summary>
		public override string GetDescriptionPart()
		{
			//ModLog.Message(" CompTipStringExtra " + xxx.get_pawnname(Pawn) + " " + parent.def.defName);
			StringBuilder stringBuilder = new StringBuilder();
			if (SizeOwner == 0)
				InitComp();
			stringBuilder.AppendLine("Previous owner: " + PreviousOwner);
			stringBuilder.AppendLine("Original owner race: " + RaceOwner);
			stringBuilder.AppendLine("Original owner race size: " + SizeOwner);
			if (parent.def.defName.ToLower().Contains("breasts"))
			{
				if (FluidType != "")
					stringBuilder.AppendLine("Producing: " + FluidType);
				if (FluidAmmount != 0)
				{
					stringBuilder.AppendLine("Amount: " + FluidAmmount.ToString("F2"));
				}
				if (Size != "")
					stringBuilder.AppendLine("Size: " + Size);
			}
			else if (parent.def.defName.ToLower().Contains("penis") || parent.def.defName.ToLower().Contains("vagina"))
			{
				if (FluidAmmount != 0)
				{
					if (FluidType != "")
						stringBuilder.AppendLine("Cum: " + FluidType);
					if (parent.def.defName.ToLower().Contains("penis"))
						stringBuilder.AppendLine("Ejaculation: " + FluidAmmount.ToString("F2") + "ml");
					if (parent.def.defName.ToLower().Contains("vagina"))
						stringBuilder.AppendLine("Wetness: " + FluidAmmount.ToString("F2"));
				}
				if (Size != "")
					stringBuilder.AppendLine("Size: " + Size);
			}
			else if (parent.def.defName.ToLower().Contains("anus"))
			{
				if (FluidType != "" && FluidAmmount != 0)
				{
					stringBuilder.AppendLine("Lube: " + FluidType);
					if (parent.def.defName.ToLower().Contains("anus"))
						stringBuilder.AppendLine("Wetness: " + FluidAmmount.ToString("F2"));
				}
				if (Size != "")
					stringBuilder.AppendLine("Size: " + Size);
			}
			else if (parent.def.defName.ToLower().Contains("ovi"))
			{
				if (Eggs != "")
					stringBuilder.AppendLine("Eggs: " + Eggs);
			}

			return stringBuilder.ToString();
		}

		public override void PostExposeData()
		{
			base.PostExposeData();
			Scribe_Values.Look(ref Size, "Size");
			Scribe_Values.Look(ref SizeBase, "SizeBase");
			Scribe_Values.Look(ref SizeOwner, "SizeOwner");
			Scribe_Values.Look(ref RaceOwner, "RaceOwner");
			Scribe_Values.Look(ref PreviousOwner, "PreviousOwner");
			Scribe_Values.Look(ref FluidType, "FluidType");
			Scribe_Values.Look(ref FluidAmmount, "FluidAmmount");
			Scribe_Values.Look(ref FluidModifier, "FluidModifier");
			Scribe_Values.Look(ref Eggs, "Eggs");
		}

		/// <summary>
		/// fill comp data
		/// </summary>
		[SyncMethod]
		public void InitComp(Pawn pawn = null)
		{
			var def = DefDatabase<HediffDef>.GetNamed(parent.def.defName);
			//pick random pawn to create temp hediff
			pawn = PawnsFinder.AllMaps_FreeColonistsAndPrisonersSpawned.RandomElement();
			//pawn = PawnsFinder.All_AliveOrDead.RandomElement(); //TODO: maybe some day add immobilizing size?

			Hediff hd = HediffMaker.MakeHediff(def, pawn);

			CompHediffBodyPart CompHediff = hd.TryGetComp<CompHediffBodyPart>();
			if (CompHediff != null)
			{
				CompHediff.initComp(pawn);
				CompHediff.updatesize();

				FluidType = CompHediff.FluidType;
				FluidAmmount = CompHediff.FluidAmmount;
				FluidModifier = CompHediff.FluidModifier;
				Size = CompHediff.Size;
				SizeBase = CompHediff.SizeBase;
				SizeOwner = CompHediff.SizeOwner;
				RaceOwner = "Unknown";
				PreviousOwner = "Unknown";
				Eggs = CompHediff.Eggs;
			}
		}
	}
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace rjw
{
	public enum Orientation
	{
		None,
		Asexual,
		Pansexual,
		Heterosexual,
		MostlyHeterosexual,
		LeaningHeterosexual,
		Bisexual,
		LeaningHomosexual,
		MostlyHomosexual,
		Homosexual
	}
}


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

namespace rjw
{
	public class Quirk
	{
		public static List<Quirk> All = new List<Quirk>();

		public static readonly Quirk Breeder = new Quirk(
			"Breeder",
			"BreederQuirk");
		public static readonly Quirk Endytophile = new Quirk(
			"Endytophile",
			"EndytophileQuirk",
			(pawn, partner) => !partner.apparel.PsychologicallyNude,
			sexProps => !sexProps.Pawn.apparel.PsychologicallyNude
			);
		public static readonly Quirk Exhibitionist = new Quirk(
			"Exhibitionist",
			"ExhibitionistQuirk",
			null,
			SatisfiesExhibitionist
			);
		public static readonly Quirk Fertile = new Quirk(
			"Fertile",
			"FertileQuirk");
		public static readonly Quirk Gerontophile = new Quirk(
			"Gerontophile",
			"GerontophileQuirk",
			(pawn, partner) => SexUtility.ScaleToHumanAge(partner) > 55,
			sexProps => sexProps.HasPartner && SexUtility.ScaleToHumanAge(sexProps.Partner) > 55
			);
		public static readonly Quirk ImpregnationFetish = new Quirk(
			"Impregnation fetish",
			"ImpregnationFetishQuirk",
			(pawn, partner) =>
				PregnancyHelper.CanImpregnate(pawn, partner)
				|| PregnancyHelper.CanImpregnate(partner, pawn),
			sexProps =>
				sexProps.HasPartner
				&& (PregnancyHelper.CanImpregnate(sexProps.Pawn, sexProps.Partner, sexProps.SexType)
					|| PregnancyHelper.CanImpregnate(sexProps.Partner, sexProps.Pawn, sexProps.SexType))
			);
		public static readonly Quirk Incubator = new Quirk(
			"Incubator",
			"IncubatorQuirk");
		public static readonly Quirk Infertile = new Quirk(
			"Infertile",
			"InfertileQuirk");
		public static readonly Quirk Messy = new Quirk(
			"Messy",
			"MessyQuirk");
		public static readonly Quirk Podophile = new Quirk(
			"Podophile",
			"PodophileQuirk",
			null,
			sexProps => sexProps.HasPartner && sexProps.SexType == xxx.rjwSextype.Footjob
			);
		public static readonly Quirk PregnancyFetish = new Quirk(
			"Pregnancy fetish",
			"PregnancyFetishQuirk",
			(pawn, partner) => partner.IsVisiblyPregnant(),
			sexProps => sexProps.HasPartner && sexProps.Partner.IsVisiblyPregnant()
			);
		public static readonly Quirk Sapiosexual = new Quirk(
			"Sapiosexual",
			"SapiosexualQuirk",
			(pawn, partner) => SatisfiesSapiosexual(partner),
			null
			);
		public static readonly Quirk Somnophile = new Quirk(
			"Somnophile",
			"SomnophileQuirk",
			(pawn, partner) => !partner.Awake(),
			sexProps => sexProps.HasPartner && !sexProps.Partner.Awake()
			);
		public static readonly Quirk Teratophile = new Quirk(
			"Teratophile",
			"TeratophileQuirk",
			(pawn, partner) => SatisfiesTeratophile(partner),
			null
			);
		public static readonly Quirk Vigorous = new Quirk(
			"Vigorous",
			"VigorousQuirk");

		// There might be too many of these I dunno.
		// People have expressed "special interest" in some of them so I thought
		// it would be cool to have them in the game but since people are weird you end up with a lot of fetishes.
		public static readonly Quirk ChitinLover = MakeTagBasedQuirk("Chitin lover", "ChitinLoverQuirk", RaceTag.Chitin);
		public static readonly Quirk DemonLover = MakeTagBasedQuirk("Demon lover", "DemonLoverQuirk", RaceTag.Demon);
		public static readonly Quirk FeatherLover = MakeTagBasedQuirk("Feather lover", "FeatherLoverQuirk", RaceTag.Feathers);
		public static readonly Quirk FurLover = MakeTagBasedQuirk("Fur lover", "FurLoverQuirk", RaceTag.Fur);
		public static readonly Quirk PlantLover = MakeTagBasedQuirk("Plant lover", "PlantLoverQuirk", RaceTag.Plant);
		public static readonly Quirk RobotLover = MakeTagBasedQuirk("Robot lover", "RobotLoverQuirk", RaceTag.Robot);
		public static readonly Quirk ScaleLover = MakeTagBasedQuirk("Scale lover", "ScaleLoverQuirk", RaceTag.Scales);
		public static readonly Quirk SkinLover = MakeTagBasedQuirk("Skin lover", "SkinLoverQuirk", RaceTag.Skin);
		public static readonly Quirk SlimeLover = MakeTagBasedQuirk("Slime lover", "SlimeLoverQuirk", RaceTag.Slime);

		public string Key { get; }
		public string LocaliztionKey { get; }
		// Hack, quirk generation logic should be in the quirk not based on flags on the quirk.
		public RaceTag RaceTag { get; }
		readonly Func<Pawn, Pawn, bool> PawnSatisfiesFunc;
		readonly Func<SexProps, bool> SexSatisfiesFunc;
		readonly Action<Pawn> AfterAddFunc;

		public static Quirk MakeTagBasedQuirk(string key, string localizationKey, RaceTag tag)
		{
			return new Quirk(
				key,
				localizationKey,
				(pawn, partner) => partner.Has(tag),
				sexProps => sexProps.HasPartner && sexProps.Partner.Has(tag),
				null,
				tag);
		}

		public Quirk(
			string key,
			string localizationKey,
			Func<Pawn, Pawn, bool> pawnSatisfies = null,
			Func<SexProps, bool> sexSatisfies = null,
			Action<Pawn> afterAdd = null,
			RaceTag raceTag = null)
		{
			Key = key;
			LocaliztionKey = localizationKey;
			PawnSatisfiesFunc = pawnSatisfies;
			SexSatisfiesFunc = sexSatisfies;
			AfterAddFunc = afterAdd;
			RaceTag = raceTag;
			All.Add(this);
		}

		public bool IsSatisfiedBy(Pawn pawn, Pawn partner)
		{
			return pawn != null
				&& partner != null
				&& pawn.Has(this)
				&& PawnSatisfiesFunc != null
				&& PawnSatisfiesFunc(pawn, partner);
		}

		public static int CountSatisfiedQuirks(Pawn pawn, Pawn partner, xxx.rjwSextype sexType, bool violent)
		{
			var props = new SexProps(pawn, partner, sexType, violent);
			var satisfies = All.Where(quirk =>
				quirk.SexSatisfiesFunc != null
				&& pawn.Has(quirk)
				&& quirk.SexSatisfiesFunc(props));
			return satisfies.Count();
		}

		public void DoAfterAdd(Pawn pawn)
		{
			AfterAddFunc?.Invoke(pawn);
		}

		public static bool SatisfiesExhibitionist(SexProps sexProps)
		{
			var zoo = xxx.is_zoophile(sexProps.Pawn);
			return sexProps.Pawn.Map.mapPawns.AllPawnsSpawned.Any(x =>
				x != sexProps.Pawn
				&& x != sexProps.Partner
				&& !x.Dead
				&& (zoo || !xxx.is_animal(x))
				&& x.CanSee(sexProps.Pawn));
		}

		public static bool SatisfiesSapiosexual(Pawn partner)
		{
			if (!xxx.has_traits(partner)) return false;
			return partner.story.traits.HasTrait(TraitDefOf.TooSmart)
				|| (xxx.CTIsActive && partner.story.traits.HasTrait(xxx.RCT_Savant))
				|| (xxx.IndividualityIsActive && partner.story.traits.HasTrait(xxx.SYR_CreativeThinker))
				|| (xxx.CTIsActive && partner.story.traits.HasTrait(xxx.RCT_Inventor))
				|| partner.story.traits.HasTrait(TraitDefOf.GreatMemory)
				|| partner.story.traits.HasTrait(TraitDefOf.Transhumanist)
				|| partner.skills.GetSkill(SkillDefOf.Intellectual).levelInt >= 15;
		}

		public static bool SatisfiesTeratophile(Pawn partner)
		{
			if (partner.story == null) return false;
			var story = partner.story;
			return RelationsUtility.IsDisfigured(partner)
				|| story.bodyType == BodyTypeDefOf.Fat
				|| story.traits.HasTrait(TraitDefOf.CreepyBreathing)
				|| (story.traits.HasTrait(TraitDefOf.Beauty) && story.traits.DegreeOfTrait(TraitDefOf.Beauty) < 0)
				|| partner.GetStatValue(StatDefOf.PawnBeauty) < 0;
		}

		public static void AddThought(Pawn pawn)
		{
			var thoughtDef = DefDatabase<ThoughtDef>.GetNamed("ThatsMyFetish");
			pawn.needs.mood.thoughts.memories.TryGainMemory(thoughtDef);
		}
	}
}


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

namespace rjw
{
	public static class QuirkAdder
	{
		public static void Add(Pawn pawn, Quirk quirk)
		{
			if (!pawn.Has(quirk))
			{
				var hasFertility = pawn.RaceHasFertility();
				if (quirk == Quirk.Fertile && (!hasFertility || CompRJW.Comp(pawn).quirks.ToString().Contains(Quirk.Infertile.Key)))
				{
					return;
				}
				if (quirk == Quirk.Infertile && (!hasFertility || CompRJW.Comp(pawn).quirks.ToString().Contains(Quirk.Fertile.Key)))
				{
					return;
				}
				// No fair having a fetish for your own race.
				// But tags don't conflict so having a fetish for robot plant dragons is fine.
				if (quirk.RaceTag != null && pawn.Has(quirk.RaceTag))
				{
					return;
				}
				if (quirk == Quirk.Fertile)
				{
					var fertility = HediffDef.Named("IncreasedFertility");
					if (fertility != null)
						pawn.health.AddHediff(fertility);
				}
				if (quirk == Quirk.Infertile)
				{
					var infertility = HediffDef.Named("DecreasedFertility");
					if (infertility != null)
						pawn.health.AddHediff(infertility);
				}

				CompRJW.Comp(pawn).quirks.AppendWithComma(quirk.Key);
				CompRJW.Comp(pawn).quirksave = CompRJW.Comp(pawn).quirks.ToString();
				quirk.DoAfterAdd(pawn);
			}
		}
		public static void Remove(Pawn pawn, Quirk quirk)
		{
			if (pawn.Has(quirk))
			{
				if (quirk == Quirk.Fertile)
				{
					var fertility = HediffDef.Named("IncreasedFertility");
					if (fertility != null)
						pawn.health.RemoveHediff(pawn.health.hediffSet.GetFirstHediffOfDef(fertility));
				}
				if (quirk == Quirk.Infertile)
				{
					var infertility = HediffDef.Named("DecreasedFertility");
					if (infertility != null)
						pawn.health.RemoveHediff(pawn.health.hediffSet.GetFirstHediffOfDef(infertility));
				}

				//CompRJW.Comp(pawn).quirks.AppendWithComma(quirk.Key);
				CompRJW.Comp(pawn).quirks.Replace(quirk.Key, null);

				if (CompRJW.Comp(pawn).quirks.Length == 0)
					CompRJW.Comp(pawn).quirks.Append("None");

				CompRJW.Comp(pawn).quirksave = CompRJW.Comp(pawn).quirks.ToString();
			}
		}

		public static void Clear(Pawn pawn)
		{
			Hediff fertility = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("IncreasedFertility"));
			if (fertility != null)
				pawn.health.RemoveHediff(fertility);
			Hediff infertility = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("DecreasedFertility"));
			if (infertility != null)
				pawn.health.RemoveHediff(infertility);

			CompRJW.Comp(pawn).quirks = new StringBuilder();

			if (CompRJW.Comp(pawn).quirks.Length == 0)
				CompRJW.Comp(pawn).quirks.Append("None");

			CompRJW.Comp(pawn).quirksave = CompRJW.Comp(pawn).quirks.ToString();
		}

		public static void Generate(Pawn pawn)
		{
			if (!pawn.RaceHasSexNeed() || (pawn.kindDef.race.defName.ToLower().Contains("droid") && !AndroidsCompatibility.IsAndroid(pawn)))
			{
				return;
			}
			else if (pawn.IsAnimal())
			{
				GenerateForAnimal(pawn);
			}
			else
			{
				GenerateForHumanlike(pawn);
			}
		}

		[SyncMethod]
		static void GenerateForHumanlike(Pawn pawn)
		{
			var count = Rand.RangeInclusive(0, RJWPreferenceSettings.MaxQuirks);
			var list = Quirk.All.ToList();
			list.Shuffle();

			// Some quirks may be hard for a given pawn to indulge in.
			// For example a female homosexual will have a hard time satisfying an impregnation fetish.
			// But rimworld is a weird place and you never know what the pawn will be capable of in the future.
			// We still don't want straight up contradictory results like fertile + infertile.
			var hasFertility = pawn.RaceHasFertility();
			var actual = new List<Quirk>();
			foreach (var quirk in list)
			{
				if (count == 0)
				{
					break;
				}

				// These special cases are sort of hacked in.
				// In theory there should be a general way for the quirk itself to decide when it applies.
				if (quirk == Quirk.Fertile && (!hasFertility || actual.Contains(Quirk.Infertile)))
				{
					continue;
				}
				if (quirk == Quirk.Infertile && (!hasFertility || actual.Contains(Quirk.Fertile)))
				{
					continue;
				}
				// Have to earn these.
				if (quirk == Quirk.Breeder || quirk == Quirk.Incubator)
				{
					continue;
				}
				// No fair having a fetish for your own race.
				// But tags don't conflict so having a fetish for robot plant dragons is fine.
				if (quirk.RaceTag != null && pawn.Has(quirk.RaceTag))
				{
					continue;
				}

				count--;
				actual.Add(quirk);
			}

			foreach (var quirk in actual)
			{
				pawn.Add(quirk);
			}
		}

		[SyncMethod]
		static void GenerateForAnimal(Pawn pawn)
		{
			if (Rand.Chance(0.1f))
			{
				pawn.Add(Quirk.Messy);
			}

			if (!pawn.RaceHasFertility())
			{
				return;
			}

			if (Rand.Chance(0.1f))
			{
				pawn.Add(Quirk.Fertile);
			}
			else if (Rand.Chance(0.1f))
			{
				pawn.Add(Quirk.Infertile);
			}
		}
	}
}


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

namespace rjw
{
	public class SexProps
	{
		//quirks
		public Pawn Pawn { get; }
		public Pawn Partner { get; }
		public bool Violent { get; }

		//sex
		public Pawn Giver { get; set; }
		public Pawn Reciever { get; set; }
		public xxx.rjwSextype SexType { get; set; }
		public InteractionDef DictionaryKey { get; set; }
		public string RulePack { get; set; }

		public bool HasPartner => Partner != null;

		public SexProps(Pawn pawn, Pawn partner, xxx.rjwSextype sexType, bool violent, Pawn giver = null, Pawn reciever = null, string rulepack = null, InteractionDef dictionaryKey = null)
		{
			Pawn = pawn;
			Partner = partner;
			Violent = violent;

			Giver = giver;
			Reciever = reciever;
			SexType = sexType;
			RulePack = rulepack;
			DictionaryKey = dictionaryKey;
		}
	}
}


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

namespace rjw
{
    [DefOf]
    public static class JobDefOf
    {
        static JobDefOf()
        {
            DefOfHelper.EnsureInitializedInCtor(typeof(JobDefOf));
        }

        public static JobDef RJW_AdjustParts;
    }
}


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

namespace Rimlaser
{
    public class JobDriver_AdjustParts : JobDriver
    {
        private Thing Gun => job.GetTarget(TargetIndex.A).Thing;

        private IBeamColorThing BeamColorThing => job.GetTarget(TargetIndex.A).Thing as IBeamColorThing;

        private Thing Prism => job.GetTarget(TargetIndex.B).Thing;

        public override bool TryMakePreToilReservations(bool errorOnFailed)
        {
            if (BeamColorThing == null) return false;

            return pawn.Reserve(Gun, job, 1, -1, null, errorOnFailed) && pawn.Reserve(Prism, job, 1, -1, null, errorOnFailed);
        }

        protected override IEnumerable<Toil> MakeNewToils()
        {
            this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
            yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).FailOnDespawnedNullOrForbidden(TargetIndex.B).FailOnSomeonePhysicallyInteracting(TargetIndex.B);
            yield return Toils_Haul.StartCarryThing(TargetIndex.B, false, false, false);
            yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch).FailOnDespawnedOrNull(TargetIndex.A);
            Toil repair = Toils_General.Wait(75, TargetIndex.None);
            repair.FailOnDespawnedOrNull(TargetIndex.A);
            repair.FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch);
            repair.WithEffect(Gun.def.repairEffect, TargetIndex.A);
            repair.WithProgressBarToilDelay(TargetIndex.A, false, -0.5f);
            yield return repair;
            yield return new Toil
            {
                initAction = delegate ()
                {

                    BeamColorThing.BeamColor = pawn.CurJob.maxNumMeleeAttacks;

                    var targetInfo = new TargetInfo(Gun.Position, Map, false);
                    Effecter effecter = EffecterDefOf.Deflect_Metal.Spawn();
                    effecter.Trigger(targetInfo, targetInfo);
                    effecter.Cleanup();
                    this.Prism.Destroy(DestroyMode.Vanish);
                }
            };
            yield break;
        }
    }
}


code:
using RimWorld;
using Verse;

namespace rjw
{
	[DefOf]
	public static class RJW_RecipeDefOf
	{
		public static RecipeDef AttachPenis;
		public static RecipeDef InstallPenis;
		public static RecipeDef RemovePenis;
	}
}


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

namespace rjw
{
	public static class PawnDesignations_Breedee
	{
		public static bool UpdateCanDesignateBreeding(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = false;

			//no permission to change designation for prisoner hero/ self
			if (!pawn.CanChangeDesignationPrisoner())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = false;

			//cant have penetrative sex
			if (!xxx.can_be_fucked(pawn))
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = false;

			if (RJWSettings.bestiality_enabled && xxx.is_human(pawn))
			{
				if (!pawn.IsDesignatedHero())
				{
					if ((xxx.is_zoophile(pawn) || (RJWSettings.override_RJW_designation_checks && !MP.IsInMultiplayer)) && pawn.IsColonist)
						return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = true;
				}
				else if (pawn.IsHeroOwner())
					return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = true;

				if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn))
					return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = true;
			}

			if (RJWSettings.animal_on_animal_enabled && xxx.is_animal(pawn)
				&& pawn.Faction == Faction.OfPlayer)
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = true;

			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = false;
		}
		public static bool CanDesignateBreeding(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding;
		}
		public static void ToggleBreeding(this Pawn pawn)
		{
			pawn.UpdateCanDesignateBreeding();
			if (pawn.CanDesignateBreeding())
			{
				if (!pawn.IsDesignatedBreeding())
					DesignateBreeding(pawn);
				else
					UnDesignateBreeding(pawn);
			}
		}
		public static bool IsDesignatedBreeding(this Pawn pawn)
		{
			if (SaveStorage.DataStore.GetPawnData(pawn).Breeding)
			{
				if (!xxx.is_animal(pawn))
				{
					if (!RJWSettings.bestiality_enabled)
						UnDesignateBreeding(pawn);

					else if (!pawn.IsDesignatedHero())
						if (!(xxx.is_zoophile(pawn) || pawn.IsPrisonerOfColony || xxx.is_slave(pawn)))
							if (!(RJWSettings.WildMode || (RJWSettings.override_RJW_designation_checks && !MP.IsInMultiplayer)))
								UnDesignateBreeding(pawn);
				}
				else
				{
					if (!RJWSettings.animal_on_animal_enabled)
						UnDesignateBreeding(pawn);

					else if (!pawn.Faction?.IsPlayer ?? false)
						UnDesignateBreeding(pawn);
				}
				if (pawn.Dead)
					pawn.UnDesignateBreeding();
			}

			return SaveStorage.DataStore.GetPawnData(pawn).Breeding;
		}
		[SyncMethod]
		public static void DesignateBreeding(this Pawn pawn)
		{
			DesignatorsData.rjwBreeding.AddDistinct(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Breeding = true;
		}
		[SyncMethod]
		public static void UnDesignateBreeding(this Pawn pawn)
		{
			DesignatorsData.rjwBreeding.Remove(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Breeding = false;
		}
	}
}


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

namespace rjw
{
	public static class PawnDesignations_Breeder
	{
		public static bool UpdateCanDesignateBreedingAnimal(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreedingAnimal = false;

			//no permission to change designation for prisoner hero/ self
			if (!pawn.CanChangeDesignationPrisoner())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreedingAnimal = false;

			//Log.Message("CanDesignateAnimal for " + xxx.get_pawnname(pawn) + " " + SaveStorage.bestiality_enabled);
			//Log.Message("checking animal props " + (pawn.Faction?.IsPlayer.ToString()?? "tynanfag") + xxx.is_animal(pawn) + xxx.can_rape(pawn));
			if ((RJWSettings.bestiality_enabled || RJWSettings.animal_on_animal_enabled)
				&& xxx.is_animal(pawn)
				&& xxx.can_fuck(pawn)
				&& pawn.Faction == Faction.OfPlayer)
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreedingAnimal = true;

			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreedingAnimal = false;
		}
		public static bool CanDesignateBreedingAnimal(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreedingAnimal;
		}
		public static void ToggleBreedingAnimal(this Pawn pawn)
		{
			pawn.UpdateCanDesignateBreedingAnimal();
			if (pawn.CanDesignateBreedingAnimal())
			{
				if (!pawn.IsDesignatedBreedingAnimal())
					DesignateBreedingAnimal(pawn);
				else
					UnDesignateBreedingAnimal(pawn);
			}
		}
		public static bool IsDesignatedBreedingAnimal(this Pawn pawn)
		{
			if (SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal)
			{
				if (!pawn.Faction?.IsPlayer ?? false)
					UnDesignateBreedingAnimal(pawn);

				if (pawn.Dead)
					pawn.UnDesignateBreedingAnimal();
			}

			return SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal;
		}
		[SyncMethod]
		public static void DesignateBreedingAnimal(this Pawn pawn)
		{
			DesignatorsData.rjwBreedingAnimal.AddDistinct(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = true;
		}
		[SyncMethod]
		public static void UnDesignateBreedingAnimal(this Pawn pawn)
		{
			DesignatorsData.rjwBreedingAnimal.Remove(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = false;
		}
	}
}


code:
using Verse;
using Multiplayer.API;

namespace rjw
{
	public static class PawnDesignations_Comfort
	{
		public static bool UpdateCanDesignateComfort(this Pawn pawn)
		{
			//rape disabled
			if (!RJWSettings.rape_enabled)
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = false;

			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = false;

			//no permission to change designation for prisoner hero/ self
			if (!pawn.CanChangeDesignationPrisoner())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = false;

			//cant sex
			if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn)))
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = false;

			if (!pawn.IsDesignatedHero())
			{
				if ((xxx.is_masochist(pawn) || (RJWSettings.override_RJW_designation_checks && !MP.IsInMultiplayer)) && pawn.IsColonist)
					return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = true;
			}
			else if (pawn.IsHeroOwner())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = true;

			if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn))
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = true;

			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = false;
		}
		public static bool CanDesignateComfort(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort;
		}
		public static void ToggleComfort(this Pawn pawn)
		{
			pawn.UpdateCanDesignateComfort();
			if (pawn.CanDesignateComfort())
			{
				if (!pawn.IsDesignatedComfort())
					DesignateComfort(pawn);
				else
					UnDesignateComfort(pawn);
			}
		}
		public static bool IsDesignatedComfort(this Pawn pawn)
		{
			if (SaveStorage.DataStore.GetPawnData(pawn).Comfort)
			{
				if (!pawn.IsDesignatedHero())
				{
					if (!pawn.IsPrisonerOfColony)
						if (!(xxx.is_masochist(pawn) || xxx.is_slave(pawn)))
						{
							if (!pawn.IsColonist)
								UnDesignateComfort(pawn);
							else if (!(RJWSettings.WildMode || (RJWSettings.override_RJW_designation_checks && !MP.IsInMultiplayer)))
								UnDesignateComfort(pawn);
						}
				}

				if (pawn.Dead)
					pawn.UnDesignateComfort();
			}

			return SaveStorage.DataStore.GetPawnData(pawn).Comfort;
		}
		[SyncMethod]
		public static void DesignateComfort(this Pawn pawn)
		{
			DesignatorsData.rjwComfort.AddDistinct(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Comfort = true;
		}
		[SyncMethod]
		public static void UnDesignateComfort(this Pawn pawn)
		{
			DesignatorsData.rjwComfort.Remove(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Comfort = false;
		}
	}
}


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

namespace rjw
{
	public static class PawnDesignations_Hero
	{
		public static bool UpdateCanDesignateHero(this Pawn pawn)
		{
			if ((RJWSettings.RPG_hero_control)
				&& xxx.is_human(pawn)
				&& pawn.IsColonist)
			{
				if (!pawn.IsDesignatedHero())
				{
					foreach (Pawn item in DesignatorsData.rjwHero)
					{
						if (item.IsHeroOwner())
						{
							if (RJWSettings.RPG_hero_control_Ironman && !SaveStorage.DataStore.GetPawnData(item).Ironman)
								SetHeroIronman(item);
							if (item.Dead && !SaveStorage.DataStore.GetPawnData(item).Ironman)
							{
								UnDesignateHero(item);
								//Log.Warning("CanDesignateHero:: "  + MP.PlayerName + " hero is dead remove hero tag from " + item.Name);
							}
							else
							{
								//Log.Warning("CanDesignateHero:: "  + MP.PlayerName + " already has hero - " + item.Name);
								return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateHero = false;
							}

						}
						else
							continue;
					}
					return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateHero = true;
				}
			}
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateHero = false;
		}
		public static bool CanDesignateHero(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateHero;
		}
		public static void ToggleHero(this Pawn pawn)
		{
			pawn.UpdateCanDesignateHero();
			if (pawn.CanDesignateHero() && Find.Selector.NumSelected == 1)
			{
				if (!pawn.IsDesignatedHero())
					DesignateHero(pawn);
			}
		}
		public static bool IsDesignatedHero(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).Hero;
		}
		public static void DesignateHero(this Pawn pawn)
		{
			MyMethod(pawn, MP.PlayerName);
		}
		[SyncMethod]
		public static void UnDesignateHero(this Pawn pawn)
		{
			DesignatorsData.rjwHero.Remove(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Hero = false;
		}
		public static bool IsHeroOwner(this Pawn pawn)
		{
			if (!MP.enabled)
				return SaveStorage.DataStore.GetPawnData(pawn).HeroOwner == "Player" || SaveStorage.DataStore.GetPawnData(pawn).HeroOwner == null || SaveStorage.DataStore.GetPawnData(pawn).HeroOwner == "";
			else
				return SaveStorage.DataStore.GetPawnData(pawn).HeroOwner == MP.PlayerName;
		}
		[SyncMethod]
		static void MyMethod(Pawn pawn, string theName)
		{
			if (!MP.enabled)
				theName = "Player";
			SaveStorage.DataStore.GetPawnData(pawn).Hero = true;
			SaveStorage.DataStore.GetPawnData(pawn).HeroOwner = theName;
			SaveStorage.DataStore.GetPawnData(pawn).Ironman = RJWSettings.RPG_hero_control_Ironman;
			DesignatorsData.rjwHero.AddDistinct(pawn);
			string text = pawn.Name + " is now hero of " + theName;
			Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent);
			//Log.Message(MP.PlayerName + "  set " + pawn.Name + " to hero:" + SaveStorage.DataStore.GetPawnData(pawn).Hero);

			pawn.UpdatePermissions();
		}
		[SyncMethod]
		public static void SetHeroIronman(this Pawn pawn)
		{
			SaveStorage.DataStore.GetPawnData(pawn).Ironman = true;
		}
	}
}


code:
using Verse;
using Multiplayer.API;

namespace rjw
{
	public static class PawnDesignations_Milking
	{
		public static bool UpdateCanDesignateMilking(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateMilking = false;
		}
		public static bool CanDesignateMilking(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateMilking = false;
		}
		public static void ToggleMilking(this Pawn pawn)
		{
			if (pawn.CanDesignateMilking())
			{
				if (!pawn.IsDesignatedMilking())
					DesignateMilking(pawn);
				else
					UnDesignateMilking(pawn);
			}
		}
		public static bool IsDesignatedMilking(this Pawn pawn)
		{
			if (SaveStorage.DataStore.GetPawnData(pawn).Milking)
			{
				if (!pawn.IsDesignatedHero())
					if (!(pawn.IsColonist || pawn.IsPrisonerOfColony || xxx.is_slave(pawn)))
						UnDesignateMilking(pawn);

				if (pawn.Dead)
					pawn.UnDesignateMilking();
			}

			return SaveStorage.DataStore.GetPawnData(pawn).Milking;
		}
		[SyncMethod]
		public static void DesignateMilking(this Pawn pawn)
		{
			DesignatorsData.rjwMilking.AddDistinct(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Milking = true;
		}
		[SyncMethod]
		public static void UnDesignateMilking(this Pawn pawn)
		{
			DesignatorsData.rjwMilking.Remove(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Milking = false;
		}
	}
}


code:
using Verse;
using Multiplayer.API;

namespace rjw
{
	public static class PawnDesignations_Service
	{
		public static bool UpdateCanDesignateService(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = false;

			//no permission to change designation for prisoner hero/ self
			if (!pawn.CanChangeDesignationPrisoner())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = false;

			//cant sex
			if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn)))
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = false;

			if (!pawn.IsDesignatedHero())
			{
				if (pawn.IsColonist)
					return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = true;
			}
			else if (pawn.IsHeroOwner())
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = true;

			if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn))
				return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = true;

			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService = false;
		}
		public static bool CanDesignateService(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanDesignateService;
		}
		public static void ToggleService(this Pawn pawn)
		{
			pawn.UpdateCanDesignateService();
			if (pawn.CanDesignateService())
			{
				if (!pawn.IsDesignatedService())
					DesignateService(pawn);
				else
					UnDesignateService(pawn);
			}
		}
		public static bool IsDesignatedService(this Pawn pawn)
		{
			if (SaveStorage.DataStore.GetPawnData(pawn).Service)
			{
				if (!pawn.IsDesignatedHero())
					if (!(pawn.IsColonist || pawn.IsPrisonerOfColony || xxx.is_slave(pawn)))
						UnDesignateService(pawn);

				if (pawn.Dead)
					pawn.UnDesignateService();
			}

			return SaveStorage.DataStore.GetPawnData(pawn).Service;
		}
		[SyncMethod]
		public static void DesignateService(this Pawn pawn)
		{
			DesignatorsData.rjwService.AddDistinct(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Service = true;
		}
		[SyncMethod]
		public static void UnDesignateService(this Pawn pawn)
		{
			DesignatorsData.rjwService.Remove(pawn);
			SaveStorage.DataStore.GetPawnData(pawn).Service = false;
		}
	}
}


code:
using Verse;
using System.Diagnostics;
using RimWorld;

namespace rjw
{
	public static class PawnDesignations_Utility
	{
		public static bool UpdatePermissions(this Pawn pawn)
		{
			pawn.UpdateCanChangeDesignationPrisoner();
			pawn.UpdateCanChangeDesignationColonist();
			pawn.UpdateCanDesignateService();
			pawn.UpdateCanDesignateComfort();
			pawn.UpdateCanDesignateBreedingAnimal();
			pawn.UpdateCanDesignateBreeding();
			pawn.UpdateCanDesignateHero();
			pawn.UpdateRMB_Menu();
			return true;
		}
		public static bool UpdateCanChangeDesignationColonist(this Pawn pawn)
		{
			//check if pawn is a hero of other player
			//if yes - limit widget access in mp for this pawn

			if ((pawn.IsDesignatedHero() && !pawn.IsHeroOwner()))
			{
				//Log.Warning("CanChangeDesignationColonist:: Pawn:" + xxx.get_pawnname(pawn));
				//Log.Warning("CanChangeDesignationColonist:: IsDesignatedHero:" + pawn.IsDesignatedHero());
				//Log.Warning("CanChangeDesignationColonist:: IsHeroOwner:" + pawn.IsHeroOwner());
				return SaveStorage.DataStore.GetPawnData(pawn).CanChangeDesignationColonist = false;
			}

			return SaveStorage.DataStore.GetPawnData(pawn).CanChangeDesignationColonist = true;
		}
		public static bool CanChangeDesignationColonist(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanChangeDesignationColonist;
		}
		public static bool UpdateCanChangeDesignationPrisoner(this Pawn pawn)
		{
			//check if player hero is a slave/prisoner
			//if yes - limit widget access in mp for all widgets

			//Stopwatch sw = new Stopwatch();
			//sw.Start();

			//Log.Warning("rjwHero:: Count " + DesignatorsData.rjwHero.Count);
			//Log.Warning("rjwComfort:: Count " + DesignatorsData.rjwComfort.Count);
			//Log.Warning("rjwService:: Count " + DesignatorsData.rjwService.Count);
			//Log.Warning("rjwMilking:: Count " + DesignatorsData.rjwMilking.Count);
			//Log.Warning("rjwBreeding:: Count " + DesignatorsData.rjwBreeding.Count);
			//Log.Warning("rjwBreedingAnimal:: Count " + DesignatorsData.rjwBreedingAnimal.Count);

			foreach (Pawn item in DesignatorsData.rjwHero)
			{
				//Log.Warning("CanChangeDesignationPrisoner:: Pawn:" + xxx.get_pawnname(item));
				//Log.Warning("CanChangeDesignationPrisoner:: IsHeroOwner:" + item.IsHeroOwner());
				if (item.IsHeroOwner())
				{
					if (item.IsPrisonerOfColony || item.IsPrisoner || xxx.is_slave(item))
					{
						//Log.Warning("CanChangeDesignationPrisoner:: Pawn:" + xxx.get_pawnname(item));
						//Log.Warning("CanChangeDesignationPrisoner:: Hero of " + MP.PlayerName);
						//Log.Warning("CanChangeDesignationPrisoner:: is prisoner(colony):" + item.IsPrisonerOfColony);
						//Log.Warning("CanChangeDesignationPrisoner:: is prisoner:" + item.IsPrisoner);
						//Log.Warning("CanChangeDesignationPrisoner:: is slave:" + xxx.is_slave(item));
						return SaveStorage.DataStore.GetPawnData(pawn).CanChangeDesignationPrisoner = false;
					}
				}
			}
			//sw.Stop();
			//Log.Warning("Elapsed={0}" + sw.Elapsed);

			return SaveStorage.DataStore.GetPawnData(pawn).CanChangeDesignationPrisoner = true;
		}
		public static bool CanChangeDesignationPrisoner(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).CanChangeDesignationPrisoner;
		}
		public static bool CheckRMB_Menu(this Pawn pawn)
		{
			return true;
			var show = false;
			//not heromode or override_control - quit

			//not heromode or override_control - quit
			if (!(RJWSettings.RPG_hero_control || RJWSettings.override_control))
			{
				pawn.UpdateRMB_Menu(show);
			}

			var HeroOK0 = false;    //is hero
			var HeroOK1 = false;    //owned hero?
			var HeroOK2 = false;    //not owned hero? maybe prison check etc in future
			if (RJWSettings.RPG_hero_control)
			{
				HeroOK0 = pawn.IsDesignatedHero();
				HeroOK1 = HeroOK0 && pawn.IsHeroOwner();
				HeroOK2 = HeroOK0 && !pawn.IsHeroOwner();
			}
			else if (!RJWSettings.override_control)
			{ }

			//not hero, not override_control - quit
			if (!(HeroOK0 && RJWSettings.override_control))
				return false;
			//not owned hero - quit
			if (!HeroOK1)
				return false;

			SaveStorage.DataStore.GetPawnData(pawn).ShowRMB_Menu = show;

			return SaveStorage.DataStore.GetPawnData(pawn).ShowRMB_Menu;
		}
		public static bool UpdateRMB_Menu(this Pawn pawn , bool show = false)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).ShowRMB_Menu = show;
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Handles creation of RJWdesignations button group for gui
	/// </summary>
	public class RJWdesignations : Command
	{
		//is actually a group of four buttons, but I've wanted them be small and so vanilla gizmo system is mostly bypassed for them

		private const float ContentPadding = 5f;
		private const float IconSize = 32f;
		private const float IconGap = 1f;

		private readonly Pawn parent;
		private Rect gizmoRect;
		/// <summary>
		/// This should keep track of last pressed pseudobutton. It is set in the pseudobutton callback.
		/// Then, the callback to encompassed Gizmo is performed by game, and this field is used to determine what exact button was pressed
		/// The callback is called by the tynancode right after the loop which detects click on button,
		/// so it will be called then and only then when it should be (no unrelated events).
		/// event handling  shit is needed to apply settings to all selected pawns.
		/// </summary>
		private static SubIcon lastClicked;

		static readonly List<SubIcon> subIcons = new List<SubIcon> {
			new Comfort(),
			//new Service(),
			//new BreederHuman(),
			new BreedingHuman(),
			new BreedingAnimal(),
			new Breeder(),
			//new Milking(),
			new Hero()
		};

		public RJWdesignations(Pawn pawn)
		{
			parent = pawn;
			defaultLabel = "RJWdesignations";
			defaultDesc = "RJWdesignations";
		}

		public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth)
		{
			Rect rect = new Rect(topLeft.x, topLeft.y, 75f, 75f);
			gizmoRect = rect.ContractedBy(ContentPadding);
			Widgets.DrawWindowBackground(rect);

			//Log.Message("RJWgizmo");
			foreach (SubIcon icon in subIcons)
			{
				if (DrawSubIcon(icon))
				{
					lastClicked = icon;
					icon.state = icon.applied(parent);
					return new GizmoResult(GizmoState.Interacted, Event.current);
				}
			}
			return new GizmoResult(GizmoState.Clear);
		}

		//this and class mess below was supposed to be quick shortcut to not write four repeated chunks of code in GizmoOnGUI
		private bool DrawSubIcon(SubIcon icon)
		{
			if (!icon.applicable(parent)) { return false; }
			//Log.Message("sub gizmo");
			Rect iconRect = new Rect(gizmoRect.x + icon.offset.x, gizmoRect.y + icon.offset.y, IconSize, IconSize);
			TooltipHandler.TipRegion(iconRect, icon.desc(parent).Translate());
			bool applied = icon.applied(parent);
			Texture2D texture = applied ? icon.cancel : icon.texture(parent);
			GUI.DrawTexture(iconRect, texture);
			//GUI.color = Color.white;

			return Widgets.ButtonInvisible(iconRect, false);
		}

		public override void ProcessInput(Event ev)
		{
			SubIcon icon = lastClicked;
			if (icon.state)
				icon.unapply(parent);
			else
				icon.apply(parent);
		}

		[StaticConstructorOnStartup]//this  is needed for textures
		public abstract class SubIcon
		{
			public abstract Texture2D texture(Pawn pawn);
			public abstract Vector2 offset { get; }
			public abstract string desc(Pawn pawn);
			public abstract bool applicable(Pawn pawn);
			public abstract bool applied(Pawn pawn);
			public abstract void apply(Pawn pawn);
			public abstract void unapply(Pawn pawn);

			static readonly Texture2D cancellText = ContentFinder<Texture2D>.Get("UI/Commands/cancel");
			public virtual Texture2D cancel => cancellText;

			public bool state;
		}
		[StaticConstructorOnStartup]
		public class Comfort : SubIcon
		{
			//comfort raping
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/ComfortPrisoner_off");
			static readonly Texture2D iconRefuse = ContentFinder<Texture2D>.Get("UI/Commands/ComfortPrisoner_Refuse");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/ComfortPrisoner_on");
			public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateComfort() || pawn.IsDesignatedComfort()) && xxx.is_human(pawn) ? iconAccept : iconRefuse;
			public override Texture2D cancel { get; } = iconCancel;

			static readonly Vector2 posComf = new Vector2(IconGap + IconSize, 0);
			public override Vector2 offset => posComf;

			public override string desc(Pawn pawn) => pawn.CanDesignateComfort() ? "ForComfortDesc" :
														!pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" :
														!pawn.CanChangeDesignationColonist() ? "ForHeroRefuse1Desc" : "ForComfortRefuseDesc";

			public override bool applicable(Pawn pawn) => RJWSettings.rape_enabled && xxx.is_human(pawn);
			public override bool applied(Pawn pawn) => pawn.IsDesignatedComfort();
			public override void apply(Pawn pawn) => pawn.ToggleComfort();
			public override void unapply(Pawn pawn) => pawn.ToggleComfort();
		}
		[StaticConstructorOnStartup]
		public class Service : SubIcon
		{
			//whoring
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Service_off");
			static readonly Texture2D iconRefuse = ContentFinder<Texture2D>.Get("UI/Commands/Service_Refuse");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Service_on");
			public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateService() || pawn.IsDesignatedService()) && xxx.is_human(pawn) ? iconAccept : iconRefuse;
			public override Texture2D cancel { get; } = iconCancel;

			public override Vector2 offset { get; } = new Vector2(0, 0);

			public override string desc(Pawn pawn) => pawn.CanDesignateService() ? "ForServiceDesc" :
														!pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" :
														!pawn.CanChangeDesignationColonist() ? "ForHeroRefuse1Desc" : "ForServiceRefuseDesc";

			public override bool applicable(Pawn pawn) => xxx.is_human(pawn);
			public override bool applied(Pawn pawn) => pawn.IsDesignatedService() && xxx.is_human(pawn);
			public override void apply(Pawn pawn) => pawn.ToggleService();
			public override void unapply(Pawn pawn) => pawn.ToggleService();
		}
		[StaticConstructorOnStartup]
		public class BreedingHuman : SubIcon
		{
			//Breed humanlike
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Pawn_off");
			static readonly Texture2D iconRefuse = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Pawn_Refuse");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Pawn_on");
			public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateBreeding() || pawn.IsDesignatedBreeding()) && xxx.is_human(pawn) ? iconAccept : iconRefuse;
			public override Texture2D cancel { get; } = iconCancel;

			public override Vector2 offset { get; } = new Vector2(0, IconSize + IconGap);

			public override string desc(Pawn pawn) => pawn.CanDesignateBreeding() && xxx.is_human(pawn) ? "ForBreedingDesc" :
														!pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" :
														!pawn.CanChangeDesignationColonist() ? "ForHeroRefuse1Desc" : "ForBreedingRefuseDesc";

			public override bool applicable(Pawn pawn) =>  RJWSettings.bestiality_enabled && xxx.is_human(pawn);
			public override bool applied(Pawn pawn) => pawn.IsDesignatedBreeding() && xxx.is_human(pawn);
			public override void apply(Pawn pawn) => pawn.ToggleBreeding();
			public override void unapply(Pawn pawn) => pawn.ToggleBreeding();
		}

		[StaticConstructorOnStartup]
		public class BreedingAnimal : SubIcon
		{
			//Breed animal
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Animal_off");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Animal_on");
			public override Texture2D texture(Pawn pawn) => iconAccept;
			public override Texture2D cancel { get; } = iconCancel;

			public override Vector2 offset { get; } = new Vector2(0, IconSize + IconGap);

			public override string desc(Pawn pawn) => !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : "ForBreedingDesc";

			public override bool applicable(Pawn pawn) => (pawn.CanDesignateBreeding() || pawn.IsDesignatedBreeding()) && xxx.is_animal(pawn);
			public override bool applied(Pawn pawn) => pawn.IsDesignatedBreeding() && xxx.is_animal(pawn);
			public override void apply(Pawn pawn) => pawn.ToggleBreeding();
			public override void unapply(Pawn pawn) => pawn.ToggleBreeding();
		}
		[StaticConstructorOnStartup]
		public class Breeder : SubIcon
		{
			//Breeder(fucker) animal
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Breeder_Animal_off");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Breeder_Animal_on");
			public override Texture2D texture(Pawn pawn) => iconAccept;
			public override Texture2D cancel { get; } = iconCancel;

			public override Vector2 offset { get; } = new Vector2(0, 0);

			public override string desc(Pawn pawn) => !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : "ForBreedingAnimalDesc";

			public override bool applicable(Pawn pawn) => pawn.CanDesignateBreedingAnimal() || pawn.IsDesignatedBreedingAnimal();
			public override bool applied(Pawn pawn) => pawn.IsDesignatedBreedingAnimal();
			public override void apply(Pawn pawn) => pawn.ToggleBreedingAnimal();
			public override void unapply(Pawn pawn) => pawn.ToggleBreedingAnimal();
		}
		[StaticConstructorOnStartup]
		public class Milking : SubIcon
		{
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Milking_off");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Milking_on");
			public override Texture2D texture(Pawn pawn) => iconAccept;
			public override Texture2D cancel { get; } = iconCancel;

			public override Vector2 offset { get; } = new Vector2(IconGap + IconSize, IconSize + IconGap);

			public override string desc(Pawn pawn) => !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : "ForMilkingDesc";

			public override bool applicable(Pawn pawn) => pawn.CanDesignateMilking() || pawn.IsDesignatedMilking();
			public override bool applied(Pawn pawn) => pawn.IsDesignatedMilking();
			public override void apply(Pawn pawn) => pawn.ToggleMilking();
			public override void unapply(Pawn pawn) => pawn.ToggleMilking();
		}
		[StaticConstructorOnStartup]
		public class Hero : SubIcon
		{
			static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Hero_off");
			static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Hero_on");
			public override Texture2D texture(Pawn pawn) => iconAccept;
			public override Texture2D cancel { get; } = iconCancel;

			public override Vector2 offset { get; } = new Vector2(IconGap + IconSize, IconSize + IconGap);

			//public override string desc(Pawn pawn) => pawn.CanDesignateHero() || (pawn.IsDesignatedHero() && pawn.IsHeroOwner()) ? "ForHeroDesc" : "Hero of " + SaveStorage.DataStore.GetPawnData(pawn).HeroOwner;
			public override string desc(Pawn pawn) => pawn.CanDesignateHero() ? "ForHeroDesc" :
														pawn.IsDesignatedHero() ? "Hero of " + SaveStorage.DataStore.GetPawnData(pawn).HeroOwner : "ForHeroDesc";

			public override bool applicable(Pawn pawn) => pawn.CanDesignateHero() || pawn.IsDesignatedHero();
			public override bool applied(Pawn pawn) => pawn.IsDesignatedHero();
			public override void apply(Pawn pawn) => pawn.ToggleHero();
			public override void unapply(Pawn pawn) => pawn.ToggleHero();
		}
	}
}


code:
using System.Collections.Generic;
using Harmony;
using RimWorld;
using UnityEngine;
using Verse;

namespace rjw
{
	public static class Building_Bed_Patch
	{
		[HarmonyPatch(typeof(Building_Bed))]
		[HarmonyPatch("ForPrisoners", MethodType.Setter)]
		public static class ForPrisoners
		{
			[HarmonyPostfix]
			public static void Postfix(Building_Bed __instance)
			{
				if (!__instance.ForPrisoners) return;

				if (__instance is Building_WhoreBed)
				{
					Building_WhoreBed.Swap(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Building_Bed), "GetGizmos")]
		public static class GetGizmos
		{
			[HarmonyPostfix]
			public static void Postfix(Building_Bed __instance, ref IEnumerable<Gizmo> __result)
			{
				__result = Process(__instance, __result);
			}

			private static IEnumerable<Gizmo> Process(Building_Bed __instance, IEnumerable<Gizmo> __result)
			{
				foreach (var gizmo in __result)
				{
					yield return gizmo;
				}
				if (__instance!=null && !__instance.ForPrisoners && !__instance.Medical && __instance.def.building.bed_humanlike)
				{
					//--Log.Message("[RJW]Building_Bed_Patch::Process - before new Command_Toggle is called");
					yield return
						new Command_Toggle
						{
							defaultLabel = "CommandBedSetAsWhoreLabel".Translate(),
							defaultDesc = "CommandBedSetAsWhoreDesc".Translate(),
							icon = ContentFinder<Texture2D>.Get("UI/Commands/AsWhore"),
							isActive = () => __instance is Building_WhoreBed,
							toggleAction = () => Building_WhoreBed.Swap(__instance),
							hotKey = KeyBindingDefOf.Misc4
						};
				}
			}
		}
	}
}


code:
using System.Reflection;
using Harmony;
using RimWorld;
using Verse;

namespace rjw
{
	/// <summary>
	/// Conditional patching class that only does patching if CnP is active
	/// </summary>
	public class CnPcompatibility
	{
		//CnP (or BnC) try to address the joy need of a child, prisoners don't have that.
		//Considering how you can arrest children without rjw, it is more of a bug of that mod than ours.
		[HarmonyPatch(typeof(Pawn_NeedsTracker), "BindDirectNeedFields")]
		static class jfpk
		{
			[HarmonyPostfix]
			static void postfix(ref Pawn_NeedsTracker __instance)
			{
				Pawn_NeedsTracker tr = __instance;
				FieldInfo fieldInfo = AccessTools.Field(typeof(Pawn_NeedsTracker), "pawn");
				Pawn pawn = fieldInfo.GetValue(__instance) as Pawn;
				if (xxx.is_human(pawn) && pawn.ageTracker.CurLifeStageIndex < AgeStage.Teenager)
				{
					if (tr.TryGetNeed(NeedDefOf.Joy) == null)
					{
						MethodInfo method = AccessTools.Method(typeof(Pawn_NeedsTracker), "AddNeed");
						method.Invoke(tr, new object[] { NeedDefOf.Joy });
					}
				}
			}
		}

		//For whatever reason, harmony shits itself, when trying to patch non void private fields, below are variants the code that would work nicely, if it didn't
		//[HarmonyPatch]
		//[StaticConstructorOnStartup]
		//internal static class joy_for_prison_kids
		//{
		//    [HarmonyTargetMethod]
		//    static MethodBase CalculateMethod(HarmonyInstance instance)
		//    {
		//        var r = AccessTools.Method(typeof(Pawn_NeedsTracker), "ShouldHaveNeed");

		//        //Log.Message("Found method "+ r.ReturnType + ' ' + r.FullDescription());
		//        //Log.Message("Parameters " + r.GetType() );
		//        //Log.Message("return " + r.ReturnParameter);
		//        return AccessTools.Method(typeof(Pawn_NeedsTracker), "ShouldHaveNeed");
		//    }
		//    [HarmonyPrepare]
		//    static bool should_patch(HarmonyInstance instance)
		//    {
		//        Log.Clear();
		//        Log.Message("Will patch "+ xxx.RimWorldChildrenIsActive);
		//        return xxx.RimWorldChildrenIsActive;
		//    }

		//doesn't work, gets:  System.Reflection.TargetParameterCountException: parameters do not match signature
		//static void Postfix(HarmonyInstance instance)
		//{
		//    Log.Message("FOO");
		//}
		//[HarmonyPrefix]
		//static bool foo(NeedDef nd)
		//{
		//    Log.Message("Prerun ");
		//    return true;
		//}
		//[HarmonyPostfix]
		//static void postfix(ref bool __result, ref Pawn_NeedsTracker __instance, NeedDef nd)
		//{
		//    if (nd != NeedDefOf.Joy) { return; }
		//    FieldInfo fieldInfo = AccessTools.Field(typeof(Pawn_NeedsTracker), "pawn");
		//    Pawn pawn = fieldInfo.GetValue(__instance) as Pawn;
		//    if (pawn.ageTracker.CurLifeStageIndex < AgeStage.Teenager)
		//    {
		//        __result = true;
		//    }
		//}
		//}
		public static void Patch(HarmonyInstance harmony)
		{
			if (!xxx.RimWorldChildrenIsActive) return;
			Doit(harmony);
		}
		private static void Doit(HarmonyInstance harmony)
		{
			var original = typeof(RimWorldChildren.ChildrenUtility).GetMethod("CanBreastfeed");
			var postfix = typeof(CnPcompatibility).GetMethod("CanBreastfeed");
			harmony.Patch(original, null, new HarmonyMethod(postfix));

			original = typeof(Building_Bed).GetMethod("get_AssigningCandidates");
			postfix = typeof(CnPcompatibility).GetMethod("BedCandidates");
			harmony.Patch(original, null, new HarmonyMethod(postfix));

			//doesn't work cannot reflect private class
			//original = typeof(RimWorldChildren.Hediff_UnhappyBaby).GetMethod("IsBabyUnhappy", BindingFlags.Static | BindingFlags.NonPublic);
			//Log.Message("original is nul " + (original == null));
			//var prefix = typeof(CnPcompatibility).GetMethod("IsBabyUnhappy");
			//harmony.Patch(original, new HarmonyMethod(prefix), null);
		}
		private static void CanBreastfeed(ref  bool __result, ref Pawn __instance)//Postfix
		{
			__result = __instance.health.hediffSet.HasHediff(HediffDef.Named("Lactating"));//I'm a simple man
		}
		private static void BedCandidates(ref IEnumerable<Pawn> __result, ref Building_Bed bed)
		{
			if (!RimWorldChildren.BedPatchMethods.IsCrib(bed)) return;
			__result = bed.Map.mapPawns.FreeColonists.Where(x => x.ageTracker.CurLifeStageIndex <= 2 && x.Faction == Faction.OfPlayer);//Basically do all the work second time but with a tweak
		}
		private static bool IsBabyUnhappy(ref bool __result, ref RimWorldChildren.Hediff_UnhappyBaby __instance)
		{
			var pawn = __instance.pawn;

			if ((pawn.needs?.joy.CurLevelPercentage??1) < 0.2f)
				__result = true;
			else
				__result =  false;
			return false;
		}
	}
}