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

repo_name: Euclidean/rjw

license: mit


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


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

namespace rjw
{
	[StaticConstructorOnStartup]
	internal static class First
	{
		/*private static void show_bpr(String body_part_record_def_name)
		{
			var bpr = BodyDefOf.Human.AllParts.Find((BodyPartRecord can) => String.Equals(can.def.defName, body_part_record_def_name));
			--Log.Message(body_part_record_def_name + " BPR internals:");
			--Log.Message("  def: " + bpr.def.ToString());
			--Log.Message("  parts: " + bpr.parts.ToString());
			--Log.Message("  parts.count: " + bpr.parts.Count.ToString());
			--Log.Message("  height: " + bpr.height.ToString());
			--Log.Message("  depth: " + bpr.depth.ToString());
			--Log.Message("  coverage: " + bpr.coverage.ToString());
			--Log.Message("  groups: " + bpr.groups.ToString());
			--Log.Message("  groups.count: " + bpr.groups.Count.ToString());
			--Log.Message("  parent: " + bpr.parent.ToString());
			--Log.Message ("  fleshCoverage: " + bpr.fleshCoverage.ToString ());
			--Log.Message ("  absoluteCoverage: " + bpr.absoluteCoverage.ToString ());
			--Log.Message ("  absoluteFleshCoverage: " + bpr.absoluteFleshCoverage.ToString ());
		}*/

		//Children mod use same defname. but not has worker class. so overriding here.
		public static void inject_Reproduction()
		{
			PawnCapacityDef reproduction = DefDatabase<PawnCapacityDef>.GetNamed("RJW_Fertility");
			reproduction.workerClass = typeof(PawnCapacityWorker_Fertility);
		}

		public static void inject_whoringtab()
		{
			//InjectTab(typeof(MainTab.MainTabWindow_Brothel), def => def.race?.Humanlike == true);
		}

		private static void InjectTab(Type tabType, Func<ThingDef, bool> qualifier)
		{
			var defs = DefDatabase<ThingDef>.AllDefs.Where(qualifier).ToList();
			defs.RemoveDuplicates();

			var tabBase = InspectTabManager.GetSharedInstance(tabType);

			foreach (var def in defs)
			{
				if (def.inspectorTabs == null || def.inspectorTabsResolved == null) continue;

				if (!def.inspectorTabs.Contains(tabType))
				{
					def.inspectorTabs.Add(tabType);
					def.inspectorTabsResolved.Add(tabBase);
					//Log.Message(def.defName+": "+def.inspectorTabsResolved.Select(d=>d.GetType().Name).Aggregate((a,b)=>a+", "+b));
				}
			}
		}

		private static void inject_recipes()
		{
			//--ModLog.Message(" First::inject_recipes");
			// Inject the recipes to create the artificial privates into the crafting spot or machining bench.
			// BUT, also dynamically detect if EPOE is loaded and, if it is, inject the recipes into EPOE's
			// crafting benches instead.

			try
			{
				//Vanilla benches
				var cra_spo = DefDatabase<ThingDef>.GetNamed("CraftingSpot");
				var mac_ben = DefDatabase<ThingDef>.GetNamed("TableMachining");
				var fab_ben = DefDatabase<ThingDef>.GetNamed("FabricationBench");
				var tai_ben = DefDatabase<ThingDef>.GetNamed("ElectricTailoringBench");

				// Inject the bondage gear recipes into their appropriate benches
				//if (xxx.config.bondage_gear_enabled)
				//{
					//fab_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeHololock"));
					//tai_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeArmbinder"));
					//tai_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeChastityBelt"));
					//tai_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeChastityBeltO"));
					//tai_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeChastityCage"));
					//tai_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeBallGag"));
					//tai_ben.AllRecipes.Add(DefDatabase<RecipeDef>.GetNamed("MakeRingGag"));
				//}
			}
			catch
			{
				ModLog.Warning("Unable to inject recipes.");
				ModLog.Warning("Yay! Your medieval mod broke recipes. And, likely, parts too, expect errors.");
			}
		}

		/*private static void show_bs(Backstory bs)
		{
			--Log.Message("Backstory \"" + bs.Title + "\" internals:");
			--Log.Message("  identifier: " + bs.identifier);
			--Log.Message("  slot: " + bs.slot.ToString());
			--Log.Message("  Title: " + bs.Title);
			--Log.Message("  TitleShort: " + bs.TitleShort);
			--Log.Message("  baseDesc: " + bs.baseDesc);
			--Log.Message("  skillGains: " + ((bs.skillGains == null) ? "null" : bs.skillGains.ToString()));
			--Log.Message("  skillGainsResolved: " + ((bs.skillGainsResolved == null) ? "null" : bs.skillGainsResolved.ToString()));
			--Log.Message("  workDisables: " + bs.workDisables.ToString());
			--Log.Message("  requiredWorkTags: " + bs.requiredWorkTags.ToString());
			--Log.Message("  spawnCategories: " + bs.spawnCategories.ToString());
			--Log.Message("  bodyTypeGlobal: " + bs.bodyTypeGlobal.ToString());
			--Log.Message("  bodyTypeFemale: " + bs.bodyTypeFemale.ToString());
			--Log.Message("  bodyTypeMale: " + bs.bodyTypeMale.ToString());
			--Log.Message("  forcedTraits: " + ((bs.forcedTraits == null) ? "null" : bs.forcedTraits.ToString()));
			--Log.Message("  disallowedTraits: " + ((bs.disallowedTraits == null) ? "null" : bs.disallowedTraits.ToString()));
			--Log.Message("  shuffleable: " + bs.shuffleable.ToString());
		}*/

		//Quick check to see if an another mod is loaded.
		private static bool IsLoaded(string mod)
		{
			return LoadedModManager.RunningModsListForReading.Any(x => x.Name == mod);
		}

