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

namespace rjw
{
	public static class Genital_Helper
	{
		public static HediffDef generic_anus = HediffDef.Named("GenericAnus");
		public static HediffDef generic_penis = HediffDef.Named("GenericPenis");
		public static HediffDef generic_vagina = HediffDef.Named("GenericVagina");
		public static HediffDef generic_breasts = HediffDef.Named("GenericBreasts");

		public static HediffDef micro_penis = HediffDef.Named("MicroPenis");
		public static HediffDef small_penis = HediffDef.Named("SmallPenis");
		public static HediffDef average_penis = HediffDef.Named("Penis");
		public static HediffDef big_penis = HediffDef.Named("BigPenis");
		public static HediffDef huge_penis = HediffDef.Named("HugePenis");
		public static HediffDef hydraulic_penis = HediffDef.Named("HydraulicPenis");
		public static HediffDef bionic_penis = HediffDef.Named("BionicPenis");
		public static HediffDef archotech_penis = HediffDef.Named("ArchotechPenis");

		public static HediffDef micro_vagina = HediffDef.Named("MicroVagina");
		public static HediffDef tight_vagina = HediffDef.Named("TightVagina");
		public static HediffDef average_vagina = HediffDef.Named("Vagina");
		public static HediffDef loose_vagina = HediffDef.Named("LooseVagina");
		public static HediffDef gaping_vagina = HediffDef.Named("GapingVagina");
		public static HediffDef hydraulic_vagina = HediffDef.Named("HydraulicVagina");
		public static HediffDef bionic_vagina = HediffDef.Named("BionicVagina");
		public static HediffDef archotech_vagina = HediffDef.Named("ArchotechVagina");

		public static HediffDef flat_breasts = HediffDef.Named("FlatBreasts");
		public static HediffDef small_breasts = HediffDef.Named("SmallBreasts");
		public static HediffDef average_breasts = HediffDef.Named("Breasts");
		public static HediffDef large_breasts = HediffDef.Named("LargeBreasts");
		public static HediffDef huge_breasts = HediffDef.Named("HugeBreasts");
		public static HediffDef hydraulic_breasts = HediffDef.Named("HydraulicBreasts");
		public static HediffDef bionic_breasts = HediffDef.Named("BionicBreasts");
		public static HediffDef featureless_chest = HediffDef.Named("FeaturelessChest");
		public static HediffDef udder = HediffDef.Named("Udder");

		public static HediffDef micro_anus = HediffDef.Named("MicroAnus");
		public static HediffDef tight_anus = HediffDef.Named("TightAnus");
		public static HediffDef loose_anus = HediffDef.Named("LooseAnus");
		public static HediffDef average_anus = HediffDef.Named("Anus");
		public static HediffDef gaping_anus = HediffDef.Named("GapingAnus");
		public static HediffDef hydraulic_anus = HediffDef.Named("HydraulicAnus");
		public static HediffDef bionic_anus = HediffDef.Named("BionicAnus");
		public static HediffDef archotech_anus = HediffDef.Named("ArchotechAnus");

		public static HediffDef peg_penis = HediffDef.Named("PegDick");

		public static HediffDef insect_anus = HediffDef.Named("InsectAnus");
		public static HediffDef ovipositorM = HediffDef.Named("OvipositorM");
		public static HediffDef ovipositorF = HediffDef.Named("OvipositorF");

		public static HediffDef demonT_penis = HediffDef.Named("DemonTentaclePenis");
		public static HediffDef demon_penis = HediffDef.Named("DemonPenis");
		public static HediffDef demon_vagina = HediffDef.Named("DemonVagina");
		public static HediffDef demon_anus = HediffDef.Named("DemonAnus");

		public static HediffDef slime_breasts = HediffDef.Named("SlimeBreasts");
		public static HediffDef slime_penis = HediffDef.Named("SlimeTentacles");
		public static HediffDef slime_vagina = HediffDef.Named("SlimeVagina");
		public static HediffDef slime_anus = HediffDef.Named("SlimeAnus");

		public static HediffDef feline_penis = HediffDef.Named("CatPenis");
		public static HediffDef feline_vagina = HediffDef.Named("CatVagina");

		public static HediffDef canine_penis = HediffDef.Named("DogPenis");
		public static HediffDef canine_vagina = HediffDef.Named("DogVagina");

		public static HediffDef equine_penis = HediffDef.Named("HorsePenis");
		public static HediffDef equine_vagina = HediffDef.Named("HorseVagina");

		public static HediffDef dragon_penis = HediffDef.Named("DragonPenis");
		public static HediffDef dragon_vagina = HediffDef.Named("DragonVagina");

		public static HediffDef raccoon_penis = HediffDef.Named("RaccoonPenis");

		public static HediffDef hemipenis = HediffDef.Named("Hemipenis");

		public static HediffDef crocodilian_penis = HediffDef.Named("CrocodilianPenis");

		public static List<HediffDef> penise = new List<HediffDef> { generic_penis,
			feline_penis, canine_penis, equine_penis, dragon_penis, raccoon_penis, hemipenis,
			ovipositorM, crocodilian_penis, average_penis, micro_penis, small_penis, big_penis,
			huge_penis,	peg_penis, hydraulic_penis, bionic_penis, archotech_penis };

		public static List<HediffDef> vaginae = new List<HediffDef> { generic_vagina,
			feline_vagina, canine_vagina, equine_vagina, dragon_vagina, ovipositorF,
			average_vagina, micro_vagina, tight_vagina, loose_vagina, gaping_vagina,
			hydraulic_vagina, bionic_vagina, archotech_vagina };