		private static void CheckingCompatibleMods()
		{
			{//Humanoid Alien Races Framework 2.0
				xxx.xenophobia = DefDatabase<TraitDef>.GetNamedSilentFail("Xenophobia");
				if (xxx.xenophobia is null)
				{
					xxx.AlienFrameworkIsActive = false;
				}
				else
				{
					xxx.AlienFrameworkIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Humanoid Alien Races 2.0 is detected. Xenophile and Xenophobe traits active.");
				}
			}

			{//relations-orientation mods
				{//RomanceDiversified
					xxx.straight = DefDatabase<TraitDef>.GetNamedSilentFail("Straight");
					xxx.faithful = DefDatabase<TraitDef>.GetNamedSilentFail("Faithful");
					xxx.philanderer = DefDatabase<TraitDef>.GetNamedSilentFail("Philanderer");
					xxx.polyamorous = DefDatabase<TraitDef>.GetNamedSilentFail("Polyamorous");
					if (xxx.straight is null || xxx.faithful is null || xxx.philanderer is null || xxx.polyamorous is null)
					{
						xxx.RomanceDiversifiedIsActive = false;
					}
					else
					{
						xxx.RomanceDiversifiedIsActive = true;
						if (RJWSettings.DevMode) ModLog.Message("RomanceDiversified is detected.");
					}
				}

				{//[SYR] Individuality
					xxx.SYR_CreativeThinker = DefDatabase<TraitDef>.GetNamedSilentFail("SYR_CreativeThinker");
					xxx.SYR_Haggler = DefDatabase<TraitDef>.GetNamedSilentFail("SYR_Haggler");
					if (xxx.SYR_CreativeThinker is null || xxx.SYR_Haggler is null)
					{
						xxx.IndividualityIsActive = false;
						if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.SYRIndividuality)
							RJWPreferenceSettings.sexuality_distribution = RJWPreferenceSettings.Rjw_sexuality.Vanilla;
					}
					else
					{
						xxx.IndividualityIsActive = true;
						if (RJWSettings.DevMode) ModLog.Message("Individuality is detected.");
					}
				}

				{//Psychology
					xxx.prude = DefDatabase<TraitDef>.GetNamedSilentFail("Prude");
					xxx.lecher = DefDatabase<TraitDef>.GetNamedSilentFail("Lecher");
					xxx.polygamous = DefDatabase<TraitDef>.GetNamedSilentFail("Polygamous");
					if (xxx.prude is null || xxx.lecher is null || xxx.polygamous is null)
					{
						xxx.PsychologyIsActive = false;
						if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Psychology)
							RJWPreferenceSettings.sexuality_distribution = RJWPreferenceSettings.Rjw_sexuality.Vanilla;
					}
					else
					{
						xxx.PsychologyIsActive = true;
						if (RJWSettings.DevMode) ModLog.Message("Psychology is detected. (Note: only partially supported)");
					}
				}

				if (xxx.PsychologyIsActive == false && xxx.IndividualityIsActive == false)
				{
					if (RJWPreferenceSettings.sexuality_distribution != RJWPreferenceSettings.Rjw_sexuality.Vanilla)
					{
						RJWPreferenceSettings.sexuality_distribution = RJWPreferenceSettings.Rjw_sexuality.Vanilla;
					}
				}
			}

			{//SimpleSlavery
				xxx.Enslaved = DefDatabase<HediffDef>.GetNamedSilentFail("Enslaved");
				if (xxx.Enslaved is null)
				{
					xxx.SimpleSlaveryIsActive = false;
				}
				else
				{
					xxx.SimpleSlaveryIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("SimpleSlavery is detected.");
				}
			}

			{//[KV] Consolidated Traits
				xxx.RCT_NeatFreak = DefDatabase<TraitDef>.GetNamedSilentFail("RCT_NeatFreak");
				xxx.RCT_Savant = DefDatabase<TraitDef>.GetNamedSilentFail("RCT_Savant");
				xxx.RCT_Inventor = DefDatabase<TraitDef>.GetNamedSilentFail("RCT_Inventor");
				xxx.RCT_AnimalLover = DefDatabase<TraitDef>.GetNamedSilentFail("RCT_AnimalLover");
				if (xxx.RCT_NeatFreak is null || xxx.RCT_Savant is null || xxx.RCT_Inventor is null || xxx.RCT_AnimalLover is null)
				{
					xxx.CTIsActive = false;
				}
				else
				{
					xxx.CTIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Consolidated Traits found, adding trait compatibility.");
				}
			}

			{//Rimworld of Magic
				xxx.Succubus = DefDatabase<TraitDef>.GetNamedSilentFail("Succubus");
				xxx.Warlock = DefDatabase<TraitDef>.GetNamedSilentFail("Warlock");
				xxx.TM_Mana = DefDatabase<NeedDef>.GetNamedSilentFail("TM_Mana");
				xxx.TM_ShapeshiftHD = DefDatabase<HediffDef>.GetNamedSilentFail("TM_ShapeshiftHD");
				if (xxx.Succubus is null || xxx.Warlock is null || xxx.TM_Mana is null || xxx.TM_ShapeshiftHD is null)
				{
					xxx.RoMIsActive = false;
				}
				else
				{
					xxx.RoMIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Rimworld of Magic is detected.");
				}
			}

			{//Nightmare Incarnation
				xxx.NI_Need_Mana = DefDatabase<NeedDef>.GetNamedSilentFail("NI_Need_Mana");
				if (xxx.NI_Need_Mana is null)
				{
					xxx.NightmareIncarnationIsActive = false;
				}
				else
				{
					xxx.NightmareIncarnationIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Nightmare Incarnation is detected.");
				}
			}

			{//DubsBadHygiene
				xxx.DBHThirst = DefDatabase<NeedDef>.GetNamedSilentFail("DBHThirst");
				if (xxx.DBHThirst is null)
				{
					xxx.DubsBadHygieneIsActive = false;
				}
				else
				{
					xxx.DubsBadHygieneIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Dubs Bad Hygiene is detected.");
				}
			}

			{//Immortals
				xxx.IH_Immortal = DefDatabase<HediffDef>.GetNamedSilentFail("IH_Immortal");
				if (xxx.IH_Immortal is null)
				{
					xxx.ImmortalsIsActive = false;
				}
				else
				{
					xxx.ImmortalsIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Immortals is detected.");
				}
			}

			{//Children and Pregnancy
				xxx.BabyState = DefDatabase<HediffDef>.GetNamedSilentFail("BabyState");
				xxx.PostPregnancy = DefDatabase<HediffDef>.GetNamedSilentFail("PostPregnancy");
				xxx.Lactating = DefDatabase<HediffDef>.GetNamedSilentFail("Lactating");
				xxx.NoManipulationFlag = DefDatabase<HediffDef>.GetNamedSilentFail("NoManipulationFlag");
				xxx.IGaveBirthFirstTime = DefDatabase<ThoughtDef>.GetNamedSilentFail("IGaveBirthFirstTime");
				xxx.IGaveBirth = DefDatabase<ThoughtDef>.GetNamedSilentFail("IGaveBirth");
				xxx.PartnerGaveBirth = DefDatabase<ThoughtDef>.GetNamedSilentFail("PartnerGaveBirth");
				if (xxx.BabyState is null || xxx.PostPregnancy is null || xxx.Lactating is null || xxx.NoManipulationFlag is null || xxx.IGaveBirthFirstTime is null || xxx.IGaveBirth is null ||  xxx.PartnerGaveBirth is null)
				{
					xxx.RimWorldChildrenIsActive = false;
				}
				else
				{
					xxx.RimWorldChildrenIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Children&Pregnancy is detected.");
				}
			}