		public static HashSet<String> Penis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("Penis_filter").strings);
		public static HashSet<String> HydraulicPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("HydraulicPenis_filter").strings);
		public static HashSet<String> BionicPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("BionicPenis_filter").strings);
		public static HashSet<String> Vagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("Vagina_filter").strings);
		public static HashSet<String> HydraulicVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("HydraulicVagina_filter").strings);
		public static HashSet<String> BionicVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("BionicVagina_filter").strings);
		public static HashSet<String> Breasts_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("Breasts_filter").strings);
		public static HashSet<String> HydraulicBreasts_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("HydraulicBreasts_filter").strings);
		public static HashSet<String> BionicBreasts_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("BionicBreasts_filter").strings);
		public static HashSet<String> Udder_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("Udder_filter").strings);
		public static HashSet<String> FeaturelessBreasts_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("FeaturelessBreasts_filter").strings);
		public static HashSet<String> Anus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("Anus_filter").strings);
		public static HashSet<String> HydraulicAnus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("HydraulicAnus_filter").strings);
		public static HashSet<String> BionicAnus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("BionicAnus_filter").strings);
		public static HashSet<String> InsectAnus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("InsectAnus_filter").strings);
		public static HashSet<String> OvipositorM_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("OvipositorM_filter").strings);
		public static HashSet<String> OvipositorF_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("OvipositorF_filter").strings);
		public static HashSet<String> DemonTentaclePenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DemonTentaclePenis_filter").strings);
		public static HashSet<String> DemonPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DemonPenis_filter").strings);
		public static HashSet<String> DemonVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DemonVagina_filter").strings);
		public static HashSet<String> DemonAnus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DemonAnus_filter").strings);
		public static HashSet<String> SlimeTentacles_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("SlimeTentacles_filter").strings);
		public static HashSet<String> SlimeVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("SlimeVagina_filter").strings);
		public static HashSet<String> SlimeAnus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("SlimeAnus_filter").strings);
		public static HashSet<String> SlimeBreasts_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("SlimeBreasts_filter").strings);
		public static HashSet<String> CatPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("CatPenis_filter").strings);
		public static HashSet<String> CatVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("CatVagina_filter").strings);
		public static HashSet<String> DogPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DogPenis_filter").strings);
		public static HashSet<String> DogVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DogVagina_filter").strings);
		public static HashSet<String> HorsePenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("HorsePenis_filter").strings);
		public static HashSet<String> HorseVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("HorseVagina_filter").strings);
		public static HashSet<String> DragonPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DragonPenis_filter").strings);
		public static HashSet<String> DragonVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("DragonVagina_filter").strings);
		public static HashSet<String> RaccoonPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("RaccoonPenis_filter").strings);
		public static HashSet<String> Hemipenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("Hemipenis_filter").strings);
		public static HashSet<String> CrocodilianPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("CrocodilianPenis_filter").strings);
		public static HashSet<String> NoBreasts_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("NoBreasts_filter").strings);
		public static HashSet<String> NoPenis_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("NoPenis_filter").strings);
		public static HashSet<String> NoVagina_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("NoVagina_filter").strings);
		public static HashSet<String> NoAnus_filter = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("NoAnus_filter").strings);

		public static BodyPartRecord get_genitals(Pawn pawn)
		{
			//--Log.Message("Genital_Helper::get_genitals( " + xxx.get_pawnname(pawn) + " ) called");
			BodyPartRecord Part = pawn?.RaceProps.body.AllParts.Find(bpr => bpr.def.defName == "Genitals");

			if (Part == null)
			{
				//--Log.Message("[RJW] get_genitals( " + xxx.get_pawnname(pawn) + " ) - Part is null");
				return null;
			}
			return Part;
		}

		public static BodyPartRecord get_breasts(Pawn pawn)
		{
			//--Log.Message("[RJW] get_breasts( " + xxx.get_pawnname(pawn) + " ) called");
			BodyPartRecord Part = pawn?.RaceProps.body.AllParts.Find(bpr => bpr.def.defName == "Chest");

			if (Part == null)
			{
				//--Log.Message("[RJW] get_breasts( " + xxx.get_pawnname(pawn) + " ) - Part is null");
				return null;
			}
			return Part;
		}

		public static BodyPartRecord get_anus(Pawn pawn)
		{
			//--Log.Message("[RJW] get_anus( " + xxx.get_pawnname(pawn) + " ) called");
			BodyPartRecord Part = pawn?.RaceProps.body.AllParts.Find(bpr => bpr.def.defName == "Anus");

			if (Part == null)
			{
				//--Log.Message("[RJW] get_anus( " + xxx.get_pawnname(pawn) + " ) - Part is null");
				return null;
			}
			return Part;
		}

		public static bool genitals_blocked(Pawn pawn)
		{
			if (pawn.apparel != null)
			{
				foreach (var app in pawn.apparel.WornApparel)
				{
					if ((app.def is bondage_gear_def gear_def) && (gear_def.blocks_genitals))
					{
						return true;
					}
				}
			}
			return false;
		}

		public static bool breasts_blocked(Pawn pawn)
		{
			if (pawn.apparel != null)
			{
				foreach (var app in pawn.apparel.WornApparel)
				{
					if ((app.def is bondage_gear_def gear_def) && (gear_def.blocks_breasts))
						return true;
				}
			}
			return false;
		}

		public static bool anus_blocked(Pawn pawn)
		{
			if (pawn.apparel != null)
			{
				foreach (var app in pawn.apparel.WornApparel)
				{
					if ((app.def is bondage_gear_def gear_def) && (gear_def.blocks_anus))
						return true;
				}
			}
			return false;
		}

		public static bool has_genitals(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
												  (hed.Part == Part) &&
												  (hed is Hediff_Implant || hed is Hediff_AddedPart));
		}

		public static bool has_breasts(Pawn pawn)
		{
			BodyPartRecord Part = get_breasts(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
				(hed.Part == Part) &&
				(hed is Hediff_Implant || hed is Hediff_AddedPart) &&
				!hed.def.defName.ToLower().Contains("udder") &&
				!hed.def.defName.ToLower().Contains("featureless"));
		}

		public static bool has_male_breasts(Pawn pawn)
		{
			BodyPartRecord Part = get_breasts(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
				(hed.Part == Part) &&
				(hed is Hediff_Implant || hed is Hediff_AddedPart) && hed.def == flat_breasts);
		}

		public static bool has_anus(Pawn pawn)
		{
			BodyPartRecord Part = get_anus(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) && (hed is Hediff_Implant || hed is Hediff_AddedPart));
		}

		public static bool has_penis(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) &&
						   (hed.def.defName.ToLower().Contains("penis") || hed.def.defName.ToLower().Contains("ovipositorm")));
		}

		public static bool has_multipenis(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) &&
						   (hed.def.defName.ToLower().Contains("hemipenis")));
		}

		public static bool has_penis_infertile(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) &&
						   (hed.def.defName.ToLower().Contains("pegdick") || hed.def.defName.ToLower().Contains("tentacle")));
		}

		public static bool has_ovipositorF(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) &&
						   (hed.def.defName.ToLower().Contains("ovipositorf")));

		}
		public static bool has_ovipositorM(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) &&
						   (hed.def.defName.ToLower().Contains("ovipositorm")));
		}

		public static bool has_vagina(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return false;

			return pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) &&
						   (hed.def.defName.ToLower().Contains("vagina") || hed.def.defName.ToLower().Contains("ovipositorf")));
		}

		public static Hediff get_penis(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return null;

			return pawn.health.hediffSet.hediffs.Find((Hediff hed) =>
						   (hed.Part == Part) && penise.Contains(hed.def));
		}
		public static Hediff get_vagina(Pawn pawn)
		{
			BodyPartRecord Part = get_genitals(pawn);
			if (Part is null)
				return null;

			return pawn.health.hediffSet.hediffs.Find((Hediff hed) =>
						   (hed.Part == Part) && vaginae.Contains(hed.def));
		}

		public static bool is_futa(Pawn pawn)
		{
			return (has_penis(pawn) && has_vagina(pawn));
		}

		[SyncMethod]
		public static double GenderTechLevelCheck(Pawn pawn)
		{
			if (pawn == null)
				return 0;
			//--Log.Message("[RJW] check pawn tech level for bionics ( " + xxx.get_pawnname(pawn) + " )");

			bool lowtechlevel = true;

			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			double value = Rand.Value;

			if (pawn.Faction != null)
				lowtechlevel = (int)pawn.Faction.def.techLevel < 5;

			//--save savages from inventing hydraulic and bionic genitals
			while (lowtechlevel && value >= 0.90)
			{
				value = Rand.Value;
			}
			return value;
		}

		// return True if going to set penis
		// return False for vagina
		public static bool privates_gender(Pawn pawn, Gender gender)
		{
			return (pawn.gender == Gender.Male) ? (gender != Gender.Female) : (gender == Gender.Male);
		}

		[SyncMethod]
		public static void add_genitals(Pawn pawn, Pawn parent = null, Gender gender = Gender.None)
		{
			//--Log.Message("Genital_Helper::add_genitals( " + xxx.get_pawnname(pawn) + " ) called");
			BodyPartRecord Part = get_genitals(pawn);
			//--Log.Message("Genital_Helper::add_genitals( " + xxx.get_pawnname(pawn) + " ) - checking genitals");
			if (Part == null)
			{
				//--Log.Message("[RJW] add_genitals( " + xxx.get_pawnname(pawn) + " ) doesn't have a genitals");
				return;
			}
			else if (pawn.health.hediffSet.PartIsMissing(Part))
			{
				//--Log.Message("[RJW] add_genitals( " + xxx.get_pawnname(pawn) + " ) had a genital but was removed.");
				return;
			}
			if (has_genitals(pawn) && gender == Gender.None)//allow to add gender specific genitals(futa)
			{
				//--Log.Message("[RJW] add_genitals( " + xxx.get_pawnname(pawn) + " ) already has genitals");
				return;
			}
			var temppawn = pawn;
			if (parent != null)
				temppawn = parent;

			HediffDef privates;
			double value = GenderTechLevelCheck(pawn);
			string racename = temppawn.kindDef.race.defName.ToLower();

			// maybe add some check based on bodysize of pawn for genitals size limit
			//Log.Message("Genital_Helper::add_genitals( " + pawn.RaceProps.baseBodySize + " ) - 1");
			//Log.Message("Genital_Helper::add_genitals( " + pawn.kindDef.race.size. + " ) - 2");

			privates = (privates_gender(pawn, gender)) ? generic_penis : generic_vagina;

			if (has_vagina(pawn) && privates == generic_vagina)
			{
				//--Log.Message("[RJW] add_genitals( " + xxx.get_pawnname(pawn) + " ) already has vagina");
				return;
			}
			if ((has_penis(pawn) || has_penis_infertile(pawn)) && privates == generic_penis)
			{
				//--Log.Message("[RJW] add_genitals( " + xxx.get_pawnname(pawn) + " ) already has penis");
				return;
			}

			//override race genitals
			if (privates == generic_vagina)
			{
				if (NoVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					return;
				}
				if (Vagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(average_vagina, Part);
					return;
				}
				if (HydraulicVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(hydraulic_vagina, Part);
					return;
				}
				if (BionicVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(bionic_vagina, Part);
					return;
				}
				if (DemonVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(demon_vagina, Part);
					return;
				}
				if (SlimeVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(slime_vagina, Part);
					return;
				}
				if (CatVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(feline_vagina, Part);
					return;
				}
				if (DogVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(canine_vagina, Part);
					return;
				}
				if (HorseVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(equine_vagina, Part);
					return;
				}
				if (DragonVagina_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(dragon_vagina, Part);
					return;
				}
				if (OvipositorF_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(ovipositorF, Part);
					return;
				}
			}
			if (privates == generic_penis)
			{
				if (NoPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					return;
				}
				if (Penis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(average_penis, Part);
					return;
				}
				if (HydraulicPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(hydraulic_penis, Part);
					return;
				}
				if (BionicPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(bionic_penis, Part);
					return;
				}
				if (DemonTentaclePenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(demonT_penis, Part);
					return;
				}
				if (DemonPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(demon_penis, Part);
					return;
				}
				if (SlimeTentacles_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(slime_penis, Part);
					return;
				}
				if (CatPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(feline_penis, Part);
					return;
				}
				if (DogPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(canine_penis, Part);
					return;
				}
				if (HorsePenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(equine_penis, Part);
					return;
				}
				if (DragonPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(dragon_penis, Part);
					return;
				}
				if (RaccoonPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(raccoon_penis, Part);
					return;
				}
				if (Hemipenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(hemipenis, Part);
					return;
				}
				if (CrocodilianPenis_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(crocodilian_penis, Part);
					return;
				}
				if (OvipositorM_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(ovipositorM, Part);
					return;
				}
			}

			//Log.Message("Genital_Helper::add_genitals( " + xxx.get_pawnname(pawn));
			//Log.Message("Genital_Helper::add_genitals( " + pawn.kindDef.race.defName);
			if (xxx.is_mechanoid(pawn))
			{
				return;
			}
			//insects
			else if (xxx.is_insect(temppawn)
				 || racename.Contains("apini")
				 || racename.Contains("mantodean")
				 || racename.Contains("insect")
				 || racename.Contains("bug"))
			{
				privates = (privates_gender(pawn, gender)) ? ovipositorM : ovipositorF;
			}
			//space cats pawns
			else if ((racename.Contains("orassan") || racename.Contains("neko")) && !racename.ContainsAny("akaneko"))
			{
				if ((value < 0.70) || (pawn.ageTracker.AgeBiologicalYears < 2) || !pawn.RaceProps.Humanlike)
					privates = (privates_gender(pawn, gender)) ? feline_penis : feline_vagina;
				else if (value < 0.90)
					privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
				else
					privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
			}
			//space dog pawns
			else if (racename.Contains("fennex")
				 || racename.Contains("xenn")
				 || racename.Contains("leeani")
				 || racename.Contains("ferian")
				 || racename.Contains("callistan"))
			{
				if ((value < 0.70) || (pawn.ageTracker.AgeBiologicalYears < 2) || !pawn.RaceProps.Humanlike)
					privates = (privates_gender(pawn, gender)) ? canine_penis : canine_vagina;
				else if (value < 0.90)
					privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
				else
					privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
			}
			//space horse pawns
			else if (racename.Contains("equium"))
			{
				if ((value < 0.70) || (pawn.ageTracker.AgeBiologicalYears < 2) || !pawn.RaceProps.Humanlike)
					privates = (privates_gender(pawn, gender)) ? equine_penis : equine_vagina;
				else if (value < 0.90)
					privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
				else
					privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
			}
			//space raccoon pawns
			else if (racename.Contains("racc") && !racename.Contains("raccoon"))
			{
				if ((value < 0.70) || (pawn.ageTracker.AgeBiologicalYears < 2) || !pawn.RaceProps.Humanlike)
				{
					privates = (privates_gender(pawn, gender)) ? raccoon_penis : generic_vagina;
				}
				else if (value < 0.90)
				{
					privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
				}
				else
				{
					privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
				}
			}
			//alien races - ChjDroid, ChjAndroid
			else if (racename.Contains("droid"))
			{
				if (pawn.story.GetBackstory(BackstorySlot.Childhood) != null)
				{
					if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("bishojo"))
						privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("pleasure"))
						privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("idol"))
						privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("social"))
						privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("substitute"))
					{
						if (value < 0.05)
							privates = (privates_gender(pawn, gender)) ? micro_penis : micro_vagina;
						else if (value < 0.20)
							privates = (privates_gender(pawn, gender)) ? small_penis : tight_vagina;
						else if (value < 0.70)
							privates = (privates_gender(pawn, gender)) ? average_penis : average_vagina;
						else if (value < 0.80)
							privates = (privates_gender(pawn, gender)) ? big_penis : loose_vagina;
						else if (value < 0.90)
							privates = (privates_gender(pawn, gender)) ? huge_penis : gaping_vagina;
						else if (value < 0.95)
							privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
						else
							privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
					}
					else if (pawn.story.GetBackstory(BackstorySlot.Adulthood) != null)
					{
						if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("courtesan"))
							privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
						else if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("social"))
							privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
					}
					else
						return;
				}
				else if (pawn.story.GetBackstory(BackstorySlot.Adulthood) != null)
				{
					if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("courtesan"))
						privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
					else if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("social"))
						privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
				}
				if (privates == generic_penis || privates == generic_vagina)
					return;
			}
			//animal cats
			else if (racename.ContainsAny("cat", "cougar", "lion", "leopard", "cheetah", "panther", "tiger", "lynx", "smilodon", "akaneko"))
			{
				privates = (privates_gender(pawn, gender)) ? feline_penis : feline_vagina;
			}
			//animal canine/dogs
			else if (racename.ContainsAny("husky", "warg", "terrier", "collie", "hound", "retriever", "mastiff", "wolf", "fox",
				"vulptex", "dachshund", "schnauzer", "corgi", "pug", "doberman", "chowchow", "borzoi", "saintbernard", "newfoundland",
				"poodle", "dog", "coyote") && !racename.Contains("lf_foxia"))
			{
				privates = (privates_gender(pawn, gender)) ? canine_penis : canine_vagina;
			}
			//animal horse - MoreMonstergirls
			else if (racename.ContainsAny("horse", "centaur", "zebra", "donkey", "dryad"))
			{
				privates = (privates_gender(pawn, gender)) ? equine_penis : equine_vagina;
			}
			//animal raccoon
			else if (racename.Contains("racc"))
			{
				privates = (privates_gender(pawn, gender)) ? raccoon_penis : generic_vagina;
			}
			//animal crocodilian (alligator, crocodile, etc)
			else if (racename.ContainsAny("alligator", "crocodile", "caiman", "totodile", "croconaw", "feraligatr", "quinkana", "purussaurus", "kaprosuchus", "sarcosuchus"))
			{
				privates = (privates_gender(pawn, gender)) ? crocodilian_penis : generic_vagina;
			}
			//hemipenes - mostly reptiles and snakes
			else if (racename.ContainsAny("guana", "cobra", "gecko", "snake", "boa", "quinkana", "megalania", "gila", "gigantophis", "komodo", "basilisk", "thorny", "onix", "lizard", "slither") && !racename.ContainsAny("boar"))
			{
				privates = (privates_gender(pawn, gender)) ? hemipenis : generic_vagina;
			}
			//animal dragon - MoreMonstergirls
			else if (racename.ContainsAny("dragon", "thrumbo", "drake", "charizard", "saurus")&& !racename.Contains("lf_dragonia"))
			{
				privates = (privates_gender(pawn, gender)) ? dragon_penis : dragon_vagina;
			}
			//animal slime - MoreMonstergirls
			else if (racename.Contains("slime"))
			{
				//privates = (privates_gender(pawn, gender)) ? slime_penis : slime_vagina;
				pawn.health.AddHediff((privates_gender(pawn, gender)) ? slime_penis : slime_vagina, Part);
				pawn.health.AddHediff((privates_gender(pawn, gender)) ? slime_vagina : slime_penis, Part);
				return;
			}
			//animal demons - MoreMonstergirls
			else if (racename.Contains("impmother") || racename.Contains("demon"))
			{
				pawn.health.AddHediff((privates_gender(pawn, gender)) ? demon_penis : demon_vagina, Part);
				//Rand.PopState();
				//Rand.PushState(RJW_Multiplayer.PredictableSeed());
				if (Rand.Value < 0.25f)
					pawn.health.AddHediff((privates_gender(pawn, gender)) ? demon_penis : demonT_penis, Part);
				return;
			}
			//animal demons - MoreMonstergirls
			else if (racename.Contains("baphomet"))
			{
				//Rand.PopState();
				//Rand.PushState(RJW_Multiplayer.PredictableSeed());
				if (Rand.Value < 0.50f)
					pawn.health.AddHediff((privates_gender(pawn, gender)) ? demon_penis : demon_vagina, Part);
				else
					pawn.health.AddHediff((privates_gender(pawn, gender)) ? equine_penis : demon_vagina, Part);
				return;
			}
			//humanoid monstergirls - LostForest
			else if (racename.ContainsAny("lf_dragonia", "lf_flammelia", "lf_foxia", "lf_glacia", "lf_lefca", "lf_wolvern"))
			{
				if (value < 0.05)
					privates = (privates_gender(pawn, gender)) ? micro_penis : micro_vagina;
				else if (value < 0.20)
					privates = (privates_gender(pawn, gender)) ? small_penis : tight_vagina;
				else if (value < 0.70)
					privates = (privates_gender(pawn, gender)) ? average_penis : average_vagina;
				else if (value < 0.90)
					privates = (privates_gender(pawn, gender)) ? big_penis : loose_vagina;
				else
					privates = (privates_gender(pawn, gender)) ? huge_penis : loose_vagina;
				}
			else if (pawn.RaceProps.Humanlike)
			{
				//--Log.Message("Genital_Helper::add_genitals( " + xxx.get_pawnname(pawn) + " ) - race is humanlike");
				if (pawn.ageTracker.AgeBiologicalYears < 5)
				{
					if (value < 0.05)
						privates = (privates_gender(pawn, gender)) ? micro_penis : micro_vagina;
					else if (value < 0.20)
						privates = (privates_gender(pawn, gender)) ? small_penis : tight_vagina;
					else if (value < 0.70)
						privates = (privates_gender(pawn, gender)) ? average_penis : average_vagina;
					else if (value < 0.90)
						privates = (privates_gender(pawn, gender)) ? big_penis : loose_vagina;
					else
						privates = (privates_gender(pawn, gender)) ? huge_penis : loose_vagina;
				}
				else
				{
					if (value < 0.02)
						privates = (privates_gender(pawn, gender)) ? peg_penis : micro_vagina;
					else if (value < 0.05)
						privates = (privates_gender(pawn, gender)) ? micro_penis : micro_vagina;
					else if (value < 0.20)
						privates = (privates_gender(pawn, gender)) ? small_penis : tight_vagina;
					else if (value < 0.70)
						privates = (privates_gender(pawn, gender)) ? average_penis : average_vagina;
					else if (value < 0.80)
						privates = (privates_gender(pawn, gender)) ? big_penis : loose_vagina;
					else if (value < 0.90)
						privates = (privates_gender(pawn, gender)) ? huge_penis : gaping_vagina;
					else if (value < 0.95)
						privates = (privates_gender(pawn, gender)) ? hydraulic_penis : hydraulic_vagina;
					else
						privates = (privates_gender(pawn, gender)) ? bionic_penis : bionic_vagina;
				}
			}
			//--Log.Message("Genital_Helper::add_genitals final ( " + xxx.get_pawnname(pawn) + " ) " + privates.defName);
			pawn.health.AddHediff(privates, Part);
		}

		public static void add_breasts(Pawn pawn, Pawn parent = null, Gender gender = Gender.None)
		{
			//--Log.Message("[RJW] add_breasts( " + xxx.get_pawnname(pawn) + " ) called");
			BodyPartRecord Part = get_breasts(pawn);

			if (Part == null)
			{
				//--Log.Message("[RJW] add_breasts( " + xxx.get_pawnname(pawn) + " ) - pawn doesn't have a breasts");
				return;
			}
			else if (pawn.health.hediffSet.PartIsMissing(Part))
			{
				//--Log.Message("[RJW] add_breasts( " + xxx.get_pawnname(pawn) + " ) had breasts but were removed.");
				return;
			}
			if (has_breasts(pawn))
			{
				//--Log.Message("[RJW] add_breasts( " + xxx.get_pawnname(pawn) + " ) - pawn already has breasts");
				return;
			}

			var temppawn = pawn;
			if (parent != null)
				temppawn = parent;

			HediffDef bewbs;
			double value = GenderTechLevelCheck(pawn);
			string racename = temppawn.kindDef.race.defName.ToLower();

			bewbs = generic_breasts;

			//TODO: figure out how to add (flat) breasts to males
			if (bewbs == generic_breasts)
			{
				if (NoBreasts_filter.Contains(pawn.kindDef.race.defName))
				{
					return;
				}
				if (FeaturelessBreasts_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(featureless_chest, Part);
					return;
				}
				if (pawn.gender == Gender.Female || gender == Gender.Female)
				{
					if (Breasts_filter.Contains(pawn.kindDef.race.defName))
					{
						pawn.health.AddHediff(average_breasts, Part);
						return;
					}
					if (HydraulicBreasts_filter.Contains(pawn.kindDef.race.defName))
					{
						pawn.health.AddHediff(hydraulic_breasts, Part);
						return;
					}
					if (BionicBreasts_filter.Contains(pawn.kindDef.race.defName))
					{
						pawn.health.AddHediff(bionic_breasts, Part);
						return;
					}
					if (Udder_filter.Contains(pawn.kindDef.race.defName))
					{
						pawn.health.AddHediff(udder, Part);
						return;
					}
					if (SlimeBreasts_filter.Contains(pawn.kindDef.race.defName))
					{
						pawn.health.AddHediff(slime_breasts, Part);
						return;
					}
				}
			}
			if (xxx.is_mechanoid(pawn))
			{
				return;
			}
			if (xxx.is_insect(temppawn))
			{
				// this will probably need override in case there are humanoid insect race
				//--Log.Message("[RJW] add_breasts( " + xxx.get_pawnname(pawn) + " ) - is insect,doesnt need breasts");
				return;
			}
			//alien races - MoreMonstergirls
			else if (racename.Contains("slime"))
			{
				//slimes are always females, and idc what anyone else say!
				pawn.health.AddHediff(slime_breasts, Part);
				return;
			}
			else if(pawn.gender == Gender.Female || gender == Gender.Female)
			{
				if (pawn.RaceProps.Humanlike)
				{
					//alien races - ChjDroid, ChjAndroid
					if (racename.ContainsAny("mantis", "rockman", "slug", "zoltan", "engie", "sergal", "cutebold", "dodo", "owl", "parrot",
						"penguin", "cassowary", "chicken", "vulture"))
					{
						pawn.health.AddHediff(featureless_chest, Part);
						return;
					}
					else if (racename.ContainsAny("avali", "khess"))
					{
						return;
					}
					else if (racename.Contains("droid"))
					{
						if (pawn.story.GetBackstory(BackstorySlot.Childhood) != null)
						{
							if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("bishojo"))
								bewbs = bionic_breasts;
							else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("pleasure"))
								bewbs = bionic_breasts;
							else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("idol"))
								bewbs = bionic_breasts;
							else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("social"))
								bewbs = hydraulic_breasts;
							else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("substitute"))
							{
								if (value < 0.05)
									bewbs = flat_breasts;
								else if (value < 0.25)
									bewbs = small_breasts;
								else if (value < 0.70)
									bewbs = average_breasts;
								else if (value < 0.80)
									bewbs = large_breasts;
								else if (value < 0.90)
									bewbs = huge_breasts;
								else if (value < 0.95)
									bewbs = hydraulic_breasts;
								else
									bewbs = bionic_breasts;
							}
							else if (pawn.story.GetBackstory(BackstorySlot.Adulthood) != null)
							{
								if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("courtesan"))
									bewbs = bionic_breasts;
								else if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("social"))
									bewbs = hydraulic_breasts;
							}
							else
								return;
						}
						else if (pawn.story.GetBackstory(BackstorySlot.Adulthood) != null)
						{
							if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("courtesan"))
								bewbs = bionic_breasts;
							else if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("social"))
								bewbs = hydraulic_breasts;
						}
						if (bewbs == generic_breasts)
							return;
					}
					//alien races - MoreMonstergirls
					//alien races - Kijin
					else if (racename.Contains("cowgirl") || racename.Contains("kijin"))
					{
						if (value < 0.05)
							bewbs = flat_breasts;
						else if (value < 0.10)
							bewbs = small_breasts;
						else if (value < 0.20)
							bewbs = average_breasts;
						else if (value < 0.50)
							bewbs = large_breasts;
						else if (value < 0.75 && racename.Contains("cowgirl"))
							bewbs = udder;
						else
							bewbs = huge_breasts;
					}
					else if (pawn.ageTracker.AgeBiologicalYears < 5)
					{
						if (value < 0.05)
							bewbs = flat_breasts;
						else if (value < 0.15)
							bewbs = small_breasts;
						else if (value < 0.70)
							bewbs = average_breasts;
						else if (value < 0.80)
							bewbs = large_breasts;
						else
							bewbs = huge_breasts;
					}
					else
					{
						if (value < 0.05)
							bewbs = flat_breasts;
						else if (value < 0.25)
							bewbs = small_breasts;
						else if (value < 0.70)
							bewbs = average_breasts;
						else if (value < 0.80)
							bewbs = large_breasts;
						else if (value < 0.90)
							bewbs = huge_breasts;
						else if (value < 0.95)
							bewbs = hydraulic_breasts;
						else
							bewbs = bionic_breasts;
					}
				}
				//humanoid monstergirls - LostForest
				else if (racename.ContainsAny("lf_dragonia", "lf_flammelia", "lf_foxia", "lf_glacia", "lf_lefca", "lf_wolvern"))
				{
				if (value < 0.10)
					bewbs = flat_breasts;
				else if (value < 0.30)
					bewbs = small_breasts;
				else if (value < 0.70)
					bewbs = average_breasts;
				else if (value < 0.90)
					bewbs = large_breasts;
				else
					bewbs = huge_breasts;
				}
				else if (racename.ContainsAny("mammoth", "elasmotherium", "chalicotherium", "megaloceros", "sivatherium", "deinotherium",
					"aurochs", "zygolophodon", "uintatherium", "gazelle", "ffalo", "boomalope", "cow", "miltank", "elk", "reek", "nerf",
					"bantha", "tauntaun", "caribou", "deer", "ibex", "dromedary", "alpaca", "llama", "goat", "moose"))
				{
					pawn.health.AddHediff(udder, Part);
					return;
				}
				else if (racename.ContainsAny("cassowary", "emu", "dinornis", "ostrich", "turkey", "chicken", "duck", "murkroW", "bustard", "palaeeudyptes",
					"goose", "tukiri", "porg", "yi", "kiwi", "penguin", "quail", "ptarmigan", "doduo", "flamingo", "plup", "empoleon", "meadow ave") && !racename.ContainsAny("duck-billed"))
				{
					return;	 // Separate list for birds, to make it easier to add cloaca at some later date.
				}	// Other breastless creatures.
				else if (racename.ContainsAny("titanis", "titanoboa", "guan", "tortoise", "turt", "aerofleet", "quinkana", "megalochelys",
					"purussaurus", "cobra", "dewback", "rancor", "frog", "onyx", "flommel", "lapras", "aron", "chinchou",
					"squirtle", "wartortle", "blastoise", "totodile", "croconaw", "feraligatr", "litwick", "pumpkaboo", "shuppet", "haunter",
					"gastly", "oddish", "hoppip", "tropius", "budew", "roselia", "bellsprout", "drifloon", "chikorita", "bayleef", "meganium",
					"char", "drago", "dratini", "saur", "tyrannus", "carnotaurus", "baryonyx", "minmi", "diplodocus", "phodon", "indominus",
					"raptor", "caihong", "coelophysis", "cephale", "compsognathus", "mimus", "troodon", "dactyl", "tanystropheus", "geosternbergia",
					"deino", "suchus", "dracorex", "cephalus", "trodon", "quetzalcoatlus", "pteranodon", "antarctopelta", "stygimoloch", "rhabdodon",
					"rhamphorhynchus", "ceratops", "ceratus", "zalmoxes", "mochlodon", "gigantophis", "crab", "pulmonoscorpius", "manipulator",
					"meganeura", "euphoberia", "holcorobeus", "protosolpuga", "barbslinger", "blizzarisk", "frostmite", "devourer", "hyperweaver",
					"macrelcana", "acklay", "elemental", "megalania", "gecko", "gator", "komodo", "scolipede", "shuckle", "combee", "shedinja",
					"caterpie", "wurmple", "lockjaw", "needlepost", "needleroll", "squid", "slug", "gila", "pleura"))
				{
					return;
				}
				pawn.health.AddHediff(bewbs, Part);
			}
		}

		public static void add_anus(Pawn pawn, Pawn parent = null)
		{
			BodyPartRecord Part = get_anus(pawn);

			if (Part == null)
			{
				//--Log.Message("[RJW] add_anus( " + xxx.get_pawnname(pawn) + " ) doesn't have an anus");
				return;
			}
			else if (pawn.health.hediffSet.PartIsMissing(Part))
			{
				//--Log.Message("[RJW] add_anus( " + xxx.get_pawnname(pawn) + " ) had an anus but was removed.");
				return;
			}
			if (has_anus(pawn))
			{
				//--Log.Message("[RJW] add_anus( " + xxx.get_pawnname(pawn) + " ) already has an anus");
				return;
			}

			var temppawn = pawn;
			if (parent != null)
				temppawn = parent;

			HediffDef asshole;
			double value = GenderTechLevelCheck(pawn);
			string racename = temppawn.kindDef.race.defName.ToLower();

			asshole = generic_anus;

			if (asshole == generic_anus)
			{
				if (NoAnus_filter.Contains(pawn.kindDef.race.defName))
				{
					return;
				}
				if (Anus_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(average_anus, Part);
					return;
				}
				if (HydraulicAnus_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(hydraulic_anus, Part);
					return;
				}
				if (BionicAnus_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(bionic_anus, Part);
					return;
				}
				if (DemonAnus_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(demon_anus, Part);
					return;
				}
				if (SlimeAnus_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(slime_anus, Part);
					return;
				}
				if (InsectAnus_filter.Contains(pawn.kindDef.race.defName))
				{
					pawn.health.AddHediff(insect_anus, Part);
					return;
				}
			}
			if (xxx.is_mechanoid(pawn))
			{
				return;
			}
			else if (xxx.is_insect(temppawn))
			{
				asshole = insect_anus;
			}
			//alien races - ChjDroid, ChjAndroid
			else if (racename.Contains("droid"))
			{
				if (pawn.story.GetBackstory(BackstorySlot.Childhood) != null)
				{
					if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("bishojo"))
						asshole = bionic_anus;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("pleasure"))
						asshole = bionic_anus;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("idol"))
						asshole = bionic_anus;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("social"))
						asshole = hydraulic_anus;
					else if (pawn.story.childhood.untranslatedTitleShort.ToLower().Contains("substitute"))
					{
						if (value < 0.05)
							asshole = micro_anus;
						else if (value < 0.20)
							asshole = tight_anus;
						else if (value < 0.70)
							asshole = average_anus;
						else if (value < 0.80)
							asshole = loose_anus;
						else if (value < 0.90)
							asshole = gaping_anus;
						else if (value < 0.95)
							asshole = hydraulic_anus;
						else
							asshole = bionic_anus;
					}
					else if (pawn.story.GetBackstory(BackstorySlot.Adulthood) != null)
					{
						if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("courtesan"))
							asshole = bionic_anus;
						else if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("social"))
							asshole = hydraulic_anus;
					}
				}
				else if (pawn.story.GetBackstory(BackstorySlot.Adulthood) != null)
				{
					if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("courtesan"))
						asshole = bionic_anus;
					else if (pawn.story.adulthood.untranslatedTitleShort.ToLower().Contains("social"))
						asshole = hydraulic_anus;
				}
				if (asshole == generic_anus)
					return;
			}
			else if (racename.Contains("slime"))
			{
				asshole = slime_anus;
			}
			//animal demons - MoreMonstergirls
			else if (racename.Contains("impmother") || racename.Contains("baphomet") || racename.Contains("demon"))
			{
				asshole = demon_anus;
			}
			//humanoid monstergirls - LostForest
			else if (racename.ContainsAny("lf_dragonia", "lf_flammelia", "lf_foxia", "lf_glacia", "lf_lefca", "lf_wolvern"))
			{
				if (value < 0.05)
					asshole = micro_anus;
				else if (value < 0.20)
					asshole = tight_anus;
				else if (value < 0.90)
					asshole = average_anus;
				else
					asshole = loose_anus;
			}
			else if (pawn.RaceProps.Humanlike)
			{
				if (pawn.ageTracker.AgeBiologicalYears < 5)
				{
					if (value < 0.05)
						asshole = micro_anus;
					else if (value < 0.20)
						asshole = tight_anus;
					else if (value < 0.90)
						asshole = average_anus;
					else
						asshole = loose_anus;
				}
				else
				{
					if (value < 0.05)
						asshole = micro_anus;
					else if (value < 0.20)
						asshole = tight_anus;
					else if (value < 0.70)
						asshole = average_anus;
					else if (value < 0.80)
						asshole = loose_anus;
					else if (value < 0.90)
						asshole = gaping_anus;
					else if (value < 0.95)
						asshole = hydraulic_anus;
					else
						asshole = bionic_anus;
				}
			}
			pawn.health.AddHediff(asshole, Part);
		}

		[SyncMethod]
		public static void sexualize_pawn(Pawn pawn)
		{
			//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) called");
			if (pawn == null)
				return;

			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			if (!pawn.RaceProps.hasGenders)
			{
				if (Current.ProgramState == ProgramState.Playing) // DO NOT run at world generation, throws error
				{
					if (RJWSettings.GenderlessAsFuta && !xxx.is_mechanoid(pawn))
					{
						Log.Message("[RJW] sexualize_pawn() - genderless pawn, treating Genderless pawn As Futa" + xxx.get_pawnname(pawn));
						//set gender to female for futas
						pawn.gender = Gender.Female;
						add_genitals(pawn, null, Gender.Male);
						add_genitals(pawn, null, Gender.Female);
						add_breasts(pawn, null, Gender.Female);
						add_anus(pawn, null);
					}
					else
						Log.Message("[RJW] sexualize_pawn() - unable to sexualize genderless pawn " + xxx.get_pawnname(pawn) + " gender: " + pawn.gender);
					return;
				}
			}
			else
			{
				//apply normal gender
				//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) add genitals");
				add_genitals(pawn, null, pawn.gender);
				//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) add breasts");
				add_breasts(pawn, null, pawn.gender);
				//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) add anus");
				add_anus(pawn, null);

				//apply futa gender
				//if (pawn.gender == Gender.Female) // changing male to futa will break pawn generation due to relations
				//if (Current.ProgramState == ProgramState.Playing) // DO NOT run at world generation, throws error
				{
					if (pawn.Faction != null && !xxx.is_animal(pawn)) //null faction throws error
					{
						//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) techLevel: " + (int)pawn.Faction.def.techLevel);
						//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) techLevel: " + pawn.Faction.Name);

						//natives/spacer futa
						float chance = (int)pawn.Faction.def.techLevel < 5 ? RJWSettings.futa_natives_chance : RJWSettings.futa_spacers_chance;
						//nymph futa gender
						chance = xxx.is_nympho(pawn) ? RJWSettings.futa_nymph_chance : chance;

						if (Rand.Chance(chance))
						{
							//make futa
							if (pawn.gender == Gender.Female && RJWSettings.FemaleFuta)
								add_genitals(pawn, null, Gender.Male);
							//make trap
							else if (pawn.gender == Gender.Male && RJWSettings.MaleTrap)
								add_breasts(pawn, null, Gender.Female);
						}
					}
				}
			}

			if (!pawn.Dead)
			{
				//Add ticks at generation, so pawns don't instantly start lovin' when generated (esp. on scenario start).
				//if (xxx.RoMIsActive && pawn.health.hediffSet.HasHediff(HediffDef.Named("TM_ShapeshiftHD"))) // Rimworld of Magic's polymorph/shapeshift
				//	pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.01f, 0.05f));
				if (!xxx.is_insect(pawn))
					pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.1f, 1.0f));
				else
					pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.01f, 0.2f));

				//Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) add sexneed");
				if (pawn.RaceProps.Humanlike)
				{
					var sex_need = pawn.needs.TryGetNeed<Need_Sex>();
					if (pawn.Faction != null && !(pawn.Faction?.IsPlayer ?? false) && sex_need != null)
					{
						sex_need.CurLevel = Rand.Range(0.01f, 0.75f);
					}
				}
			}
		}
	}
}


code:
using Verse;

namespace rjw
{
	public class MapCom_Injector : MapComponent
	{
		public bool injected_designator = false;

		public bool triggered_after_load = false;

		public MapCom_Injector(Map m) : base(m)
		{
		}

		public override void MapComponentUpdate()
		{
		}

		public override void MapComponentTick()
		{
		}

		public override void MapComponentOnGUI()
		{
			var currently_visible = Find.CurrentMap == map;

			if ((!injected_designator) && currently_visible)
			{
				//Find.ReverseDesignatorDatabase.AllDesignators.Add(new Designator_ComfortPrisoner());
				//Find.ReverseDesignatorDatabase.AllDesignators.Add(new Designator_Breed());
				injected_designator = true;
			}
			else if (injected_designator && (!currently_visible))
				injected_designator = false;
		}

		public override void ExposeData()
		{
		}
	}
}

repo_name: Harper/rjw

license: mit


code:
using System;
using Verse;

namespace rjw
{
	public sealed class MiscTranslationDef : Def
	{
		public Type targetClass;
		public string stringA = null;
		public string stringB = null;
		public string stringC = null;

		private void Assert(bool check, string errorMessage)
		{
			if (!check)
			{
				Log.Error($"[RJW] Invalid data in MiscTranslationDef {defName}: {errorMessage}");
			}
		}