			{//Babies and Children
				xxx.BnC_RJW_PostPregnancy = DefDatabase<HediffDef>.GetNamedSilentFail("BnC_RJW_PostPregnancy");
			}

			{//Combat Extended
				xxx.MuscleSpasms = DefDatabase<HediffDef>.GetNamedSilentFail("MuscleSpasms");
				if (xxx.MuscleSpasms is null)
				{
					xxx.CombatExtendedIsActive = false;
				}
				else
				{
					xxx.CombatExtendedIsActive = true;
					if (RJWSettings.DevMode) ModLog.Message("Combat Extended is detected. Current compatibility unknown, use at your own risk. ");
				}
			}
		}

		static First()
		{
			//--ModLog.Message(" First::First() called");

			// check for required mods
			//CheckModRequirements();
			CheckIncompatibleMods();
			CheckingCompatibleMods();

			inject_Reproduction();
			//inject_recipes(); // No Longer needed.  Benches defined in recipe defs

			nymph_backstories.init();
			//bondage_gear_tradeability.init();

			var har = new Harmony("rjw");
			har.PatchAll(Assembly.GetExecutingAssembly());
			PATCH_Pawn_ApparelTracker_TryDrop.apply(har);
			//CnPcompatibility.Patch(har);							//CnP IS NO OUT YET
		}

		internal static void CheckModRequirements()
		{
			//--Log.Message("First::CheckModRequirements() called");
			List<string> required_mods = new List<string> {
				"HugsLib",
			};
			foreach (string required_mod in required_mods)
			{
				bool found = false;
				foreach (ModMetaData installed_mod in ModLister.AllInstalledMods)
				{
					if (installed_mod.Active && installed_mod.Name.Contains(required_mod))
					{
						found = true;
					}

					if (!found)
					{
						ErrorMissingRequirement(required_mod);
					}
				}
			}
		}

		internal static void CheckIncompatibleMods()
		{
			//--Log.Message("First::CheckIncompatibleMods() called");
			List<string> incompatible_mods = new List<string> {
				"Bogus Test Mod That Doesn't Exist",
				"Lost Forest"
			};
			foreach (string incompatible_mod in incompatible_mods)
			{
				foreach (ModMetaData installed_mod in ModLister.AllInstalledMods)
				{
					if (installed_mod.Active && installed_mod.Name.Contains(incompatible_mod))
					{
						ErrorIncompatibleMod(installed_mod);
					}
				}
			}
		}

		internal static void ErrorMissingRequirement(string missing)
		{
			ModLog.Error("Initialization error:  Unable to find required mod '" + missing + "' in mod list");
		}

		internal static void ErrorIncompatibleMod(ModMetaData othermod)
		{
			ModLog.Error("Initialization Error:  Incompatible mod '" + othermod.Name + "' detected in mod list");
		}
	}
}


code:
using HarmonyLib;
using Verse;
using System;
using RimWorld;

/// <summary>
/// patches PawnGenerator to add genitals to pawns and spawn nymph when needed
/// </summary>
namespace rjw
{
	[HarmonyPatch(typeof(PawnGenerator), "GenerateNewPawnInternal")]
	static class Patch_PawnGenerator
	{
		[HarmonyPrefix]
		static void Before_GenerateNewPawnInternal(ref PawnGenerationRequest request)
		{
			if (Nymph_Generator.IsNymph(request))
			{
				request = new PawnGenerationRequest(
					kind: request.KindDef = Nymph_Generator.GetFixedNymphPawnKindDef(),
					canGeneratePawnRelations: request.CanGeneratePawnRelations = false,
					validatorPreGear: Nymph_Generator.IsNymphBodyType,
					validatorPostGear: Nymph_Generator.IsNymphBodyType,
					fixedGender: request.FixedGender = Nymph_Generator.RandomNymphGender()
					);
			}
		}

		[HarmonyPostfix]
		static void After_GenerateNewPawnInternal(ref PawnGenerationRequest request, ref Pawn __result)
		{
			if (Nymph_Generator.IsNymph(request))
			{
				Nymph_Generator.set_story(__result);
				Nymph_Generator.set_skills(__result);
			}

			//ModLog.Message("After_GenerateNewPawnInternal:: " + xxx.get_pawnname(__result));
			if (CompRJW.Comp(__result) != null && CompRJW.Comp(__result).orientation == Orientation.None)
			{
				//ModLog.Message("After_GenerateNewPawnInternal::Sexualize " + xxx.get_pawnname(__result));
				CompRJW.Comp(__result).Sexualize(__result);
			}
		}
	}
}


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

/// <summary>
/// patches PawnUtility to fix humanlike childrens post birth
/// </summary>
namespace rjw
{
	[HarmonyPatch(typeof(PawnUtility), "TrySpawnHatchedOrBornPawn")]
	static class Patch_PawnUtility
	{
		//[HarmonyPrefix]
		//static void prefix_TrySpawnHatchedOrBornPawn(ref Pawn pawn, Thing motherOrEgg)
		//{
		//	//ModLog.Message("prefix_TrySpawnHatchedOrBornPawn::");
		//	//ModLog.Message(" " + __result);
		//	//ModLog.Message(" " + xxx.get_pawnname(pawn));
		//	//ModLog.Message(" " + xxx.get_pawnname(motherOrEgg as Pawn));
		//	//ModLog.Message(" " + RJWPregnancySettings.humanlike_pregnancy_enabled);
		//	//ModLog.Message(" " + xxx.is_human(pawn));
		//	//ModLog.Message(" " + !xxx.is_mechanoid(pawn));
		//	//string last_name = NameTriple.FromString(pawn.Name.ToStringFull).Last;
		//	//ModLog.Message(" prefix_TrySpawnHatchedOrBornPawn Baby surname will be " + last_name);
		//}

		//resets pawn/doesn't work for some races with C# constructors
		[HarmonyPostfix]
		static void postfix_TrySpawnHatchedOrBornPawn(ref bool __result, ref Pawn pawn, Thing motherOrEgg)
		{
			//ModLog.Message("postfix_TrySpawnHatchedOrBornPawn::");
			//ModLog.Message(" " + __result);
			//ModLog.Message(" " + xxx.get_pawnname(pawn));
			//ModLog.Message(" " + xxx.get_pawnname(motherOrEgg as Pawn));
			//ModLog.Message(" " + RJWPregnancySettings.humanlike_pregnancy_enabled);
			//ModLog.Message(" " + xxx.is_human(pawn));
			//ModLog.Message(" " + !xxx.is_mechanoid(pawn));
			//string last_name = NameTriple.FromString(pawn.Name.ToStringFull).Last;
			//ModLog.Message(" postfix_TrySpawnHatchedOrBornPawn 1 Baby surname will be " + last_name);
			//var skin_whiteness = pawn.story.melanin;
			//var last_name1 = pawn.story.birthLastName;
			if (__result
				&& RJWPregnancySettings.humanlike_pregnancy_enabled
				&& xxx.is_human(pawn)
				&& !xxx.is_mechanoid(pawn))
			{
				changestory(pawn);
				removeimplants(pawn);
				removeskills(pawn);
				grow(pawn);
			}
			//ModLog.Message(" postfix_TrySpawnHatchedOrBornPawn 2 Baby surname will be " + NameTriple.FromString(pawn.Name.ToStringFull).Last);
			//pawn.story.melanin = skin_whiteness;
			//pawn.story.birthLastName = last_name1;
		}

		static void removeimplants(Pawn pawn)
		{
			if (!pawn.health.hediffSet.hediffs.NullOrEmpty())
			{
				var hdlist = pawn.health.hediffSet.hediffs.ToList();
				foreach (Hediff hd in hdlist)
				{
					if (hd == null) continue;

					// remove DeathAcidifier
					//if (hd.def.defName == "DeathAcidifier")
					//{
					//	pawn.health.RemoveHediff(hd);
					//	continue;
					//}

					// remove implants
					if (hd is Hediff_Implant)
					{
						var part = hd.Part;
						pawn.health.RestorePart(part);
					}

					// remove immortality
					if (xxx.ImmortalsIsActive && hd.def == xxx.IH_Immortal)
					{
						pawn.health.RemoveHediff(hd);
					}
				}
			}
		}

		//resets/doest work for some races
		static void changestory(Pawn pawn)
		{
			if (!xxx.RimWorldChildrenIsActive)
			{
				pawn.story.childhood = null;
				pawn.story.adulthood = null;

				// set child to tribal
				try
				{
					Backstory bs = null;
					BackstoryDatabase.TryGetWithIdentifier("rjw_childT", out bs);

					pawn.story.childhood = bs;
				}
				catch (Exception e)
				{
					ModLog.Warning(e.ToString());
				}
			}
		}

		static void grow(Pawn pawn)
		{
			if (!xxx.RimWorldChildrenIsActive)
			{
				// add growing
				if (!pawn.Dead)
				{
					pawn.health.AddHediff(xxx.RJW_BabyState, null, null);
					Hediff_SimpleBaby pawnstate = (Hediff_SimpleBaby)pawn.health.hediffSet.GetFirstHediffOfDef(xxx.RJW_BabyState);
					if (pawnstate != null)
					{
						pawnstate.GrowUpTo(0, true);
					}
				}
			}
		}

		static void removeskills(Pawn pawn)
		{
			// remove skills
			foreach (var skill in pawn.skills?.skills)
				skill.Level = 0;
		}
	}
}


code:
using HarmonyLib;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.Sound;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

namespace rjw
{
	[HarmonyPatch(typeof(CharacterCardUtility), "DrawCharacterCard")]
	public static class SexcardPatch
	{
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo HighlightOpportunity = AccessTools.Method(typeof(UIHighlighter), "HighlightOpportunity");
			MethodInfo SexualityCardToggle = AccessTools.Method(typeof(SexcardPatch), nameof(SexualityCardToggle));
			bool traits = false;
			bool found = false;
			foreach (CodeInstruction i in instructions)
			{
				if (found)
				{
					yield return new CodeInstruction(OpCodes.Ldarg_0) { labels = i.labels.ListFullCopy() };//rect
					yield return new CodeInstruction(OpCodes.Ldarg_1);//pawn
					yield return new CodeInstruction(OpCodes.Ldarg_3);//creationRect
					yield return new CodeInstruction(OpCodes.Call, SexualityCardToggle);
					found = false;
					i.labels.Clear();
				}
				if (i.opcode == OpCodes.Call && i.operand == HighlightOpportunity)
				{
					found = true;
				}
				if (i.opcode == OpCodes.Ldstr && i.operand.Equals("Traits"))
				{
					traits = true;
				}
				if (traits && i.opcode == OpCodes.Ldc_R4 && i.operand.Equals(2f))//replaces rect y calculation
				{
					yield return new CodeInstruction(OpCodes.Ldc_R4, 0f);
					traits = false;
					continue;
				}
				yield return i;
			}
		}

		public static void SexualityCardToggle(Rect rect, Pawn pawn, Rect creationRect)
		{
			if (pawn == null) return;
			if (CompRJW.Comp(pawn) == null) return;

			Rect rectNew = new Rect(CharacterCardUtility.BasePawnCardSize.x - 50f, 2f, 24f, 24f);
			if (Current.ProgramState != ProgramState.Playing)
			{
				if (xxx.IndividualityIsActive) // Move icon lower to avoid overlap.
					rectNew = new Rect(creationRect.width - 24f, 56f, 24f, 24f);
				else
					rectNew = new Rect(creationRect.width - 24f, 30f, 24f, 24f);
			}
			Color old = GUI.color;

			GUI.color = rectNew.Contains(Event.current.mousePosition) ? new Color(0.25f, 0.59f, 0.75f) : new Color(1f, 1f, 1f);
			// TODO: Replace the placeholder icons with... something
			if (CompRJW.Comp(pawn).quirks.ToString() != "None")
				GUI.DrawTexture(rectNew, ContentFinder<Texture2D>.Get("UI/Commands/Service_on"));
			else
				GUI.DrawTexture(rectNew, ContentFinder<Texture2D>.Get("UI/Commands/Service_off"));

			TooltipHandler.TipRegion(rectNew, "SexcardTooltip".Translate());
			if (Widgets.ButtonInvisible(rectNew))
			{
				SoundDefOf.InfoCard_Open.PlayOneShotOnCamera();
				Find.WindowStack.Add(new Dialog_Sexcard(pawn));
			}
			GUI.color = old;
		}
	}
}


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