		public override void PostLoad()
		{
			Assert(targetClass != null, "targetClass field must be set");
		}

		public override void ResolveReferences()
		{
			base.ResolveReferences();
		}
	}
}


code:
/*using Verse;
using HugsLib;
using HugsLib.Settings;
using HugsLib.Utils;
using System;
using System.Collections.Generic;

namespace rjw
{
	/// <summary>
	/// Harmony provided class for mod settings.
	/// BEWARE, there is currently nasty mixup between these and the ancient config.cs
	/// </summary>
	public class Mod_Settings : ModBase
	{
		public override string ModIdentifier
		{
			get
			{
				return "RJW";
			}
		}

		public override Version GetVersion()
		{
			//--Log.Message("GetVersion() called");
			return base.GetVersion();
		}

		public static DataStore DataStore;//reference to savegame data, hopefully
		public override void WorldLoaded()
		{
			DataStore = UtilityWorldObjectManager.GetUtilityWorldObject<DataStore>();
		}
		protected override bool HarmonyAutoPatch { get => false; }//first.cs creates harmony and does some convoulted stuff with it

		public static bool WildMode;
		public static bool GenderlessAsFuta;
		public static float sexneed_decay_rate;
		public static bool nymphos;
		public static float male_nymph_chance;
		public static float futa_nymph_chance;
		public static float futa_natives_chance;
		public static float futa_spacers_chance;
		public static bool std_floor;
		public static uint sex_minimum_age;
		public static uint sex_free_for_all_age;

		public static bool prisoner_beating;
		public static bool visitor_CP_rape;
		public static bool animal_CP_rape;
		public static float NonFutaWomenRaping_MaxVulnerability;
		public static float Rapee_MinVulnerability_human;
		//Disabled, because using same vulnerability calculatuion for animals and colonists doesn't work at all.
		//Need to implement a separate animal vulnerability stat somehow.
		//public static float Rapee_MinVulnerability_animals;

		// Feature Toggles
		public static bool comfort_prisoners_enabled; // Updated //this one is in config.cs as well!
		public static bool ComfortColonist; // New
		public static bool ComfortAnimal; // New
		public static bool cum_enabled = true; // TODO: Add as toggle.
		public static bool rape_me_sticky_enabled; // Updated
		public static bool sounds_enabled = true; // TODO: Add as toggle.
		public static bool stds_enabled; // Updated
		public static bool bondage_gear_enabled; // Updated
		public static bool nymph_joiners_enabled; // Updated
		public static bool random_rape_enabled = true; // TODO: Add as toggle.
		public static bool always_accept_whores; // Updated
		public static bool nymphs_always_JoinInBed; // Updated
		public static bool zoophis_always_rape; // Updated
		public static bool rapists_always_rape; // Updated
		public static bool pawns_always_do_fapping; // Updated
		public static bool pawns_always_rapeCP; // Updated
		public static bool whores_always_findjob; // Updated

		public static bool animal_on_animal_enabled;
		public static bool necrophilia_enabled;
		public static bool bestiality_enabled; // Updated
		public static bool submit_button_enabled; //added

		// Display Toggles
		public bool show_regular_dick_and_vag; // Updated
		public static bool show_RJW_designation_box;

		// STD config
		public bool std_show_roll_to_catch; // Updated
		public float std_min_severity_to_pitch; // Updated
		public float std_env_pitch_cleanliness_exaggeration; // Updated
		public float std_env_pitch_dirtiness_exaggeration; // Updated
		public float std_outdoor_cleanliness; // Updated

		// Age Config
		//

		public float significant_pain_threshold; // Updated
		public float extreme_pain_threshold; // Updated
		public float base_chance_to_hit_prisoner; // Updated
		public int min_ticks_between_hits; // Updated
		public int max_ticks_between_hits; // Updated

		public float max_nymph_fraction; // Updated
		public float opp_inf_initial_immunity; // Updated
		public float comfort_prisoner_rape_mtbh_mul; // Updated
		public float whore_mtbh_mul; // Updated
		public float nymph_spawn_with_std_mul; // Updated

		// Pregnancy config
		public static uint pregnancy_weight_parent; //to-do: convert 'em into float
		public static uint pregnancy_weight_species;
		public static uint pregnancy_coefficient_human;
		public static uint pregnancy_coefficient_animals;
		public static bool pregnancy_use_parent_method;

		public static bool RJWH_pregnancy;
		public static bool RJWB_pregnancy;
		public static bool RJWI_pregnancy;
		public static bool RJWM_pregnancy;
		public static bool RJWA_pregnancy;
		//public static bool CP_pregnancy;
		public static bool genetic_trait_filter;

		//disabled for now, since the new version scales to lifespan and flat values don't work with that.
		//public static float fertility_endAge_male;
		//public static float fertility_endAge_female;

		//sex types
		public static float vaginal_sex;
		public static float anal_sex;
		public static float fellatio_sex;
		public static float cunnilingus_sex;
		public static float rimming_sex;
		public static float double_penetrative_sex;
		public static float breastjob;
		public static float handjob;
		public static float footjob;
		public static float fingering;
		public static float scissoring;
		public static float mutual_masturbation;
		public static float fisting;
		public static float sixtynine;

		// Log config
		// show messages for rjw patches
		public static bool DevMode;

		//Mod Settings handles
		private SettingHandle<bool> option_WildMode;
		private SettingHandle<bool> option_GenderlessAsFuta;
		private SettingHandle<int> option_sexneed_decay_rate;
		private SettingHandle<bool> option_nymphs_join;
		private SettingHandle<int> option_male_nymph_chance;
		private SettingHandle<int> option_futa_nymph_chance;
		private SettingHandle<int> option_futa_natives_chance;
		private SettingHandle<int> option_futa_spacers_chance;
		private SettingHandle<bool> option_STD_floor_catch;
		private SettingHandle<int> option_sex_minimum_age;
		private SettingHandle<int> option_sex_free_for_all_age;
		private SettingHandle<bool> option_submit_button_enabled;
		private SettingHandle<bool> option_bestiality_enabled;
		private SettingHandle<bool> option_animal_on_animal_enabled;
		private SettingHandle<bool> option_necrophilia_enabled;
		private SettingHandle<bool> option_show_RJW_designation_box;

		private SettingHandle<bool> option_rape_beating;
		private SettingHandle<bool> option_visitor_CP_rape;
		private SettingHandle<bool> option_animal_CP_rape;
		private SettingHandle<int> option_NonFutaWomenRaping_MaxVulnerability;
		private SettingHandle<int> option_Rapee_MinVulnerability_human;
		//private SettingHandle<int> option_Rapee_MinVulnerability_animals;

		private SettingHandle<int> option_pregnancy_weight_parent;
		private SettingHandle<int> option_pregnancy_weight_species;
		private SettingHandle<int> option_pregnancy_coefficient_human;
		private SettingHandle<int> option_pregnancy_coefficient_animals;
		private SettingHandle<bool> option_pregnancy_use_parent_method;

		private SettingHandle<bool> option_RJWH_pregnancy;
		private SettingHandle<bool> option_RJWB_pregnancy;
		private SettingHandle<bool> option_RJWI_pregnancy;
		private SettingHandle<bool> option_RJWM_pregnancy;
		private SettingHandle<bool> option_RJWA_pregnancy;
		//private SettingHandle<bool> option_CP_pregnancy;
		private SettingHandle<bool> option_genetic_trait_filter;

		//private SettingHandle<int> option_fertility_endAge_male;
		//private SettingHandle<int> option_fertility_endAge_female;

		//sex types
		private SettingHandle<int> option_vaginal_sex;
		private SettingHandle<int> option_anal_sex;
		private SettingHandle<int> option_fellatio_sex;
		private SettingHandle<int> option_cunnilingus_sex;
		private SettingHandle<int> option_rimming_sex;
		private SettingHandle<int> option_double_penetrative_sex;
		private SettingHandle<int> option_breastjob;
		private SettingHandle<int> option_handjob;
		private SettingHandle<int> option_footjob;
		private SettingHandle<int> option_fingering;
		private SettingHandle<int> option_scissoring;
		private SettingHandle<int> option_mutual_masturbation;
		private SettingHandle<int> option_fisting;
		private SettingHandle<int> option_sixtynine;

		private SettingHandle<bool> option_DevMode;

		public override void Initialize()
		{
			//--Log.Message("Initialize() called");
			base.Initialize();
		}

		private static SettingHandle<string> _tabsHandler;

		private readonly SettingHandle.ValueIsValid _positiveInt = value =>
		{
			int i;
			if (int.TryParse(value, out i)) return i >= 0;

			return false;
		};

		private readonly List<string> _tabNames = new List<string>
		{
			"RJWToggle".Translate(),
			"RJWProbability".Translate(),
			"RJWSex".Translate()
		};

		public override void DefsLoaded()
		{
			//--Log.Message("DefsLoaded() called");
			general_features();
			pregnancy_settings();
			sex_probability_tweaks();
			SettingsChanged();

			/*
			//option_WildMode.VisibilityPredicate = () => _tabsHandler.Value == _tabNames[0];
			_tabsHandler = Settings.GetHandle<String>("tabs", "RG_Tabs_Title".Translate(), "", "none");
			if (_tabsHandler.Value == _tabNames[0])
				general_features();
			if (_tabsHandler.Value == _tabNames[1])
				pregnancy_settings();
			if (_tabsHandler.Value == _tabNames[2])
				sex_probability_tweaks();

			//_tabsHandler.CustomDrawer = rect => Properties.Settings.CustomDrawer_Tabs(rect, _tabsHandler, _tabNames[0]);
			//_tabsHandler.CustomDrawer = rect => Properties.Settings.CustomDrawer_Tabs(rect, _tabsHandler, _tabNames[1]);
			//_tabsHandler.CustomDrawer = rect => Properties.Settings.CustomDrawer_Tabs(rect, _tabsHandler, _tabNames[2]);
		}

		public void general_features()
		{
			option_DevMode = Settings.GetHandle<bool>("DevMode", "DevMode_name".Translate(), ("DevMode" + "_desc").Translate(), false);
			option_WildMode = Settings.GetHandle<bool>("WildMode", "WildMode_name".Translate(), ("WildMode" + "_desc").Translate(), false);
			option_GenderlessAsFuta = Settings.GetHandle<bool>("GenderlessAsFuta", "GenderlessAsFuta_name".Translate(), ("GenderlessAsFuta" + "_desc").Translate(), false);
			// Do not lower minimum age. Already got an ultimatum about that. Next time likely means that the mod will be banned from LoversLab.
			option_sex_minimum_age = Settings.GetHandle<int>("sex_minimum_age", "SexMinimumAge".Translate(), ("SexMinimumAge" + "_desc").Translate(), 18, Validators.IntRangeValidator(18, 9999));
			option_sex_free_for_all_age = Settings.GetHandle<int>("sex_free_for_all_age", "SexFreeForAllAge".Translate(), ("SexFreeForAllAge" + "_desc").Translate(), 18, Validators.IntRangeValidator(18, 9999));
			option_sexneed_decay_rate = Settings.GetHandle<int>("sexneed_decay_rate", "sexneed_decay_rate_name".Translate(), ("sexneed_decay_rate" + "_desc").Translate(), 100, Validators.IntRangeValidator(0, 1000000));
			option_sexneed_decay_rate.SpinnerIncrement = 25;
			option_nymphs_join = Settings.GetHandle<bool>("nymphs_join", "NymphsJoin".Translate(), ("NymphsJoin" + "_desc").Translate(), true);
			option_male_nymph_chance = Settings.GetHandle<int>("male_nymph_chance", "male_nymph_chance".Translate(), ("male_nymph_chance" + "_desc").Translate(), 0, Validators.IntRangeValidator(0, 100));
			option_futa_nymph_chance = Settings.GetHandle<int>("futa_nymph_chance", "futa_nymph_chance".Translate(), ("futa_nymph_chance" + "_desc").Translate(), 0, Validators.IntRangeValidator(0, 100));
			option_futa_natives_chance = Settings.GetHandle<int>("futa_natives_chance", "futa_natives_chance".Translate(), ("futa_natives_chance" + "_desc").Translate(), 0, Validators.IntRangeValidator(0, 100));
			option_futa_spacers_chance = Settings.GetHandle<int>("futa_spacers_chance", "futa_spacers_chance".Translate(), ("futa_spacers_chance" + "_desc").Translate(), 5, Validators.IntRangeValidator(0, 100));
			option_STD_floor_catch = Settings.GetHandle<bool>("STD_floor_catch", "STD_FromFloors".Translate(), ("STD_FromFloors" + "_desc").Translate(), true);
			option_submit_button_enabled = Settings.GetHandle<bool>("submit_button_enabled", "submit_button_enabled".Translate(), ("submit_button_enabled" + "_desc").Translate(), defaultValue: true);
			option_bestiality_enabled = Settings.GetHandle<bool>("bestiality_enabled", "bestiality_enabled".Translate(), ("bestiality_enabled" + "_desc").Translate(), defaultValue: false);
			option_animal_on_animal_enabled = Settings.GetHandle<bool>("animal_on_animal_enabled", "animal_on_animal_enabled".Translate(), ("animal_on_animal_enabled" + "_desc").Translate(), defaultValue: false);
			option_necrophilia_enabled = Settings.GetHandle<bool>("necrophilia_enabled", "necrophilia_enabled".Translate(), ("necrophilia_enabled" + "_desc").Translate(), defaultValue: false);
			option_show_RJW_designation_box = Settings.GetHandle<bool>("RJW_designation_box", "RJW_designation_box".Translate(), ("RJW_designation_box" + "_desc").Translate(), defaultValue: true);

			option_rape_beating = Settings.GetHandle<bool>("rape_beating", "PrisonersBeating".Translate(), ("PrisonersBeating" + "_desc").Translate(), false);
			option_visitor_CP_rape = Settings.GetHandle<bool>("visitor_CP_rape", "VisitorsCanCP".Translate(), ("VisitorsCanCP" + "_desc").Translate(), false);
			option_animal_CP_rape = Settings.GetHandle<bool>("animal_CP_rape", "AnimalsCanCP".Translate(), ("AnimalsCanCP" + "_desc").Translate(), false);
			option_NonFutaWomenRaping_MaxVulnerability = Settings.GetHandle<int>("nonFutaWomenRaping_MaxVulnerability", "NonFutaWomenRaping_MaxVulnerability".Translate(), ("NonFutaWomenRaping_MaxVulnerability" + "_desc").Translate(), 20, Validators.IntRangeValidator(0, 300));
			option_Rapee_MinVulnerability_human = Settings.GetHandle<int>("rapee_MinVulnerability_human", "Rapee_MinVulnerability_human".Translate(), ("Rapee_MinVulnerability_human" + "_desc").Translate(), 50, Validators.IntRangeValidator(0, 300));
			//option_Rapee_MinVulnerability_animals = Settings.GetHandle<int>("rapee_MinVulnerability_animals", "Rapee_MinVulnerability_animals".Translate(), ("Rapee_MinVulnerability_animals" + "_desc").Translate(), 40, Validators.IntRangeValidator(0, 300));
		}

		public void pregnancy_settings()
		{
			option_RJWH_pregnancy = Settings.GetHandle<bool>("RJWH_pregnancy", "RJWH_pregnancy".Translate(), ("RJWH_pregnancy" + "_desc").Translate(), defaultValue: true);
			option_pregnancy_coefficient_human = Settings.GetHandle<int>("pregnancy_coefficient_human", "PregnantCoeffecientForHuman".Translate(), ("PregnantCoeffecientForHuman" + "_desc").Translate(), 20, Validators.IntRangeValidator(0, 300));
			//option_CP_pregnancy = Settings.GetHandle<bool>("CP_pregnancy", "CP_pregnancy".Translate(), ("CP_pregnancy" + "_desc").Translate(), defaultValue: false);
			option_genetic_trait_filter = Settings.GetHandle<bool>("genetic_trait_filter", "genetic_trait_filter".Translate(), ("genetic_trait_filter" + "_desc").Translate(), defaultValue: true);

			option_RJWB_pregnancy = Settings.GetHandle<bool>("RJWB_pregnancy", "RJWB_pregnancy".Translate(), ("RJWB_pregnancy" + "_desc").Translate(), defaultValue: true);
			option_pregnancy_coefficient_animals = Settings.GetHandle<int>("pregnancy_coefficient_animals", "PregnantCoeffecientForAnimals".Translate(), ("PregnantCoeffecientForAnimals" + "_desc").Translate(), 50, Validators.IntRangeValidator(0, 300));

			option_pregnancy_use_parent_method = Settings.GetHandle<bool>("pregnancy_use_parent_method", "UseParentMethod".Translate(), ("UseParentMethod" + "_desc").Translate(), true);
			option_pregnancy_weight_parent = Settings.GetHandle<int>("pregnancy_weight_parent", "OffspringLookLikeTheirMother".Translate(), ("OffspringLookLikeTheirMother" + "_desc").Translate(), 50, Validators.IntRangeValidator(0, 100));
			option_pregnancy_weight_species = Settings.GetHandle<int>("pregnancy_weight_species", "OffspringIsHuman".Translate(), ("OffspringIsHuman" + "_desc").Translate(), 50, Validators.IntRangeValidator(0, 100));

			option_RJWI_pregnancy = Settings.GetHandle<bool>("RJWI_pregnancy", "RJWI_pregnancy".Translate(), ("RJWI_pregnancy" + "_desc").Translate(), defaultValue: true);
			option_RJWM_pregnancy = Settings.GetHandle<bool>("RJWM_pregnancy", "RJWM_pregnancy".Translate(), ("RJWM_pregnancy" + "_desc").Translate(), defaultValue: true);
			option_RJWA_pregnancy = Settings.GetHandle<bool>("RJWA_pregnancy", "RJWA_pregnancy".Translate(), ("RJWA_pregnancy"+"_desc").Translate(), defaultValue: true);

			//option_fertility_endAge_male = Settings.GetHandle<int>("RJW_fertility_endAge_male", "RJW_fertility_endAge_male".Translate(), "RJW_fertility_endAge_male" + "_desc").Translate(), 100, Validators.IntRangeValidator(0, 100));
			//option_fertility_endAge_female = Settings.GetHandle<int>("RJW_fertility_endAge_female", "RJW_fertility_endAge_female".Translate(), "RJW_fertility_endAge_female" + "_desc").Translate(), 50, Validators.IntRangeValidator(0, 100));
		}

		public void sex_probability_tweaks()
		{
			option_vaginal_sex = Settings.GetHandle<int>("vaginal_sex", "vaginal_sex".Translate(), ("vaginal_sex" + "_desc").Translate(), 100, Validators.IntRangeValidator(1, 200));
			option_cunnilingus_sex = Settings.GetHandle<int>("cunnilingus_sex", "cunnilingus_sex".Translate(), ("cunnilingus_sex" + "_desc").Translate(), 80, Validators.IntRangeValidator(1, 200));
			option_anal_sex = Settings.GetHandle<int>("anal_sex", "anal_sex".Translate(), ("anal_sex" + "_desc").Translate(), 80, Validators.IntRangeValidator(1, 200));
			option_rimming_sex = Settings.GetHandle<int>("rimming_sex", "rimming_sex".Translate(), ("rimming_sex" + "_desc").Translate(), 50, Validators.IntRangeValidator(1, 200));
			option_fellatio_sex = Settings.GetHandle<int>("fellatio_sex", "fellatio_sex".Translate(), ("fellatio_sex" + "_desc").Translate(), 80, Validators.IntRangeValidator(1, 200));
			option_handjob = Settings.GetHandle<int>("handjob", "handjob".Translate(), ("handjob" + "_desc").Translate(), 60, Validators.IntRangeValidator(1, 200));
			option_mutual_masturbation = Settings.GetHandle<int>("mutual_masturbation", "mutual_masturbation".Translate(), ("mutual_masturbation" + "_desc").Translate(), 70, Validators.IntRangeValidator(1, 200));
			option_sixtynine = Settings.GetHandle<int>("sixtynine", "sixtynine".Translate(), ("sixtynine" + "_desc").Translate(), 60, Validators.IntRangeValidator(1, 200));
			option_double_penetrative_sex = Settings.GetHandle<int>("double_penetrative_sex", "double_penetrative_sex".Translate(), ("double_penetrative_sex" + "_desc").Translate(), 50, Validators.IntRangeValidator(1, 200));
			option_breastjob = Settings.GetHandle<int>("breastjob", "breastjob".Translate(), ("breastjob" + "_desc").Translate(), 50, Validators.IntRangeValidator(1, 200));
			option_fingering = Settings.GetHandle<int>("fingering", "fingering".Translate(), ("fingering" + "_desc").Translate(), 50, Validators.IntRangeValidator(1, 200));
			option_scissoring = Settings.GetHandle<int>("scissoring", "scissoring".Translate(), ("scissoring" + "_desc").Translate(), 50, Validators.IntRangeValidator(1, 200));
			option_footjob = Settings.GetHandle<int>("footjob", "footjob".Translate(), ("footjob" + "_desc").Translate(), 30, Validators.IntRangeValidator(1, 200));
			option_fisting = Settings.GetHandle<int>("fisting", "fisting".Translate(), ("fisting" + "_desc").Translate(), 30, Validators.IntRangeValidator(1, 200));
		}

		public override void SettingsChanged()
		{
			base.SettingsChanged();
			DevMode = option_DevMode.Value;
			WildMode = option_WildMode.Value;
			GenderlessAsFuta = option_GenderlessAsFuta.Value;
			sex_minimum_age = (uint)option_sex_minimum_age.Value;
			sex_free_for_all_age = (uint)option_sex_free_for_all_age.Value;
			sexneed_decay_rate = ((float)option_sexneed_decay_rate.Value) / 100f;
			nymphos = option_nymphs_join.Value;
			male_nymph_chance = (float)option_male_nymph_chance.Value / 100.0f;
			futa_nymph_chance = (float)option_futa_nymph_chance.Value / 100.0f;
			futa_natives_chance = (float)option_futa_natives_chance.Value / 100.0f;
			futa_spacers_chance = (float)option_futa_spacers_chance.Value / 100.0f;
			std_floor = option_STD_floor_catch.Value;
			bestiality_enabled = (bool)option_bestiality_enabled.Value;
			animal_on_animal_enabled = (bool)option_animal_on_animal_enabled.Value;
			necrophilia_enabled = (bool)option_necrophilia_enabled.Value;
			show_RJW_designation_box = (bool)option_show_RJW_designation_box.Value;

			prisoner_beating = option_rape_beating.Value;
			visitor_CP_rape = option_visitor_CP_rape.Value;
			animal_CP_rape = option_animal_CP_rape.Value;
			NonFutaWomenRaping_MaxVulnerability = ((float)option_NonFutaWomenRaping_MaxVulnerability.Value) / 100f;
			Rapee_MinVulnerability_human = ((float)option_Rapee_MinVulnerability_human.Value) / 100f;
			//Rapee_MinVulnerability_animals = ((float)option_Rapee_MinVulnerability_animals.Value) / 100f;
			submit_button_enabled = (bool)option_submit_button_enabled.Value;

			RJWH_pregnancy = (bool)option_RJWH_pregnancy.Value;
			pregnancy_weight_parent = (uint)option_pregnancy_weight_parent.Value;
			pregnancy_weight_species = (uint)option_pregnancy_weight_species.Value;
			RJWB_pregnancy = (bool)option_RJWB_pregnancy.Value;
			pregnancy_coefficient_human = (uint)option_pregnancy_coefficient_human.Value;
			pregnancy_coefficient_animals = (uint)option_pregnancy_coefficient_animals.Value;
			pregnancy_use_parent_method = option_pregnancy_use_parent_method.Value;
			RJWI_pregnancy = (bool)option_RJWI_pregnancy.Value;
			RJWA_pregnancy = (bool)option_RJWA_pregnancy.Value;

			//CP_pregnancy = (bool)option_CP_pregnancy.Value;
			genetic_trait_filter = (bool)option_genetic_trait_filter.Value;

			vaginal_sex = (float)option_vaginal_sex.Value / 100.0f;
			anal_sex = (float)option_anal_sex.Value / 100.0f;
			fellatio_sex = (float)option_fellatio_sex.Value / 100.0f;
			cunnilingus_sex = (float)option_cunnilingus_sex.Value / 100.0f;
			rimming_sex = (float)option_rimming_sex.Value / 100.0f;
			double_penetrative_sex = (float)option_double_penetrative_sex.Value / 100.0f;
			breastjob = (float)option_breastjob.Value / 100.0f;
			handjob = (float)option_handjob.Value / 100.0f;
			footjob = (float)option_footjob.Value / 100.0f;
			fingering = (float)option_fingering.Value / 100.0f;
			scissoring = (float)option_scissoring.Value / 100.0f;
			mutual_masturbation = (float)option_mutual_masturbation.Value / 100.0f;
			fisting = (float)option_fisting.Value / 100.0f;
			sixtynine = (float)option_sixtynine.Value / 100.0f;

			//fertility_endAge_male = ((float)option_fertility_endAge_male.Value) / 100f;
			//fertility_endAge_female = ((float)option_fertility_endAge_female.Value) / 100f;

			//--Log.Message("[RJW] Settings Changed:");
		}

		public override void MapLoaded(Map map)
		{
			//--Log.Message("[RJW] Settings loaded:");
			base.MapLoaded(map);
		}

		/*
		public override void Update() {
			base.Update();
		}

		public override void FixedUpdate() {
			base.FixedUpdate();
		}

		public override void MapComponentsInitializing(Map map) {
			//--Log.Message("MapComponentsInitializing() called");
			base.MapComponentsInitializing(map);
		}

		public override void MapDiscarded(Map map) {
			//--Log.Message("MapDiscarded() called");
			base.MapDiscarded(map);
		}

		public override void MapGenerated(Map map) {
			//--Log.Message("MapGenerated() called");
			base.MapGenerated(map);
		}

		public override void MapLoaded(Map map) {
			//--Log.Message("MapLoaded() called");
			base.MapLoaded(map);
		}

		public override void OnGUI() {
			base.OnGUI();
		}

		public override void SceneLoaded(Scene scene) {
			//--Log.Message("SceneLoaded() called");
			base.SceneLoaded(scene);
		}

		public override void Tick(int currentTick) {
			base.Tick(currentTick);
		}

		public override void WorldLoaded() {
			//--Log.Message("WorldLoaded() called");
			base.WorldLoaded();
		}

		private void MakeSettingsCategoryToggle(string labelId, Action buttonAction)
		{
			var toolToggle = Settings.GetHandle<bool>(labelId, labelId.Translate(), null);
			toolToggle.Unsaved = true;
			toolToggle.CustomDrawer = rect =>
			{
				if (Widgets.ButtonText(rect, "setting_showToggles_btn".Translate())) buttonAction();
				return false;
			};
		}
	}
}
*/


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