namespace rjw
{
	//TODO: check slime stuff working in mp
	//TODO: separate menus in sub scripts
	//TODO: add demon switch parts
	//TODO: figure out and make interface?
	//TODO: add vibration toggle for bionics(+50% partner satisfaction?)
	public class Dialog_Sexcard : Window
	{
		private readonly Pawn pawn;

		public Dialog_Sexcard(Pawn editFor)
		{
			pawn = editFor;
		}

		public static breasts Breasts;
		public enum breasts
		{
			selectone,
			none,
			featureless_chest,
			flat_breasts,
			small_breasts,
			average_breasts,
			large_breasts,
			huge_breasts,
			slime_breasts,
		};

		public static anuses Anuses;
		public enum anuses
		{
			selectone,
			none,
			micro_anus,
			tight_anus,
			average_anus,
			loose_anus,
			gaping_anus,
			slime_anus,
		};

		public static vaginas Vaginas;
		public enum vaginas
		{
			selectone,
			none,
			micro_vagina,
			tight_vagina,
			average_vagina,
			loose_vagina,
			gaping_vagina,
			slime_vagina,
			feline_vagina,
			canine_vagina,
			equine_vagina,
			dragon_vagina,
		};

		public static penises Penises;
		public enum penises
		{
			selectone,
			none,
			micro_penis,
			small_penis,
			average_penis,
			big_penis,
			huge_penis,
			slime_penis,
			feline_penis,
			canine_penis,
			equine_penis,
			dragon_penis,
			raccoon_penis,
			hemipenis,
			crocodilian_penis,
		};

		public void SexualityCard(Rect rect, Pawn pawn)
		{
			CompRJW comp = pawn.TryGetComp<CompRJW>();
			if (pawn == null || comp == null) return;

			Text.Font = GameFont.Medium;
			Rect rect1 = new Rect(8f, 4f, rect.width - 8f, rect.height - 20f);
			Widgets.Label(rect1, "RJW");//rjw

			Text.Font = GameFont.Tiny;
			float num = rect1.y + 40f;
			Rect row1 = new Rect(10f, num, rect.width - 8f, 24f);//sexuality
			Rect row2 = new Rect(10f, num + 24, rect.width - 8f, 24f);//quirks
			Rect row3 = new Rect(10f, num + 48, rect.width - 8f, 24f);//whore price

			//Rect sexuality_button = new Rect(10f, rect1.height - 0f, rect.width - 8f, 24f);//change sex pref
			Rect button1 = new Rect(10f, rect1.height - 10f, rect.width - 8f, 24f);//re sexualize
			Rect button2 = new Rect(10f, rect1.height - 34f, rect.width - 8f, 24f);//archtech toggle
			Rect button3 = new Rect(10f, rect1.height - 58f, rect.width - 8f, 24f);//breast
			Rect button4 = new Rect(10f, rect1.height - 82f, rect.width - 8f, 24f);//anus
			Rect button5 = new Rect(10f, rect1.height - 106f, rect.width - 8f, 24f);//vagina
			Rect button6 = new Rect(10f, rect1.height - 130f, rect.width - 8f, 24f);//penis 1
			Rect button7 = new Rect(10f, rect1.height - 154f, rect.width - 8f, 24f);//penis 2

			DrawSexuality(pawn, row1);
			DrawQuirks(pawn, row2);
			DrawWhoring(pawn, row3);

			// TODO: Add translations. or not
			if (Prefs.DevMode || Current.ProgramState != ProgramState.Playing)
			{
				if (Widgets.ButtonText(button1, Current.ProgramState != ProgramState.Playing ? "Reroll sexuality" : "[DEV] Reroll sexuality"))
				{
					Re_sexualize(pawn);
				}
			}
			if (pawn.health.hediffSet.HasHediff(Genital_Helper.archotech_penis) || pawn.health.hediffSet.HasHediff(Genital_Helper.archotech_vagina))
			{
				if (pawn.health.hediffSet.HasHediff(HediffDef.Named("ImpregnationBlocker")))
				{
					if (Widgets.ButtonText(button2, "[Archotech genitalia] Enable reproduction"))
					{
						Change_Archotechmode(pawn);
					}
				}
				else if (!pawn.health.hediffSet.HasHediff(HediffDef.Named("FertilityEnhancer")))
				{
					if (Widgets.ButtonText(button2, "[Archotech genitalia] Enchance fertility"))
					{
						Change_Archotechmode(pawn);
					}
				}
				else if (Widgets.ButtonText(button2, "[Archotech genitalia] Disable reproduction"))
				{
					Change_Archotechmode(pawn);
				}
			}
			// TODO: add mp synchronizers
			// TODO: clean that mess
			// TODO: add demon toggles
			if (MP.IsInMultiplayer)
				return;

			//List<String> Parts = null;
			//if (xxx.is_slime(pawn))
			//	Parts = new List<string>(DefDatabase<StringListDef>.GetNamed("SlimeMorphFilters").strings);
			//if (xxx.is_demon(pawn))
			//	Parts = new List<string>(DefDatabase<StringListDef>.GetNamed("DemonMorphFilters").strings);
			// TODO: replace that mess with floating menu
			//if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.clickCount == 2 && Mouse.IsOver(rect))
			//{
				//Event.current.Use();//?
				//DrawMedOperationsTab(0, pawn, Parts,0);
			//}

			//if (Parts.Any() && (pawn.IsColonistPlayerControlled || pawn.IsPrisonerOfColony))
			//if (xxx.is_slime(pawn) && (pawn.IsColonistPlayerControlled || pawn.IsPrisonerOfColony))
			//{
			//	BodyPartRecord bpr_genitalia = Genital_Helper.get_genitals(pawn);
			//	BodyPartRecord bpr_breasts = Genital_Helper.get_breasts(pawn);
			//	BodyPartRecord bpr_anus = Genital_Helper.get_anus(pawn);
			//	BodyPartRecord bpr = null;
			//	HediffDef hed = null;

			//	if (Widgets.ButtonText(button3, "Morph breasts"))
			//	{
			//		Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
			//	{
			//		new FloatMenuOption("none", (() => Breasts = breasts.none), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.featureless_chest.label.CapitalizeFirst(), (() => Breasts = breasts.featureless_chest), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.flat_breasts.label.CapitalizeFirst(), (() => Breasts = breasts.flat_breasts), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.small_breasts.label.CapitalizeFirst(), (() => Breasts = breasts.small_breasts), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.average_breasts.label.CapitalizeFirst(), (() => Breasts = breasts.average_breasts), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.large_breasts.label.CapitalizeFirst(), (() => Breasts = breasts.large_breasts), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.huge_breasts.label.CapitalizeFirst(), (() => Breasts = breasts.huge_breasts), MenuOptionPriority.Default),
			//		new FloatMenuOption(Genital_Helper.slime_breasts.label.CapitalizeFirst(), (() => Breasts = breasts.slime_breasts), MenuOptionPriority.Default),
			//	}));
			//	}
			//	switch (Breasts)
			//	{
			//		case breasts.none:
			//			bpr = bpr_breasts;
			//			break;
			//		case breasts.featureless_chest:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.featureless_chest;
			//			break;
			//		case breasts.flat_breasts:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.flat_breasts;
			//			break;
			//		case breasts.small_breasts:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.small_breasts;
			//			break;
			//		case breasts.average_breasts:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.average_breasts;
			//			break;
			//		case breasts.large_breasts:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.large_breasts;
			//			break;
			//		case breasts.huge_breasts:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.huge_breasts;
			//			break;
			//		case breasts.slime_breasts:
			//			bpr = bpr_breasts;
			//			hed = Genital_Helper.slime_breasts;
			//			break;
			//		default:
			//			break;
			//	}

			//	if (Widgets.ButtonText(button4, "Morph anus"))
			//	{
			//		Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
			//		{
			//			new FloatMenuOption("none", (() => Anuses = anuses.none), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.micro_anus.label.CapitalizeFirst(), (() => Anuses = anuses.micro_anus), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.tight_anus.label.CapitalizeFirst(), (() => Anuses = anuses.tight_anus), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.average_anus.label.CapitalizeFirst(), (() => Anuses = anuses.average_anus), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.loose_anus.label.CapitalizeFirst(), (() => Anuses = anuses.loose_anus), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.gaping_anus.label.CapitalizeFirst(), (() => Anuses = anuses.gaping_anus), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.slime_anus.label.CapitalizeFirst(), (() => Anuses = anuses.slime_anus), MenuOptionPriority.Default),
			//		}));
			//	}
			//	switch (Anuses)
			//	{
			//		case anuses.none:
			//			bpr = bpr_anus;
			//			break;
			//		case anuses.micro_anus:
			//			bpr = bpr_anus;
			//			hed = Genital_Helper.micro_anus;
			//			break;
			//		case anuses.tight_anus:
			//			bpr = bpr_anus;
			//			hed = Genital_Helper.tight_anus;
			//			break;
			//		case anuses.average_anus:
			//			bpr = bpr_anus;
			//			hed = Genital_Helper.average_anus;
			//			break;
			//		case anuses.loose_anus:
			//			bpr = bpr_anus;
			//			hed = Genital_Helper.loose_anus;
			//			break;
			//		case anuses.gaping_anus:
			//			bpr = bpr_anus;
			//			hed = Genital_Helper.gaping_anus;
			//			break;
			//		case anuses.slime_anus:
			//			bpr = bpr_anus;
			//			hed = Genital_Helper.slime_anus;
			//			break;
			//		default:
			//			break;
			//	}

			//	if (Widgets.ButtonText(button5, "Morph vagina"))
			//	{
			//		Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
			//		{
			//			new FloatMenuOption("none", (() => Vaginas = vaginas.none), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.micro_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.micro_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.tight_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.tight_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.average_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.average_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.loose_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.loose_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.gaping_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.gaping_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.slime_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.slime_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.feline_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.feline_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.canine_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.canine_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.equine_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.equine_vagina), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.dragon_vagina.label.CapitalizeFirst(), (() => Vaginas = vaginas.dragon_vagina), MenuOptionPriority.Default),
			//		}));
			//	}
			//	switch (Vaginas)
			//	{
			//		case vaginas.none:
			//			bpr = bpr_genitalia;
			//			break;
			//		case vaginas.micro_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.micro_vagina;
			//			break;
			//		case vaginas.tight_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.tight_vagina;
			//			break;
			//		case vaginas.average_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.average_vagina;
			//			break;
			//		case vaginas.loose_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.loose_vagina;
			//			break;
			//		case vaginas.gaping_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.gaping_vagina;
			//			break;
			//		case vaginas.slime_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.slime_vagina;
			//			break;
			//		case vaginas.feline_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.feline_vagina;
			//			break;
			//		case vaginas.canine_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.canine_vagina;
			//			break;
			//		case vaginas.equine_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.equine_vagina;
			//			break;
			//		case vaginas.dragon_vagina:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.dragon_vagina;
			//			break;
			//		default:
			//			break;
			//	}

			//	if (Widgets.ButtonText(button6, "Morph penis"))
			//	{
			//		Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
			//		{
			//			new FloatMenuOption("none", (() => Penises = penises.none), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.micro_penis.label.CapitalizeFirst(), (() => Penises = penises.micro_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.small_penis.label.CapitalizeFirst(), (() => Penises = penises.small_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.average_penis.label.CapitalizeFirst(), (() => Penises = penises.average_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.big_penis.label.CapitalizeFirst(), (() => Penises = penises.big_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.huge_penis.label.CapitalizeFirst(), (() => Penises = penises.huge_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.slime_penis.label.CapitalizeFirst(), (() => Penises = penises.slime_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.feline_penis.label.CapitalizeFirst(), (() => Penises = penises.feline_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.canine_penis.label.CapitalizeFirst(), (() => Penises = penises.canine_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.equine_penis.label.CapitalizeFirst(), (() => Penises = penises.equine_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.dragon_penis.label.CapitalizeFirst(), (() => Penises = penises.dragon_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.raccoon_penis.label.CapitalizeFirst(), (() => Penises = penises.raccoon_penis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.hemipenis.label.CapitalizeFirst(), (() => Penises = penises.hemipenis), MenuOptionPriority.Default),
			//			new FloatMenuOption(Genital_Helper.crocodilian_penis.label.CapitalizeFirst(), (() => Penises = penises.crocodilian_penis), MenuOptionPriority.Default),
			//		}));
			//	}
			//	switch (Penises)
			//	{
			//		case penises.none:
			//			bpr = bpr_genitalia;
			//			break;
			//		case penises.micro_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.micro_penis;
			//			break;
			//		case penises.small_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.small_penis;
			//			break;
			//		case penises.average_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.average_penis;
			//			break;
			//		case penises.big_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.big_penis;
			//			break;
			//		case penises.huge_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.huge_penis;
			//			break;
			//		case penises.slime_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.slime_penis;
			//			break;
			//		case penises.feline_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.feline_penis;
			//			break;
			//		case penises.canine_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.canine_penis;
			//			break;
			//		case penises.equine_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.equine_penis;
			//			break;
			//		case penises.dragon_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.dragon_penis;
			//			break;
			//		case penises.raccoon_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.raccoon_penis;
			//			break;
			//		case penises.hemipenis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.hemipenis;
			//			break;
			//		case penises.crocodilian_penis:
			//			bpr = bpr_genitalia;
			//			hed = Genital_Helper.crocodilian_penis;
			//			break;
			//		default:
			//			break;
			//	}

			//	if (bpr != null)
			//	{
			//		//Log.Message("start ");
			//		if (bpr != bpr_genitalia)
			//		{
			//			if (pawn.needs.TryGetNeed<Need_Food>().CurLevel > 0.5f)
			//			{
			//				pawn.needs.food.CurLevel -= 0.5f;
			//				pawn.health.RestorePart(bpr);
			//				if (hed != null)
			//					pawn.health.AddHediff(hed, bpr);
			//			}
			//			Anuses = anuses.selectone;
			//			Breasts = breasts.selectone;
			//		}
			//		else if (bpr == bpr_genitalia && Vaginas != vaginas.selectone)
			//		{
			//			if (pawn.needs.TryGetNeed<Need_Food>().CurLevel > 0.5f)
			//			{
			//				pawn.needs.food.CurLevel -= 0.5f;
			//				List<Hediff> list = new List<Hediff>();
			//				foreach (Hediff heddif in pawn.health.hediffSet.hediffs.Where(x =>
			//						x.Part == bpr &&
			//						x.def.defName.ToLower().Contains("vagina")))
			//					list.Add(heddif);

			//				foreach (Hediff heddif in list)
			//					pawn.health.hediffSet.hediffs.Remove(heddif);

			//				if (hed != null)
			//					pawn.health.AddHediff(hed, bpr);
			//			}
			//			Vaginas = vaginas.selectone;
			//		}
			//		else if (bpr == bpr_genitalia && Penises != penises.selectone)
			//		{
			//			if (pawn.needs.TryGetNeed<Need_Food>().CurLevel > 0.5f)
			//			{
			//				pawn.needs.food.CurLevel -= 0.5f;
			//				List<Hediff> list = new List<Hediff>();
			//				foreach (Hediff heddif in pawn.health.hediffSet.hediffs.Where(x =>
			//						x.Part == bpr &&
			//						x.def.defName.ToLower().Contains("penis") ||
			//						x.def.defName.ToLower().Contains("tentacle")))
			//					list.Add(heddif);

			//				foreach (Hediff heddif in list)
			//					pawn.health.hediffSet.hediffs.Remove(heddif);

			//				if (hed != null)
			//					pawn.health.AddHediff(hed, bpr);
			//			}
			//			Penises = penises.selectone;
			//		}
			//		//Log.Message("end ");
			//	}
			//}
		}