namespace rjw
{
	/// <summary>
	/// Utility rjw data object for storing Parts(genitals, breasts, anuses) data between operations
	/// </summary>
	public class PartsData : IExposable
	{
		public Pawn Pawn = null; // store original owner , maybe better kinddef?
		public Thing Thing = null; // store world thing?
		public float Severity = 0.0f; // store size

		public PartsData() { }

		public PartsData(Thing thing, Pawn pawn = null, float severity = 0.5f)
		{
			//Log.Message("Creating PartsData for " + thing);
			Pawn = pawn;
			Thing = thing;
			Severity = severity;
			//Log.Message("This data is valid " + this.IsValid);
		}

		public void ExposeData()
		{
			Scribe_Values.Look<float>(ref Severity, "severity", 0.5f, true);
			Scribe_References.Look<Pawn>(ref this.Pawn, "Pawn");
			Scribe_References.Look<Thing>(ref this.Thing, "Thing");
		}

		public bool IsValid { get { return Thing != null; } }
	}
}


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

namespace rjw
{
	public class SaveStorage : ModBase
	{
		public override string ModIdentifier => "RJW";

		public override Version GetVersion()
		{
			//--Log.Message("GetVersion() called");
			return base.GetVersion();
		}

		public static DataStore DataStore;//reference to savegame data, hopefully
		public override void WorldLoaded()
		{
			DataStore = UtilityWorldObjectManager.GetUtilityWorldObject<DataStore>();
		}
		protected override bool HarmonyAutoPatch { get => false; }//first.cs creates harmony and does some convoulted stuff with it
	}