		static void DrawSexuality(Pawn pawn, Rect row)
		{
			string sexuality;

			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Vanilla)
				CompRJW.VanillaTraitCheck(pawn);
			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.SYRIndividuality)
				CompRJW.CopyIndividualitySexuality(pawn);
			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.Psychology)
				CompRJW.CopyPsychologySexuality(pawn);

			switch (CompRJW.Comp(pawn).orientation)
			{
				case Orientation.Asexual:
					sexuality = "Asexual";
					break;
				case Orientation.Bisexual:
					sexuality = "Bisexual";
					break;
				case Orientation.Heterosexual:
					sexuality = "Hetero";
					break;
				case Orientation.Homosexual:
					sexuality = "Gay";
					break;
				case Orientation.LeaningHeterosexual:
					sexuality = "Bisexual, leaning hetero";
					break;
				case Orientation.LeaningHomosexual:
					sexuality = "Bisexual, leaning gay";
					break;
				case Orientation.MostlyHeterosexual:
					sexuality = "Mostly hetero";
					break;
				case Orientation.MostlyHomosexual:
					sexuality = "Mostly gay";
					break;
				case Orientation.Pansexual:
					sexuality = "Pansexual";
					break;
				default:
					sexuality = "None";
					break;
			}

			//allow to change pawn sexuality for:
			//own hero, game start
			if (RJWPreferenceSettings.sexuality_distribution == RJWPreferenceSettings.Rjw_sexuality.RimJobWorld &&
				(((Current.ProgramState == ProgramState.Playing &&
				pawn.IsDesignatedHero() && pawn.IsHeroOwner()) ||
				Prefs.DevMode) ||
				Current.ProgramState == ProgramState.Entry))

			{
				if (Widgets.ButtonText(row, "Sexuality: " + sexuality, false))
				{
					Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()			//this needs fixing in 1.1 with vanilla orientation traits
					{
						new FloatMenuOption("Asexual", (() => Change_orientation(pawn, Orientation.Asexual)), MenuOptionPriority.Default),
						new FloatMenuOption("Pansexual", (() => Change_orientation(pawn, Orientation.Pansexual)), MenuOptionPriority.Default),
						new FloatMenuOption("Heterosexual", (() => Change_orientation(pawn, Orientation.Heterosexual)), MenuOptionPriority.Default),
						new FloatMenuOption("MostlyHeterosexual", (() => Change_orientation(pawn, Orientation.MostlyHeterosexual)), MenuOptionPriority.Default),
						new FloatMenuOption("LeaningHeterosexual", (() => Change_orientation(pawn, Orientation.LeaningHeterosexual)), MenuOptionPriority.Default),
						new FloatMenuOption("Bisexual", (() => Change_orientation(pawn, Orientation.Bisexual)), MenuOptionPriority.Default),
						new FloatMenuOption("LeaningHomosexual", (() => Change_orientation(pawn, Orientation.LeaningHomosexual)), MenuOptionPriority.Default),
						new FloatMenuOption("MostlyHomosexual", (() => Change_orientation(pawn, Orientation.MostlyHomosexual)), MenuOptionPriority.Default),
						new FloatMenuOption("Homosexual", (() => Change_orientation(pawn, Orientation.Homosexual)), MenuOptionPriority.Default),
					}));
				}
			}
			else
			{
				Widgets.Label(row, "Sexuality: " + sexuality);
				if (Mouse.IsOver(row))
					Widgets.DrawHighlight(row);
			}
		}

		static void DrawQuirks(Pawn pawn, Rect row)
		{

			var quirks = Quirk.All
				.Where(quirk => pawn.Has(quirk))
				.OrderBy(quirk => quirk.Key)
				.ToList();

			// Not actually localized.
			var quirkString = quirks.Select(quirk => quirk.Key).ToCommaList();

			if ((Current.ProgramState == ProgramState.Playing &&
				pawn.IsDesignatedHero() && pawn.IsHeroOwner() ||
				Prefs.DevMode) ||
				Current.ProgramState == ProgramState.Entry)

			{
				var quirksAll = Quirk.All
								.OrderBy(quirk => quirk.Key)
								.ToList();

				if (!RJWSettings.DevMode)
				{
					quirksAll.Remove(Quirk.Breeder);
					quirksAll.Remove(Quirk.Incubator);
				}

				if (xxx.is_insect(pawn))
					quirksAll.Add(Quirk.Incubator);

				if (Widgets.ButtonText(row, "Quirks".Translate() + quirkString, false))
				{
					var list = new List<FloatMenuOption>();
					list.Add(new FloatMenuOption("Reset", (() => QuirkAdder.Clear(pawn)), MenuOptionPriority.Default));
					foreach (Quirk quirk in quirksAll)
					{
						if (!pawn.Has(quirk))
							list.Add(new FloatMenuOption(quirk.Key, (() => QuirkAdder.Add(pawn, quirk))));
						//else
						//	list.Add(new FloatMenuOption(quirk.Key, (() => QuirkAdder.Remove(pawn, quirk))));
						//TODO: fix quirk description box in 1.1 menus
						//list.Add(new FloatMenuOption(quirk.Key, (() => QuirkAdder.Add(pawn, quirk)), MenuOptionPriority.Default, delegate
						//{
						//	TooltipHandler.TipRegion(row, quirk.LocaliztionKey.Translate(pawn.Named("pawn")));
						//}
						//));
					}
					Find.WindowStack.Add(new FloatMenu(list));
				}
			}
			else
			{
				// TODO: long quirk list support
				// This can be too long and line wrap.
				// Should probably be a vertical list like traits.
				Widgets.Label(row, "Quirks".Translate() + quirkString);

			}

			if (!Mouse.IsOver(row)) return;

			Widgets.DrawHighlight(row);
			if (quirks.NullOrEmpty())
			{
				TooltipHandler.TipRegion(row, "NoQuirks".Translate());
			}
			else
			{
				StringBuilder stringBuilder = new StringBuilder();
				foreach (var q in quirks)
				{
					stringBuilder.AppendLine(q.Key.Colorize(Color.yellow));
					stringBuilder.AppendLine(q.LocaliztionKey.Translate(pawn.Named("pawn")).AdjustedFor(pawn).Resolve());
					stringBuilder.AppendLine("");
				}
				string str = stringBuilder.ToString().TrimEndNewlines();
				TooltipHandler.TipRegion(row, str);
			}
		}

		static string DrawWhoring(Pawn pawn, Rect row)
		{
			string price;
			if (pawn.ageTracker.AgeBiologicalYears < RJWSettings.sex_minimum_age)
				price = "Inapplicable (too young)";
			else if (pawn.ownership.OwnedRoom == null)
			{
				if (Current.ProgramState == ProgramState.Playing)
					price = WhoringHelper.WhoreMinPrice(pawn) + " - " + WhoringHelper.WhoreMaxPrice(pawn) + " (base, needs suitable bedroom)";
				else
					price = WhoringHelper.WhoreMinPrice(pawn) + " - " + WhoringHelper.WhoreMaxPrice(pawn) + " (base, modified by bedroom quality)";
			}
			else if (xxx.is_animal(pawn))
				price = "Incapable of whoring";
			else
				price = WhoringHelper.WhoreMinPrice(pawn) + " - " + WhoringHelper.WhoreMaxPrice(pawn);

			Widgets.Label(row, "WhorePrice".Translate() + price);
			if (Mouse.IsOver(row))
				Widgets.DrawHighlight(row);
			return price;
		}

		[SyncMethod]
		static void Change_orientation(Pawn pawn, Orientation orientation)
		{
			CompRJW.Comp(pawn).orientation = orientation;
		}

		[SyncMethod]
		static void Change_Archotechmode(Pawn pawn)
		{
			BodyPartRecord genitalia = Genital_Helper.get_genitalsBPR(pawn);
			Hediff blocker = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("ImpregnationBlocker"));
			Hediff enhancer = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("FertilityEnhancer"));

			if (blocker != null)
			{
				pawn.health.RemoveHediff(blocker);
			}
			else if (enhancer == null)
			{
				pawn.health.AddHediff(HediffDef.Named("FertilityEnhancer"), genitalia);
			}
			else
			{
				if (enhancer != null)
					pawn.health.RemoveHediff(enhancer);
				pawn.health.AddHediff(HediffDef.Named("ImpregnationBlocker"), genitalia);
			}
		}

		[SyncMethod]
		static void Re_sexualize(Pawn pawn)
		{
			CompRJW.Comp(pawn).Sexualize(pawn, true);
		}

		public override void DoWindowContents(Rect inRect)
		{
			bool flag = false;
			soundClose = SoundDefOf.InfoCard_Close;
			closeOnClickedOutside = true;
			absorbInputAroundWindow = false;
			forcePause = true;
			preventCameraMotion = false;
			if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.Escape))
			{
				flag = true;
				Event.current.Use();
			}
			Rect windowRect = inRect.ContractedBy(17f);
			Rect mainRect = new Rect(windowRect.x, windowRect.y, windowRect.width, windowRect.height - 20f);
			Rect okRect = new Rect(inRect.width / 3, mainRect.yMax + 10f, inRect.width / 3f, 30f);
			SexualityCard(mainRect, pawn);
			if (Widgets.ButtonText(okRect, "CloseButton".Translate()) || flag)
			{
				Close();
			}
		}
	}
}