	/// <summary>
	/// Utility rjw data object and a collection of extension methods for Pawn
	/// </summary>
	public class PawnData : IExposable
	{
		//Should probably mix but not shake it with RJW designation classes
		public bool Comfort = false;
		public bool Service = false;
		public bool Breeding = false;
		public bool Milking = false;
		public bool Hero = false;
		public string HeroOwner = "";
		public bool BreedingAnimal = false;
		public Pawn Pawn = null;

		public PawnData() { }

		public PawnData(Pawn pawn)
		{
			//Log.Message("Creating pawndata for " + pawn);
			Pawn = pawn;
			//Log.Message("This data is valid " + this.IsValid);
		}

		public void ExposeData()
		{
			Scribe_Values.Look<bool>(ref Comfort, "Comfort", false, true);
			Scribe_Values.Look<bool>(ref Service, "Service", false, true);
			Scribe_Values.Look<bool>(ref Breeding, "Breeding", false, true);
			Scribe_Values.Look<bool>(ref Milking, "Milking", false, true);
			Scribe_Values.Look<bool>(ref Hero, "Hero", false, true);
			Scribe_Values.Look<String>(ref HeroOwner, "HeroOwner", "", true);
			Scribe_Values.Look<bool>(ref BreedingAnimal, "BreedingAnimal", false, true);
			Scribe_References.Look<Pawn>(ref this.Pawn, "Pawn");
		}

		public bool IsValid { get { return Pawn != null; } }
	}
	public static class PawnDesignations
	{
		public static bool CanChangeDesignationColonist(this Pawn pawn)
		{
			//check if pawn is a hero of other player
			//limit widget access in mp

			//Log.Warning("CanChangeDesignationColonist:: IsHeroOwner" + pawn.Name + " IsDesignatedHero" + pawn.IsDesignatedHero() + " IsHeroOwner" + pawn.IsHeroOwner());
			if ((pawn.IsDesignatedHero() && !pawn.IsHeroOwner()))
				return false;

			return true;
		}
		public static bool CanChangeDesignationPrisoner(this Pawn pawn)
		{
			//check if player hero slave/prisoner
			//limit widget access in mp

			foreach (Pawn item in Find.AnyPlayerHomeMap.mapPawns.AllPawnsSpawned.ToList().Where(x => x.IsDesignatedHero()))
			//foreach (Pawn item in AllDesignationsOn(pawn.Map).Where(data => (data.Hero)).Select(data => data.Pawn))
			{
				//Log.Warning(item.IsHeroOwner() + " IsHeroOwner" + item.Name );
				if (item.IsHeroOwner())
				{
					if (item.IsPrisonerOfColony || xxx.is_slave(item))
					{
						//Log.Warning("Hero of "+MP.PlayerName+" is prisoner");
						return false;
					}
				}
			}

			return true;
		}
		public static bool CanDesignateComfort(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return false;

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

			//cant sex
			if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn)))
				return false;

			if (!pawn.IsDesignatedHero())
			{
				if (xxx.is_masochist(pawn) && pawn.IsColonist)
					return true;
			}
			else if (pawn.IsHeroOwner())
				return true;

			if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn))
				return true;

			return false;
		}
		public static bool CanDesignateService(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return false;

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

			//cant sex
			if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn)))
				return false;

			if (!pawn.IsDesignatedHero())
			{
				if (pawn.IsColonist)
					return true;
			}
			else if (pawn.IsHeroOwner())
				return true;

			if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn))
				return true;

			return false;
		}
		public static bool CanDesignateBreeding(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return false;

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

			//cant sex
			if (!xxx.can_be_fucked(pawn))
				return false;

			if (RJWSettings.bestiality_enabled && xxx.is_human(pawn))
			{
				if (!pawn.IsDesignatedHero())
				{
					if (xxx.is_zoophile(pawn) && pawn.IsColonist)
						return true;
				}
				else if (pawn.IsHeroOwner())
					return true;

				if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn))
					return true;
			}

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

			return false;
		}
		public static bool CanDesignateBreedAnimal(this Pawn pawn)
		{
			//no permission to change designation for NON prisoner hero/ other player
			if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist())
				return false;

			//no permission to change designation for prisoner hero/ self
			if (!pawn.CanChangeDesignationPrisoner())
				return 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 true;

			return false;

		}
		public static bool CanDesignateMilking(this Pawn pawn) { return false; }//todo
		public static bool CanDesignateHero(this Pawn pawn)
		{
			if ((RJWSettings.RPG_hero_control)
				&& xxx.is_human(pawn)
				&& pawn.IsColonist
				&& pawn.Map.IsPlayerHome)
			{
				if (!pawn.IsDesignatedHero())
				{
					//TODO replace this with own tracking list, maybe
					List<Pawn> pwnlist = Find.ColonistBar.GetColonistsInOrder();//colonists
					pwnlist.AddRange(pawn.Faction.kidnapped.KidnappedPawnsListForReading.Distinct());//kidnapped
					pwnlist.AddRange(Find.AnyPlayerHomeMap.mapPawns.AllPawnsSpawned.ToList().Distinct());//prisoners
					//foreach (Pawn item in Find.ColonistBar.GetColonistsInOrder())
					//foreach (Pawn item in Find.AnyPlayerHomeMap.mapPawns.AllPawnsSpawned.ToList())
					foreach (Pawn item in pwnlist)
					{
						if (item.IsDesignatedHero())
						{
							if (item.IsHeroOwner())
							{
								//Log.Warning("CanDesignateHero:: "  + MP.PlayerName + " already has hero - " + item.Name);
								return false;
							}
							else
								continue;
						}
					}
					return true;
				}
			}
			return false;
		}

		public static void ToggleComfort(this Pawn pawn)
		{
			if (pawn.CanDesignateComfort())
			{
				if (!pawn.IsDesignatedComfort())
					DesignateComfort(pawn);
				else
					UnDesignateComfort(pawn);
			}
		}
		public static bool IsDesignatedComfort(this Pawn pawn)
		{
			if (SaveStorage.DataStore.GetPawnData(pawn).Comfort == true)
				if (!pawn.IsDesignatedHero())
					if (!(xxx.is_masochist(pawn) || pawn.IsPrisonerOfColony || xxx.is_slave(pawn)))
						UnDesignateComfort(pawn);

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

		public static void ToggleService(this Pawn pawn)
		{
			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);

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

		public static void ToggleBreeding(this Pawn pawn)
		{
			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 (!pawn.IsDesignatedHero())
						if (!(xxx.is_zoophile(pawn) || pawn.IsPrisonerOfColony || xxx.is_slave(pawn)))
							UnDesignateBreeding(pawn);
				}
				else
				{
					if (!pawn.Faction.IsPlayer)
						UnDesignateBreeding(pawn);
				}

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

		public static void ToggleBreedingAnimal(this Pawn pawn)
		{
			if (pawn.CanDesignateBreeding())
			{
				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)
					UnDesignateBreedingAnimal(pawn);

			return SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal;
		}
		[SyncMethod]
		public static void DesignateBreedingAnimal(this Pawn pawn)
		{
			SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = true;
		}
		[SyncMethod]
		public static void UnDesignateBreedingAnimal(this Pawn pawn)
		{
			SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = 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);

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

		public static void ToggleHero(this Pawn pawn)
		{
			if (pawn.CanDesignateHero())
			{
				if (!pawn.IsDesignatedHero())
					DesignateHero(pawn);
				else
					UnDesignateHero(pawn);
			}
		}
		public static void DesignateHero(this Pawn pawn)
		{
			MyMethod(pawn, MP.PlayerName);
		}
		public static bool IsDesignatedHero(this Pawn pawn)
		{
			return SaveStorage.DataStore.GetPawnData(pawn).Hero;
		}
		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;
			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);
		}
		[SyncMethod]
		public static void UnDesignateHero(this Pawn pawn)
		{
		}

		private static IEnumerable<PawnData> AllDesignationsOn(Map map)
		{
			return SaveStorage.DataStore.PawnData
				.Where(ent => (ent.Value != null && ent.Value.IsValid && map == ent.Value.Pawn.Map))
				.Select(ent => ent.Value)
				.InRandomOrder();
		}
		public static IEnumerable<Pawn> AllComfortDesignations(this Map map)
		{
			return AllDesignationsOn(map)
				.Where(data => (data.Comfort))
				.Select(data => data.Pawn);
		}
		public static IEnumerable<Pawn> AllBreedDesignations(this Map map)
		{
			return AllDesignationsOn(map)
				.Where(data => (data.Breeding))
				.Select(data => data.Pawn);
		}

		public static IEnumerable<Pawn> AllBreedAnimalDesignations(this Map map)
		{
			return AllDesignationsOn(map)
				.Where(data => (data.BreedingAnimal))
				.Select(data => data.Pawn);
		}
		//}
		//public static class PawnDesignations
		//{
		//	public enum Types
		//		{
		//			Comfort,
		//			Service,
		//			Milking,
		//			Breeding
		//		}
		//	public static Dictionary<Types, Func<Pawn, bool>> Checks = new Dictionary<Types, Func<Pawn, bool>>()
		//	{
		//		{ Types.Comfort, CanDesignateComfort}
		//	};
	}
}


code:
using Verse;

namespace rjw
{
	/* TO BE FINISHED
	public enum RandomDialogueJobType
	{
		Rape = 0,
		Love = 1,
		Other = 2
	}

	public sealed class RandomDialoguesDef : Def
	{
		public RandomDialogueJobType JobType;
		public string RD0;
		public string RD1;
		public string RD2;
		public string RD3;
		public string RD4;
		public string RD5;
		public string RD6;
		public string RD7;
		public string RD8;
		public string RD9;
		public string RD10;
		public string RD11;
		public string RD12;
		public string RD13;
		public string RD14;
		public string RD15;
		public string RD16;
		public string RD17;
		public string RD18;
		public string RD19;
	}

	[DefOf]
	public static class RandomDialoguesDefOf
	{
		//0 means before, 1 means during, 2 means after
		//public readonly static RandomDialoguesDef rape0;
		//public readonly static RandomDialoguesDef rape1;
		//public readonly static RandomDialoguesDef rape2;

		//public readonly static RandomDialoguesDef love0;
		//public readonly static RandomDialoguesDef love1;
		//public readonly static RandomDialoguesDef love2;

		//public readonly static RandomDialoguesDef other0;
		//public readonly static RandomDialoguesDef other1;
		//public readonly static RandomDialoguesDef other2;
	}
	*/

	// TO BE FINISHED
	/*
	public static class RandomDialogues
	{
		public static void processBeforeDialogue(Pawn psubject,Pawn pobject,int Type = 4)
		{
			switch (Type)
			{
				case 0:
					string traitDefName;
					if (xxx.has_traits(psubject)&&Rand.Value<0.25){
						traitDefName = psubject.random_pick_a_trait();
						switch (traitDefName)
						{
							case "Nymphomaniac":
								break;

							case "Rapist":
								break;

							case "Necrophiliac":
								break;

							case "Zoophile":
								break;

							case "Bloodlust":
								break;

							case "Psychopath":
								break;

							case "Cannibal":
								break;

							case "Masochist":
								break;

							case "Prosthophile":
								break;

							case "Prosthophobe":
								break;

							case "Jealous":
								break;

							case "Gay":
								break;

							default:
								break;
						}
					}
					if (xxx.has_traits(pobject))
					{
					}
					return;

				case 1:
					return;

				case 2:
					return;

				default:
					Log.Error("[RJW]RandomDialogues::processBeforeDialogue - Type not found");
					return;
			}
		}

		public static void processDuringDialogue(Pawn psubject, Pawn pobject, int Type = 4)
		{
			switch (Type)
			{
				case 0:
					return;

				case 1:
					return;

				case 2:
					return;

				default:
					Log.Error("[RJW]RandomDialogues::processBeforeDialogue - Type not found");
					return;
			}
		}

		public static void processAfterDialogue(Pawn psubject, Pawn pobject, int Type = 4)
		{
			switch (Type)
			{
				case 0:
					return;

				case 1:
					return;

				case 2:
					return;

				default:
					Log.Error("[RJW]RandomDialogues::processBeforeDialogue - Type not found");
					return;
			}
		}
	}
	*/
}