code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
  <Operation Class="PatchOperationAdd">
    <xpath>Defs/RulePackDef[defName = "GlobalUtility"]/include</xpath>
    <value>

TalkTopicsSex

    </value>
  </Operation>

  <Operation Class="PatchOperationAdd">
    <xpath>Defs/InteractionDef[defName = "DeepTalk"]/logRulesInitiator/rulesStrings</xpath>
    <value>

subject(p=0.24)->[TalkTopicSex]

    </value>
  </Operation>

  <Operation Class="PatchOperationAdd">
    <xpath>Defs/InteractionDef[defName = "Chitchat"]/logRulesInitiator/rulesStrings</xpath>
    <value>

r_logentry(p=0.12)->[INITIATOR_nameDef] and [RECIPIENT_nameDef] [talkedabout] [TalkTopicSex].

r_logentry(p=0.12)->[INITIATOR_nameDef] [talkedabout] [TalkTopicSex] with [RECIPIENT_nameDef].

r_logentry(p=0.24)->[INITIATOR_nameDef] [commentedabout] [TalkTopicSex] to [RECIPIENT_nameDef].

    </value>
  </Operation>
</Patch>


code:
<Patch>
	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/ThoughtDef[defName="HarmedMe"]/nullifyingTraits</xpath>
				<value>

Masochist

				</value>

		</operations>
	</Operation>
</Patch>

repo_name: Timura/rjw

license: mit


code:
<Patch>
	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/ThoughtDef[defName="ObservedLayingCorpse"]/nullifyingTraits</xpath>
				<value>

Necrophiliac

				</value>

				<xpath>Defs/ThoughtDef[defName="ObservedLayingRottingCorpse"]/nullifyingTraits</xpath>
				<value>

Necrophiliac

				</value>

		</operations>
	</Operation>
</Patch>


code:
root=true

[*.{cs,xml}]
indent_style = tab


code:
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RimJobWorld")]
[assembly: AssemblyDescription("Adult mod for Rimworld")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Community Project")]
[assembly: AssemblyProduct("RimJobWorld")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c2825019-7f0b-456d-85a3-479c1a2a8805")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
[assembly: AssemblyVersion("1.0.0.0")]


code:
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Lib.Harmony" version="2.1.0" targetFramework="net472" />
  <package id="RimWorld.MultiplayerAPI" version="0.2.0" targetFramework="net472" />
  <package id="UnlimitedHugs.Rimworld.HugsLib" version="9.0.0" targetFramework="net472" />
</packages>


code:
/*
Core versions of scripts addapted for Greater Good
*/

using System;
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using RimWorld.Planet;
using Verse;
using rjw;

namespace rjw_CORE_EXPOSED
{
	// used in Vulnerability StatDef calculation
	public class SkillNeed_BaseBonus : SkillNeed
	{
		private float baseValue = 0.5f;

		private float bonusPerLevel = 0.05f;

		public override float ValueFor(Pawn pawn)
		{
			if (pawn.skills == null)
			{
				return 1f;
			}
			int level = pawn.skills.GetSkill(this.skill).Level;
			// remove melee bonus for pawns: downed, sleeping/resting/lying, wearing armbinder
			if (pawn.Downed || pawn.GetPosture() != PawnPosture.Standing || pawn.health.hediffSet.HasHediff(DefDatabase<HediffDef>.GetNamedSilentFail("Armbinder")))
				//|| pawn.health.hediffSet.HasHediff(HediffDef.Named("Yoke")) || pawn.health.hediffSet.HasHediff(HediffDef.Named("BoundHands")))
				level = 0;
			return this.ValueAtLevel(level);
		}

		private float ValueAtLevel(int level)
		{
			return this.baseValue + this.bonusPerLevel * (float)level;
		}

		public override IEnumerable<string> ConfigErrors()
		{
			foreach (string error in base.ConfigErrors())
			{
				yield return error;
			}
			for (int i = 1; i <= 20; i++)
			{
				float factor = this.ValueAtLevel(i);
				if (factor <= 0f)
				{
					yield return "SkillNeed yields factor < 0 at skill level " + i;
				}
			}
		}
	}

	public static class LovePartnerRelationUtility
	{
		public static float LovinMtbSinglePawnFactor(Pawn pawn)
		{
			float num = 1f;
			num /= 1f - pawn.health.hediffSet.PainTotal;
			float efficiency = pawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness);
			if (efficiency < 0.5f)
			{
				num /= efficiency * 2f;
			}

			if (!pawn.RaceProps.Humanlike)
			{
				return num * 4f;
			}
			if (RimWorld.LovePartnerRelationUtility.ExistingLovePartner(pawn) != null)
			{
				num *= 2f; //This is a factor which makes pawns with love partners less likely to do fappin/random raping/rapingCP/bestiality/necro.
			}
			else if (pawn.gender == Gender.Male)
			{
				num /= 1.25f; //This accounts for single men
			}
			return num / GenMath.FlatHill(0.0001f, 8f, 13f, 28f, 50f, 0.15f, pawn.ageTracker.AgeBiologicalYearsFloat);//this needs to be changed
		}
	}

	public static class MedicalRecipesUtility
	{
		public static bool IsCleanAndDroppable(Pawn pawn, BodyPartRecord part)
		{
			return IsClean(pawn, part) && part.def.spawnThingOnRemoved != null;
		}
		//TODO: add check if hediff are bad?
		public static bool IsClean(Pawn pawn, BodyPartRecord part)
		{
			//in vanilla Hediff = always bad?
			return !pawn.Dead && !(from x in pawn.health.hediffSet.hediffs
									where (x.Part == part)
									select x).Any<Hediff>();
		}

		public static bool IsViolationOnPawn(Pawn pawn, BodyPartRecord part, Faction billDoerFaction)
		{
			return pawn.Faction != billDoerFaction || HealthUtility.PartRemovalIntent(pawn, part) == BodyPartRemovalIntent.Harvest;
		}

		public static void RestorePartAndSpawnAllPreviousParts(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			SpawnNaturalPartIfClean(pawn, part, pos, map);
			SpawnThingsFromHediffs(pawn, part, pos, map);
			pawn.health.RestorePart(part, null, true);
		}

		// always false since rjw uses hediffs for genitals, thus its always dirty
		public static Thing SpawnNaturalPartIfClean(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			if (MedicalRecipesUtility.IsCleanAndDroppable(pawn, part))
			{
				//normal/rimworld parts
				return GenSpawn.Spawn(part.def.spawnThingOnRemoved, pos, map);
			}
			return null;
		}

		/// <summary>
		/// spawn rjw parts after operation
		/// </summary>
		/// <param name="pawn"></param>
		/// <param name="part"></param>
		/// <param name="pos"></param>
		/// <param name="map"></param>
		public static void SpawnThingsFromHediffs(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			if (!pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Contains(part))
			{
				return;
			}
			if (pawn.Dead)
			{
				return;
			}
			IEnumerable<Hediff> enumerable = from x in pawn.health.hediffSet.hediffs
											 where x.Part == part
											 select x;
			//RJW parts and other implants?
			foreach (Hediff current in enumerable)
			{
				if (current.def.spawnThingOnRemoved != null)
				{
					//Thing thing = GenSpawn.Spawn(current.def.spawnThingOnRemoved, pos, map);

					//spawn thing
					GenSpawn.Spawn(SexPartAdder.recipePartRemover(current), pos, map);
				}
			}
			//spawn sub parts? not sure why would it call itself but w/e
			for (int i = 0; i < part.parts.Count; i++)
			{
				MedicalRecipesUtility.SpawnThingsFromHediffs(pawn, part.parts[i], pos, map);
			}
		}
	}

	public class Recipe_RemoveBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				IEnumerable<BodyPartRecord> parts = pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined);
				foreach (BodyPartRecord part in parts)
				{
					if (pawn.health.hediffSet.HasDirectlyAddedPartFor(part))
					{
						yield return part;
					}
					if (MedicalRecipesUtility.IsCleanAndDroppable(pawn, part))
					{
						yield return part;
					}
					if (part != pawn.RaceProps.body.corePart && part.def.canSuggestAmputation && pawn.health.hediffSet.hediffs.Any((Hediff d) => !(d is Hediff_Injury) && d.def.isBad && d.Visible && d.Part == part))
					{
						yield return part;
					}
				}
			}
		}

		private const int ViolationGoodwillImpact = -15;

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			bool flag = MedicalRecipesUtility.IsClean(pawn, part);
			bool flag2 = MedicalRecipesUtility.IsViolationOnPawn(pawn, part, Faction.OfPlayer);
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				MedicalRecipesUtility.SpawnNaturalPartIfClean(pawn, part, billDoer.Position, billDoer.Map);
				MedicalRecipesUtility.SpawnThingsFromHediffs(pawn, part, billDoer.Position, billDoer.Map);
			}
			DamageDef surgicalCut = DamageDefOf.SurgicalCut;
			float amount = 99999f;
			float armorPenetration = 999f;
			pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
			if (flag)
			{
				if (pawn.Dead)
				{
					ThoughtUtility.GiveThoughtsForPawnExecuted(pawn, billDoer, PawnExecutionKind.OrganHarvesting);
				}
				ThoughtUtility.GiveThoughtsForPawnOrganHarvested(pawn, billDoer);
			}
			if (flag2 && pawn.Faction != null && billDoer != null && billDoer.Faction != null)
			{
				Faction faction = pawn.Faction;
				Faction faction2 = billDoer.Faction;
				HistoryEventDef reason = DefDatabase<HistoryEventDef>.GetNamedSilentFail("GoodwillChangedReason_RemovedBodyPart");
				//string reason = "GoodwillChangedReason_RemovedBodyPart".Translate(part.LabelShort);
				GlobalTargetInfo? lookTarget = pawn;
				faction.TryAffectGoodwillWith(faction2, ViolationGoodwillImpact, true, true, reason, lookTarget);
			}
		}

		public override string GetLabelWhenUsedOn(Pawn pawn, BodyPartRecord part)
		{
			if (pawn.RaceProps.IsMechanoid || pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(part))
			{
				return RecipeDefOf.RemoveBodyPart.LabelCap;
			}
			BodyPartRemovalIntent bodyPartRemovalIntent = HealthUtility.PartRemovalIntent(pawn, part);
			if (bodyPartRemovalIntent == BodyPartRemovalIntent.Harvest)
			{
				return "Harvest".Translate();
			}
			if (bodyPartRemovalIntent != BodyPartRemovalIntent.Amputate)
			{
				throw new InvalidOperationException();
			}
			if (part.depth == BodyPartDepth.Inside)
			{
				return "RemoveOrgan".Translate();
			}
			return "Amputate".Translate();
		}
	}

	public class Recipe_InstallOrReplaceBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				//ModLog.Message("Recipe_InstallOrReplaceBodyPart Recipe: " + recipe.defName);

				// For all parts listed in the recipe
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					// Grab the recipe part
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];

					// For all parts on the pawn
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						// Grab the pawn part
						BodyPartRecord record = bpList[j];

						// If the recipe part and pawn part match
						if (record.def == part)
						{
							// Grab all pawn hediffs for natural and artificial parts that are on the current pawn body part
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record && (x is Hediff_PartBaseNatural || x is Hediff_PartBaseArtifical)
														select x;

							//ModLog.Message("Recipe_InstallOrReplaceBodyPart GetPartsToApplyOn: Pawn=" + pawn.Name + " Part=" + record.Label + ", diffs.Count=" + diffs.Count<Hediff>() + ", First Diff=" + diffs.First<Hediff>().def.defName + " recipe.addsHediff=" + recipe.addsHediff.defName);

							// If the pawn doesn't have exactly 1 diff for that part OR the first diff found is not the one being added by the recipe
							//if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								//ModLog.Message("Diff Matched.  Recipe parent=" + record.parent?.Label);

								// If this is the base body OR the pawn has the parent body part of the recipe part
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									//ModLog.Message("Parent Found.  PartOrAnyAncestorHasDirectlyAddedParts=" + pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) + ", HasDirectlyAddedPartFor=" + pawn.health.hediffSet.HasDirectlyAddedPartFor(record));

									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										//ModLog.Message("Recipe: " + recipe.defName + "Applies to: " + record.Label + " of " + pawn.Name);
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					DamageDef surgicalCut = DamageDefOf.SurgicalCut;
					float amount = 99999f;
					float armorPenetration = 999f;
					pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				MedicalRecipesUtility.RestorePartAndSpawnAllPreviousParts(pawn, part, billDoer.Position, billDoer.Map);
			}
			//pawn.health.AddHediff(recipe.addsHediff, part, null, null);

			pawn.health.AddHediff(SexPartAdder.recipePartAdder(recipe, pawn, part, ingredients), part, null, null);
		}
	}

	public class Recipe_AddBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						BodyPartRecord record = bpList[j];
						if (record.def == part)
						{
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record && (x is Hediff_PartBaseNatural || x is Hediff_PartBaseArtifical)
														select x;

							// If the pawn doesn't have exactly 1 diff for that part OR the first diff found is not the one being added by the recipe
							//if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					DamageDef surgicalCut = DamageDefOf.SurgicalCut;
					float amount = 99999f;
					float armorPenetration = 999f;
					pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				//pawn.health.AddHediff(recipe.addsHediff, part, null, null);

				pawn.health.AddHediff(SexPartAdder.recipePartAdder(recipe, pawn, part, ingredients), part, null, null);
			}
		}
	}
	public class Recipe_RemovePart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						BodyPartRecord record = bpList[j];
						if (record.def == part)
						{
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record && (x is Hediff_PartBaseNatural || x is Hediff_PartBaseArtifical)
														select x;

							// If the pawn doesn't have exactly 1 diff for that part OR the first diff found is not the one being added by the recipe
							//if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					DamageDef surgicalCut = DamageDefOf.SurgicalCut;
					float amount = 99999f;
					float armorPenetration = 999f;
					pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				//pawn.health.AddHediff(recipe.addsHediff, part, null, null);

				pawn.health.AddHediff(SexPartAdder.recipePartAdder(recipe, pawn, part, ingredients), part, null, null);
			}
		}
	}
}


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

using System;
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using RimWorld.Planet;
using Verse;

namespace rjw_CORE_EXPOSED
{
	[StaticConstructorOnStartup]
	public static class rjwHealthCardUtility
	{
		public static Vector2 scrollPosition = Vector2.zero;

		public static float scrollViewHeight = 0f;

		public static bool highlight = true;

		public static bool onOperationTab = false;

		public static Vector2 billsScrollPosition = Vector2.zero;

		public static float billsScrollHeight = 1000f;

		public static bool showAllHediffs = false;

		public static bool showHediffsDebugInfo = false;

		public const float TopPadding = 20f;

		public const float ThoughtLevelHeight = 25f;

		public const float ThoughtLevelSpacing = 4f;

		public const float IconSize = 20f;

		public static readonly Color HighlightColor = new Color(0.5f, 0.5f, 0.5f, 1f);

		public static readonly Color StaticHighlightColor = new Color(0.75f, 0.75f, 0.85f, 1f);

		public static readonly Color VeryPoorColor = new Color(0.4f, 0.4f, 0.4f);

		public static readonly Color PoorColor = new Color(0.55f, 0.55f, 0.55f);

		public static readonly Color WeakenedColor = new Color(0.7f, 0.7f, 0.7f);

		public static readonly Color EnhancedColor = new Color(0.5f, 0.5f, 0.9f);

		public static readonly Color MediumPainColor = new Color(0.9f, 0.9f, 0f);

		public static readonly Color SeverePainColor = new Color(0.9f, 0.5f, 0f);

		public static readonly Texture2D BleedingIcon = ContentFinder<Texture2D>.Get("UI/Icons/Medical/Bleeding", true);

		public static List<ThingDef> tmpMedicineBestToWorst = new List<ThingDef>();

		public static void DrawPawnHealthCard(Rect outRect, Pawn pawn, bool allowOperations, bool showBloodLoss, Thing thingForMedBills)
		{
			if (pawn.Dead && allowOperations)
			{
				Log.Error("Called DrawPawnHealthCard with a dead pawn and allowOperations=true. Operations are disallowed on corpses.", false);
				allowOperations = false;
			}
			outRect = outRect.Rounded();
			Rect rect = new Rect(outRect.x, outRect.y, outRect.width * 0.375f, outRect.height).Rounded();
			Rect rect2 = new Rect(rect.xMax, outRect.y, outRect.width - rect.width, outRect.height);
			rect.yMin += 11f;
			rjwHealthCardUtility.DrawHealthSummary(rect, pawn, allowOperations, thingForMedBills);
			rjwHealthCardUtility.DrawHediffListing(rect2.ContractedBy(10f), pawn, showBloodLoss);
		}

		public static void DrawHealthSummary(Rect rect, Pawn pawn, bool allowOperations, Thing thingForMedBills)
		{
			GUI.color = Color.white;
			if (!allowOperations)
			{
				rjwHealthCardUtility.onOperationTab = false;
			}
			Widgets.DrawMenuSection(rect);
			List<TabRecord> list = new List<TabRecord>();
			list.Add(new TabRecord("HealthOverview".Translate(), delegate
			{
				rjwHealthCardUtility.onOperationTab = false;
			}, !rjwHealthCardUtility.onOperationTab));
			if (allowOperations)
			{
				string label = (!pawn.RaceProps.IsMechanoid) ? "MedicalOperationsShort".Translate(pawn.BillStack.Count) : "MedicalOperationsMechanoidsShort".Translate(pawn.BillStack.Count);
				list.Add(new TabRecord(label, delegate
				{
					rjwHealthCardUtility.onOperationTab = true;
				}, rjwHealthCardUtility.onOperationTab));
			}
			TabDrawer.DrawTabs(rect, list, 200f);
			rect = rect.ContractedBy(9f);
			GUI.BeginGroup(rect);
			float curY = 0f;
			Text.Font = GameFont.Medium;
			GUI.color = Color.white;
			Text.Anchor = TextAnchor.UpperCenter;
			if (rjwHealthCardUtility.onOperationTab)
			{
				PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.MedicalOperations, KnowledgeAmount.FrameDisplayed);
				curY = rjwHealthCardUtility.DrawMedOperationsTab(rect, pawn, thingForMedBills, curY);
			}
			else
			{
				curY = rjwHealthCardUtility.DrawOverviewTab(rect, pawn, curY);
			}
			Text.Font = GameFont.Small;
			GUI.color = Color.white;
			Text.Anchor = TextAnchor.UpperLeft;
			GUI.EndGroup();
		}

		public static void DrawHediffListing(Rect rect, Pawn pawn, bool showBloodLoss)
		{
			GUI.color = Color.white;
			if (Prefs.DevMode && Current.ProgramState == ProgramState.Playing)
			{
				rjwHealthCardUtility.DoDebugOptions(rect, pawn);
			}
			GUI.BeginGroup(rect);
			float lineHeight = Text.LineHeight;
			Rect outRect = new Rect(0f, 0f, rect.width, rect.height - lineHeight);
			Rect viewRect = new Rect(0f, 0f, rect.width - 16f, rjwHealthCardUtility.scrollViewHeight);
			Rect rect2 = rect;
			if (viewRect.height > outRect.height)
			{
				rect2.width -= 16f;
			}
			Widgets.BeginScrollView(outRect, ref rjwHealthCardUtility.scrollPosition, viewRect, true);
			GUI.color = Color.white;
			float num = 0f;
			rjwHealthCardUtility.highlight = true;
			bool flag = false;
			foreach (IGrouping<BodyPartRecord, Hediff> current in rjwHealthCardUtility.VisibleHediffGroupsInOrder(pawn, showBloodLoss))
			{
				flag = true;
				rjwHealthCardUtility.DrawHediffRow(rect2, pawn, current, ref num);
			}
			if (!flag)
			{
				Widgets.NoneLabelCenteredVertically(new Rect(0f, 0f, viewRect.width, outRect.height), "(" + "NoHealthConditions".Translate() + ")");
				num = outRect.height - 1f;
			}
			if (Event.current.type == EventType.Layout)
			{
				rjwHealthCardUtility.scrollViewHeight = num;
			}
			Widgets.EndScrollView();
			float bleedRateTotal = pawn.health.hediffSet.BleedRateTotal;
			if (bleedRateTotal > 0.01f)
			{
				Rect rect3 = new Rect(0f, rect.height - lineHeight, rect.width, lineHeight);
				string text = string.Concat(new string[]
				{
					"BleedingRate".Translate(),
					": ",
					bleedRateTotal.ToStringPercent(),
					"/",
					"LetterDay".Translate()
				});
				int num2 = HealthUtility.TicksUntilDeathDueToBloodLoss(pawn);
				if (num2 < 60000)
				{
					text = text + " (" + "TimeToDeath".Translate(num2.ToStringTicksToPeriod()) + ")";
				}
				else
				{
					text = text + " (" + "WontBleedOutSoon".Translate() + ")";
				}
				Widgets.Label(rect3, text);
			}
			GUI.EndGroup();
			GUI.color = Color.white;
		}

		[DebuggerHidden]
		public static IEnumerable<IGrouping<BodyPartRecord, Hediff>> VisibleHediffGroupsInOrder(Pawn pawn, bool showBloodLoss)
		{
			foreach (IGrouping<BodyPartRecord, Hediff> group in from x in rjwHealthCardUtility.VisibleHediffs(pawn, showBloodLoss)
			group x by x.Part into x
			orderby rjwHealthCardUtility.GetListPriority(x.First<Hediff>().Part) descending
			select x)
			{
				yield return group;
			}
		}

		public static float GetListPriority(BodyPartRecord rec)
		{
			if (rec == null)
			{
				return 9999999f;
			}
			return (float)((int)rec.height * 10000) + rec.coverageAbsWithChildren;
		}

		[DebuggerHidden]
		public static IEnumerable<Hediff> VisibleHediffs(Pawn pawn, bool showBloodLoss)
		{
			if (!rjwHealthCardUtility.showAllHediffs)
			{
				List<Hediff_MissingPart> mpca = pawn.health.hediffSet.GetMissingPartsCommonAncestors();
				for (int i = 0; i < mpca.Count; i++)
				{
					yield return mpca[i];
				}
				IEnumerable<Hediff> visibleDiffs = from d in pawn.health.hediffSet.hediffs
				where !(d is Hediff_MissingPart) && d.Visible && (showBloodLoss || d.def != HediffDefOf.BloodLoss)
				select d;
				foreach (Hediff diff in visibleDiffs)
				{
					yield return diff;
				}
			}
			else
			{
				foreach (Hediff diff2 in pawn.health.hediffSet.hediffs)
				{
					yield return diff2;
				}
			}
		}

		public static float DrawMedOperationsTab(Rect leftRect, Pawn pawn, Thing thingForMedBills, float curY)
		{
			curY += 2f;
			Func<List<FloatMenuOption>> recipeOptionsMaker = delegate
			{
				List<FloatMenuOption> list = new List<FloatMenuOption>();
				foreach (RecipeDef current in thingForMedBills.def.AllRecipes)
				{
					if (current.AvailableNow)
					{
						IEnumerable<ThingDef> enumerable = current.PotentiallyMissingIngredients(null, thingForMedBills.Map);
						if (!enumerable.Any((ThingDef x) => x.isTechHediff))
						{
							if (!enumerable.Any((ThingDef x) => x.IsDrug))
							{
								if (!enumerable.Any<ThingDef>() || !current.dontShowIfAnyIngredientMissing)
								{
									if (current.targetsBodyPart)
									{
										foreach (BodyPartRecord current2 in current.Worker.GetPartsToApplyOn(pawn, current))
										{
											list.Add(rjwHealthCardUtility.GenerateSurgeryOption(pawn, thingForMedBills, current, enumerable, current2));
										}
									}
									else
									{
										list.Add(rjwHealthCardUtility.GenerateSurgeryOption(pawn, thingForMedBills, current, enumerable, null));
									}
								}
							}
						}
					}
				}
				return list;
			};
			Rect rect = new Rect(leftRect.x - 9f, curY, leftRect.width, leftRect.height - curY - 20f);
			((IBillGiver)thingForMedBills).BillStack.DoListing(rect, recipeOptionsMaker, ref rjwHealthCardUtility.billsScrollPosition, ref rjwHealthCardUtility.billsScrollHeight);
			return curY;
		}

		public static FloatMenuOption GenerateSurgeryOption(Pawn pawn, Thing thingForMedBills, RecipeDef recipe, IEnumerable<ThingDef> missingIngredients, BodyPartRecord part = null)
		{
			string text = recipe.Worker.GetLabelWhenUsedOn(pawn, part).CapitalizeFirst();
			if (part != null && !recipe.hideBodyPartNames)
			{
				text = text + " (" + part.Label + ")";
			}
			FloatMenuOption floatMenuOption;
			if (missingIngredients.Any<ThingDef>())
			{
				text += " (";
				bool flag = true;
				foreach (ThingDef current in missingIngredients)
				{
					if (!flag)
					{
						text += ", ";
					}
					flag = false;
					text += "MissingMedicalBillIngredient".Translate(current.label);
				}
				text += ")";
				floatMenuOption = new FloatMenuOption(text, null, MenuOptionPriority.Default, null, null, 0f, null, null);
			}
			else
			{
				Action action = delegate
				{
					Pawn pawn2 = thingForMedBills as Pawn;
					if (pawn2 == null)
					{
						return;
					}
					Bill_Medical bill_Medical = new Bill_Medical(recipe);
					pawn2.BillStack.AddBill(bill_Medical);
					bill_Medical.Part = part;
					if (recipe.conceptLearned != null)
					{
						PlayerKnowledgeDatabase.KnowledgeDemonstrated(recipe.conceptLearned, KnowledgeAmount.Total);
					}
					Map map = thingForMedBills.Map;
					if (!map.mapPawns.FreeColonists.Any((Pawn col) => recipe.PawnSatisfiesSkillRequirements(col)))
					{
						Bill.CreateNoPawnsWithSkillDialog(recipe);
					}
					if (!pawn2.InBed() && pawn2.RaceProps.IsFlesh)
					{
						if (pawn2.RaceProps.Humanlike)
						{
							if (!map.listerBuildings.allBuildingsColonist.Any((Building x) => x is Building_Bed && RestUtility.CanUseBedEver(pawn, x.def) && ((Building_Bed)x).Medical))
							{
								Messages.Message("MessageNoMedicalBeds".Translate(), pawn2, MessageTypeDefOf.CautionInput, false);
							}
						}
						else if (!map.listerBuildings.allBuildingsColonist.Any((Building x) => x is Building_Bed && RestUtility.CanUseBedEver(pawn, x.def)))
						{
							Messages.Message("MessageNoAnimalBeds".Translate(), pawn2, MessageTypeDefOf.CautionInput, false);
						}
					}
					if (pawn2.Faction != null && !pawn2.Faction.def.hidden && !pawn2.Faction.HostileTo(Faction.OfPlayer) && recipe.Worker.IsViolationOnPawn(pawn2, part, Faction.OfPlayer))
					{
						Messages.Message("MessageMedicalOperationWillAngerFaction".Translate(pawn2.Faction), pawn2, MessageTypeDefOf.CautionInput, false);
					}
					ThingDef minRequiredMedicine = rjwHealthCardUtility.GetMinRequiredMedicine(recipe);
					if (minRequiredMedicine != null && pawn2.playerSettings != null && !pawn2.playerSettings.medCare.AllowsMedicine(minRequiredMedicine))
					{
						Messages.Message("MessageTooLowMedCare".Translate(minRequiredMedicine.label, pawn2.LabelShort, pawn2.playerSettings.medCare.GetLabel(), pawn2.Named("PAWN")), pawn2, MessageTypeDefOf.CautionInput, false);
					}
				};
				floatMenuOption = new FloatMenuOption(text, action, MenuOptionPriority.Default, null, null, 0f, null, null);
			}
			floatMenuOption.extraPartWidth = 29f;
			floatMenuOption.extraPartOnGUI = ((Rect rect) => Widgets.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2f, recipe));
			return floatMenuOption;
		}

		public static ThingDef GetMinRequiredMedicine(RecipeDef recipe)
		{
			rjwHealthCardUtility.tmpMedicineBestToWorst.Clear();
			List<ThingDef> allDefsListForReading = DefDatabase<ThingDef>.AllDefsListForReading;
			for (int i = 0; i < allDefsListForReading.Count; i++)
			{
				if (allDefsListForReading[i].IsMedicine)
				{
					rjwHealthCardUtility.tmpMedicineBestToWorst.Add(allDefsListForReading[i]);
				}
			}
			rjwHealthCardUtility.tmpMedicineBestToWorst.SortByDescending((ThingDef x) => x.GetStatValueAbstract(StatDefOf.MedicalPotency, null));
			ThingDef thingDef = null;
			for (int j = 0; j < recipe.ingredients.Count; j++)
			{
				ThingDef thingDef2 = null;
				for (int k = 0; k < rjwHealthCardUtility.tmpMedicineBestToWorst.Count; k++)
				{
					if (recipe.ingredients[j].filter.Allows(rjwHealthCardUtility.tmpMedicineBestToWorst[k]))
					{
						thingDef2 = rjwHealthCardUtility.tmpMedicineBestToWorst[k];
					}
				}
				if (thingDef2 != null && (thingDef == null || thingDef2.GetStatValueAbstract(StatDefOf.MedicalPotency, null) > thingDef.GetStatValueAbstract(StatDefOf.MedicalPotency, null)))
				{
					thingDef = thingDef2;
				}
			}
			rjwHealthCardUtility.tmpMedicineBestToWorst.Clear();
			return thingDef;
		}

		public static float DrawOverviewTab(Rect leftRect, Pawn pawn, float curY)
		{
			curY += 4f;
			Text.Font = GameFont.Tiny;
			Text.Anchor = TextAnchor.UpperLeft;
			GUI.color = new Color(0.9f, 0.9f, 0.9f);
			string text = string.Empty;
			if (pawn.gender != Gender.None)
			{
				text = pawn.GetGenderLabel() + " ";
			}
			text = text + pawn.def.label + ", " + "AgeIndicator".Translate(pawn.ageTracker.AgeNumberString);
			Rect rect = new Rect(0f, curY, leftRect.width, 34f);
			Widgets.Label(rect, text.CapitalizeFirst());
			TooltipHandler.TipRegion(rect, () => pawn.ageTracker.AgeTooltipString, 73412);
			if (Mouse.IsOver(rect))
			{
				Widgets.DrawHighlight(rect);
			}
			GUI.color = Color.white;
			curY += 34f;
			if (pawn.foodRestriction != null && pawn.foodRestriction.Configurable)
			{
				Rect rect2 = new Rect(0f, curY, leftRect.width * 0.42f, 23f);
				Text.Anchor = TextAnchor.MiddleLeft;
				Widgets.Label(rect2, "FoodRestriction".Translate());
				GenUI.ResetLabelAlign();
				Rect rect3 = new Rect(rect2.width, curY, leftRect.width - rect2.width, 23f);
				if (Widgets.ButtonText(rect3, pawn.foodRestriction.CurrentFoodRestriction.label, true, false, true))
				{
					List<FloatMenuOption> list = new List<FloatMenuOption>();
					List<FoodRestriction> allFoodRestrictions = Current.Game.foodRestrictionDatabase.AllFoodRestrictions;
					for (int i = 0; i < allFoodRestrictions.Count; i++)
					{
						FoodRestriction localRestriction = allFoodRestrictions[i];
						list.Add(new FloatMenuOption(localRestriction.label, delegate
						{
							pawn.foodRestriction.CurrentFoodRestriction = localRestriction;
						}, MenuOptionPriority.Default, null, null, 0f, null, null));
					}
					list.Add(new FloatMenuOption("ManageFoodRestrictions".Translate(), delegate
					{
						Find.WindowStack.Add(new Dialog_ManageFoodRestrictions(null));
					}, MenuOptionPriority.Default, null, null, 0f, null, null));
					Find.WindowStack.Add(new FloatMenu(list));
				}
				curY += 23f;
			}
			if (pawn.IsColonist && !pawn.Dead)
			{
				bool selfTend = pawn.playerSettings.selfTend;
				Rect rect4 = new Rect(0f, curY, leftRect.width, 24f);
				Widgets.CheckboxLabeled(rect4, "SelfTend".Translate(), ref pawn.playerSettings.selfTend, false, null, null, false);
				if (pawn.playerSettings.selfTend && !selfTend)
				{
					if (pawn.story.WorkTypeIsDisabled(WorkTypeDefOf.Doctor))
					{
						pawn.playerSettings.selfTend = false;
						Messages.Message("MessageCannotSelfTendEver".Translate(pawn.LabelShort, pawn), MessageTypeDefOf.RejectInput, false);
					}
					else if (pawn.workSettings.GetPriority(WorkTypeDefOf.Doctor) == 0)
					{
						Messages.Message("MessageSelfTendUnsatisfied".Translate(pawn.LabelShort, pawn), MessageTypeDefOf.CautionInput, false);
					}
				}
				TooltipHandler.TipRegion(rect4, "SelfTendTip".Translate(Faction.OfPlayer.def.pawnsPlural, 0.7f.ToStringPercent()).CapitalizeFirst());
				curY += 28f;
			}
			if (pawn.playerSettings != null && !pawn.Dead && Current.ProgramState == ProgramState.Playing)
			{
				Rect rect5 = new Rect(0f, curY, 140f, 28f);
				MedicalCareUtility.MedicalCareSetter(rect5, ref pawn.playerSettings.medCare);
				if (Widgets.ButtonText(new Rect(leftRect.width - 70f, curY, 70f, 28f), "MedGroupDefaults".Translate(), true, false, true))
				{
					Find.WindowStack.Add(new Dialog_MedicalDefaults());
				}
				curY += 32f;
			}
			Text.Font = GameFont.Small;
			if (pawn.def.race.IsFlesh)
			{
				Pair<string, Color> painLabel = rjwHealthCardUtility.GetPainLabel(pawn);
				string painTip = rjwHealthCardUtility.GetPainTip(pawn);
				curY = rjwHealthCardUtility.DrawLeftRow(leftRect, curY, "PainLevel".Translate(), painLabel.First, painLabel.Second, painTip);
			}
			if (!pawn.Dead)
			{
				IEnumerable<PawnCapacityDef> source;
				if (pawn.def.race.Humanlike)
				{
					source = from x in DefDatabase<PawnCapacityDef>.AllDefs
					where x.showOnHumanlikes
					select x;
				}
				else if (pawn.def.race.Animal)
				{
					source = from x in DefDatabase<PawnCapacityDef>.AllDefs
					where x.showOnAnimals
					select x;
				}
				else
				{
					source = from x in DefDatabase<PawnCapacityDef>.AllDefs
					where x.showOnMechanoids
					select x;
				}
				foreach (PawnCapacityDef current in from act in source
				orderby act.listOrder
				select act)
				{
					if (PawnCapacityUtility.BodyCanEverDoCapacity(pawn.RaceProps.body, current))
					{
						PawnCapacityDef activityLocal = current;
						Pair<string, Color> efficiencyLabel = rjwHealthCardUtility.GetEfficiencyLabel(pawn, current);
						Func<string> textGetter = () => (!pawn.Dead) ? rjwHealthCardUtility.GetPawnCapacityTip(pawn, activityLocal) : string.Empty;
						curY = rjwHealthCardUtility.DrawLeftRow(leftRect, curY, current.GetLabelFor(pawn.RaceProps.IsFlesh, pawn.RaceProps.Humanlike).CapitalizeFirst(), efficiencyLabel.First, efficiencyLabel.Second, new TipSignal(textGetter, pawn.thingIDNumber ^ (int)current.index));
					}
				}
			}
			return curY;
		}

		public static float DrawLeftRow(Rect leftRect, float curY, string leftLabel, string rightLabel, Color rightLabelColor, TipSignal tipSignal)
		{
			Rect rect = new Rect(0f, curY, leftRect.width, 20f);
			if (Mouse.IsOver(rect))
			{
				GUI.color = rjwHealthCardUtility.HighlightColor;
				GUI.DrawTexture(rect, TexUI.HighlightTex);
			}
			GUI.color = Color.white;
			Widgets.Label(new Rect(0f, curY, leftRect.width * 0.65f, 30f), leftLabel);
			GUI.color = rightLabelColor;
			Widgets.Label(new Rect(leftRect.width * 0.65f, curY, leftRect.width * 0.35f, 30f), rightLabel);
			TooltipHandler.TipRegion(new Rect(0f, curY, leftRect.width, 20f), tipSignal);
			curY += 20f;
			return curY;
		}

		public static void DrawHediffRow(Rect rect, Pawn pawn, IEnumerable<Hediff> diffs, ref float curY)
		{
			float num = rect.width * 0.375f;
			float width = rect.width - num - 20f;
			BodyPartRecord part = diffs.First<Hediff>().Part;
			float a;
			if (part == null)
			{
				a = Text.CalcHeight("WholeBody".Translate(), num);
			}
			else
			{
				a = Text.CalcHeight(part.LabelCap, num);
			}
			float b = 0f;
			float num2 = curY;
			float num3 = 0f;
			foreach (IGrouping<int, Hediff> current in from x in diffs
			group x by x.UIGroupKey)
			{
				int num4 = current.Count<Hediff>();
				string text = current.First<Hediff>().LabelCap;
				if (num4 != 1)
				{
					text = text + " x" + num4.ToString();
				}
				num3 += Text.CalcHeight(text, width);
			}
			b = num3;
			Rect rect2 = new Rect(0f, curY, rect.width, Mathf.Max(a, b));
			rjwHealthCardUtility.DoRightRowHighlight(rect2);
			if (part != null)
			{
				GUI.color = HealthUtility.GetPartConditionLabel(pawn, part).Second;
				Widgets.Label(new Rect(0f, curY, num, 100f), part.LabelCap);
			}
			else
			{
				GUI.color = HealthUtility.DarkRedColor;
				Widgets.Label(new Rect(0f, curY, num, 100f), "WholeBody".Translate());
			}
			GUI.color = Color.white;
			foreach (IGrouping<int, Hediff> current2 in from x in diffs
			group x by x.UIGroupKey)
			{
				int num5 = 0;
				Hediff hediff = null;
				Texture2D texture2D = null;
				TextureAndColor textureAndColor = null;
				float num6 = 0f;
				foreach (Hediff current3 in current2)
				{
					if (num5 == 0)
					{
						hediff = current3;
					}
					textureAndColor = current3.StateIcon;
					if (current3.Bleeding)
					{
						texture2D = rjwHealthCardUtility.BleedingIcon;
					}
					num6 += current3.BleedRate;
					num5++;
				}
				string text2 = hediff.LabelCap;
				if (num5 != 1)
				{
					text2 = text2 + " x" + num5.ToStringCached();
				}
				GUI.color = hediff.LabelColor;
				float num7 = Text.CalcHeight(text2, width);
				Rect rect3 = new Rect(num, curY, width, num7);
				Widgets.Label(rect3, text2);
				GUI.color = Color.white;
				Rect rect4 = new Rect(rect2.xMax - 20f, curY, 20f, 20f);
				if (texture2D)
				{
					Rect position = rect4.ContractedBy(GenMath.LerpDouble(0f, 0.6f, 5f, 0f, Mathf.Min(num6, 1f)));
					GUI.DrawTexture(position, texture2D);
					rect4.x -= rect4.width;
				}
				if (textureAndColor.HasValue)
				{
					GUI.color = textureAndColor.Color;
					GUI.DrawTexture(rect4, textureAndColor.Texture);
					GUI.color = Color.white;
					rect4.x -= rect4.width;
				}
				curY += num7;
			}
			GUI.color = Color.white;
			curY = num2 + Mathf.Max(a, b);
			if (Widgets.ButtonInvisible(rect2, false))
			{
				rjwHealthCardUtility.EntryClicked(diffs, pawn);
			}
			TooltipHandler.TipRegion(rect2, new TipSignal(() => rjwHealthCardUtility.GetTooltip(diffs, pawn, part), (int)curY + 7857));
		}

		public static string GetPainTip(Pawn pawn)
		{
			return "PainLevel".Translate() + ": " + (pawn.health.hediffSet.PainTotal * 100f).ToString("F0") + "%";
		}

		public static string GetPawnCapacityTip(Pawn pawn, PawnCapacityDef capacity)
		{
			List<PawnCapacityUtility.CapacityImpactor> list = new List<PawnCapacityUtility.CapacityImpactor>();
			float num = PawnCapacityUtility.CalculateCapacityLevel(pawn.health.hediffSet, capacity, list);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(capacity.LabelCap + ": " + (num * 100f).ToString("F0") + "%");
			if (list.Count > 0)
			{
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("AffectedBy".Translate());
				for (int i = 0; i < list.Count; i++)
				{
					if (list[i] is PawnCapacityUtility.CapacityImpactorHediff)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[i].Readable(pawn)));
					}
				}
				for (int j = 0; j < list.Count; j++)
				{
					if (list[j] is PawnCapacityUtility.CapacityImpactorBodyPartHealth)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[j].Readable(pawn)));
					}
				}
				for (int k = 0; k < list.Count; k++)
				{
					if (list[k] is PawnCapacityUtility.CapacityImpactorCapacity)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[k].Readable(pawn)));
					}
				}
				for (int l = 0; l < list.Count; l++)
				{
					if (list[l] is PawnCapacityUtility.CapacityImpactorPain)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[l].Readable(pawn)));
					}
				}
			}
			return stringBuilder.ToString();
		}

		public static string GetTooltip(IEnumerable<Hediff> diffs, Pawn pawn, BodyPartRecord part)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (part != null)
			{
				stringBuilder.Append(part.LabelCap + ": ");
				stringBuilder.AppendLine(" " + pawn.health.hediffSet.GetPartHealth(part).ToString() + " / " + part.def.GetMaxHealth(pawn).ToString());
				float num = PawnCapacityUtility.CalculatePartEfficiency(pawn.health.hediffSet, part, false, null);
				if (num != 1f)
				{
					stringBuilder.AppendLine("Efficiency".Translate() + ": " + num.ToStringPercent());
				}
			}
			else
			{
				stringBuilder.AppendLine("WholeBody".Translate());
			}
			stringBuilder.AppendLine("------------------");
			foreach (IGrouping<int, Hediff> current in from x in diffs
			group x by x.UIGroupKey)
			{
				foreach (Hediff current2 in current)
				{
					string severityLabel = current2.SeverityLabel;
					bool flag = rjwHealthCardUtility.showHediffsDebugInfo && !current2.DebugString().NullOrEmpty();
					if (!current2.Label.NullOrEmpty() || !severityLabel.NullOrEmpty() || !current2.CapMods.NullOrEmpty<PawnCapacityModifier>() || flag)
					{
						stringBuilder.Append(current2.LabelCap);
						if (!severityLabel.NullOrEmpty())
						{
							stringBuilder.Append(": " + severityLabel);
						}
						stringBuilder.AppendLine();
						string tipStringExtra = current2.TipStringExtra;
						if (!tipStringExtra.NullOrEmpty())
						{
							stringBuilder.AppendLine(tipStringExtra.TrimEndNewlines().Indented("    "));
						}
						if (flag)
						{
							stringBuilder.AppendLine(current2.DebugString().TrimEndNewlines());
						}
					}
				}
			}
			string s;
			LogEntry logEntry;
			if (rjwHealthCardUtility.GetCombatLogInfo(diffs, out s, out logEntry))
			{
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("Cause:");
				stringBuilder.AppendLine(s.Indented("    "));
			}
			return stringBuilder.ToString().TrimEnd(new char[0]);
		}

		public static void EntryClicked(IEnumerable<Hediff> diffs, Pawn pawn)
		{
			LogEntry combatLogEntry;
			string text;
			if (!rjwHealthCardUtility.GetCombatLogInfo(diffs, out text, out combatLogEntry) || combatLogEntry == null)
			{
				return;
			}
			if (!Find.BattleLog.Battles.Any((Battle b) => b.Concerns(pawn) && b.Entries.Any((LogEntry e) => e == combatLogEntry)))
			{
				return;
			}
			ITab_Pawn_Log tab_Pawn_Log = InspectPaneUtility.OpenTab(typeof(ITab_Pawn_Log)) as ITab_Pawn_Log;
			if (tab_Pawn_Log == null)
			{
				return;
			}
			tab_Pawn_Log.SeekTo(combatLogEntry);
			tab_Pawn_Log.Highlight(combatLogEntry);
		}

		public static bool GetCombatLogInfo(IEnumerable<Hediff> diffs, out string combatLogText, out LogEntry combatLogEntry)
		{
			combatLogText = null;
			combatLogEntry = null;
			foreach (Hediff current in diffs)
			{
				if ((current.combatLogEntry != null && current.combatLogEntry.Target != null) || (combatLogText.NullOrEmpty() && !current.combatLogText.NullOrEmpty()))
				{
					combatLogEntry = ((current.combatLogEntry == null) ? null : current.combatLogEntry.Target);
					combatLogText = current.combatLogText;
				}
				if (combatLogEntry != null)
				{
					return true;
				}
			}
			return false;
		}

		public static void DoRightRowHighlight(Rect rowRect)
		{
			if (rjwHealthCardUtility.highlight)
			{
				GUI.color = rjwHealthCardUtility.StaticHighlightColor;
				GUI.DrawTexture(rowRect, TexUI.HighlightTex);
			}
			rjwHealthCardUtility.highlight = !rjwHealthCardUtility.highlight;
			if (Mouse.IsOver(rowRect))
			{
				GUI.color = rjwHealthCardUtility.HighlightColor;
				GUI.DrawTexture(rowRect, TexUI.HighlightTex);
			}
		}

		public static void DoDebugOptions(Rect rightRect, Pawn pawn)
		{
			Widgets.CheckboxLabeled(new Rect(rightRect.x, rightRect.y - 25f, 110f, 30f), "Dev: AllDiffs", ref rjwHealthCardUtility.showAllHediffs, false, null, null, false);
			Widgets.CheckboxLabeled(new Rect(rightRect.x + 115f, rightRect.y - 25f, 120f, 30f), "DiffsDebugInfo", ref rjwHealthCardUtility.showHediffsDebugInfo, false, null, null, false);
			if (Widgets.ButtonText(new Rect(rightRect.x + 240f, rightRect.y - 27f, 115f, 25f), "Debug info", true, false, true))
			{
				List<FloatMenuOption> list = new List<FloatMenuOption>();
				list.Add(new FloatMenuOption("Parts hit chance (this part or any child node)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby x.coverageAbsWithChildren descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.coverageAbsWithChildren.ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("Parts hit chance (exactly this part)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					float num = 0f;
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby x.coverageAbs descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.coverageAbs.ToStringPercent());
						num += current.coverageAbs;
					}
					stringBuilder.AppendLine();
					stringBuilder.AppendLine("Total " + num.ToStringPercent());
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("Per-part efficiency", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.RaceProps.body.AllParts)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + PawnCapacityUtility.CalculatePartEfficiency(pawn.health.hediffSet, current, false, null).ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("BodyPartGroup efficiency (of only natural parts)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartGroupDef current in from x in DefDatabase<BodyPartGroupDef>.AllDefs
					where pawn.RaceProps.body.AllParts.Any((BodyPartRecord y) => y.groups.Contains(x))
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + PawnCapacityUtility.CalculateNaturalPartsAverageEfficiency(pawn.health.hediffSet, current).ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("IsSolid", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.def.IsSolid(current, pawn.health.hediffSet.hediffs));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("IsSkinCovered", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.def.IsSkinCovered(current, pawn.health.hediffSet));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("does have added parts", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap + " " + pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(current));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("GetNotMissingParts", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap);
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("GetCoverageOfNotMissingNaturalParts", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby pawn.health.hediffSet.GetCoverageOfNotMissingNaturalParts(x) descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + ": " + pawn.health.hediffSet.GetCoverageOfNotMissingNaturalParts(current).ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("parts nutrition (assuming adult)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					float totalCorpseNutrition = StatDefOf.Nutrition.Worker.GetValueAbstract(pawn.RaceProps.corpseDef, null);
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby FoodUtility.GetBodyPartNutrition(totalCorpseNutrition, pawn, x) descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + ": " + FoodUtility.GetBodyPartNutrition(totalCorpseNutrition, pawn, current));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("test permanent injury pain factor probability", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					int num = 0;
					int num2 = 0;
					int num3 = 0;
					float num4 = 0f;
					int num5 = 10000;
					for (int i = 0; i < num5; i++)
					{
						float num6 = Mathf.Max(0f, Rand.ByCurve(HealthTuning.PermanentInjuryPainFactorRandomCurve));
						if (num6 < 0f)
						{
							Log.Error("Pain factor < 0", false);
						}
						if (num6 == 0f)
						{
							num++;
						}
						if (num6 < 1f)
						{
							num2++;
						}
						if (num6 < 5f)
						{
							num3++;
						}
						if (num6 > num4)
						{
							num4 = num6;
						}
					}
					stringBuilder.AppendLine("total: " + num5);
					stringBuilder.AppendLine(string.Concat(new object[]
					{
						"0: ",
						num,
						" (",
						((float)num / (float)num5).ToStringPercent(),
						")"
					}));
					stringBuilder.AppendLine(string.Concat(new object[]
					{
						"< 1: ",
						num2,
						" (",
						((float)num2 / (float)num5).ToStringPercent(),
						")"
					}));
					stringBuilder.AppendLine(string.Concat(new object[]
					{
						"< 5: ",
						num3,
						" (",
						((float)num3 / (float)num5).ToStringPercent(),
						")"
					}));
					stringBuilder.AppendLine("max: " + num4);
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("HediffGiver_Birthday chance at age", delegate
				{
					List<FloatMenuOption> list2 = new List<FloatMenuOption>();
					foreach (HediffGiverSetDef current in pawn.RaceProps.hediffGiverSets)
					{
						foreach (HediffGiver_Birthday current2 in current.hediffGivers.OfType<HediffGiver_Birthday>())
						{
							HediffGiver_Birthday hLocal = current2;
							FloatMenuOption item = new FloatMenuOption(current.defName + " - " + current2.hediff.defName, delegate
							{
								StringBuilder stringBuilder = new StringBuilder();
								stringBuilder.AppendLine("% of pawns which will have at least 1 " + hLocal.hediff.label + " at age X:");
								stringBuilder.AppendLine();
								int num = 1;
								while ((float)num < pawn.RaceProps.lifeExpectancy + 20f)
								{
									stringBuilder.AppendLine(num + ": " + hLocal.DebugChanceToHaveAtAge(pawn, num).ToStringPercent());
									num++;
								}
								Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
							}, MenuOptionPriority.Default, null, null, 0f, null, null);
							list2.Add(item);
						}
					}
					Find.WindowStack.Add(new FloatMenu(list2));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("HediffGiver_Birthday count at age", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					stringBuilder.AppendLine("Average hediffs count (from HediffGiver_Birthday) at age X:");
					stringBuilder.AppendLine();
					int num = 1;
					while ((float)num < pawn.RaceProps.lifeExpectancy + 20f)
					{
						float num2 = 0f;
						foreach (HediffGiverSetDef current in pawn.RaceProps.hediffGiverSets)
						{
							foreach (HediffGiver_Birthday current2 in current.hediffGivers.OfType<HediffGiver_Birthday>())
							{
								num2 += current2.DebugChanceToHaveAtAge(pawn, num);
							}
						}
						stringBuilder.AppendLine(num + ": " + num2.ToStringDecimalIfSmall());
						num++;
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				Find.WindowStack.Add(new FloatMenu(list));
			}
		}

		public static Pair<string, Color> GetEfficiencyLabel(Pawn pawn, PawnCapacityDef activity)
		{
			float level = pawn.health.capacities.GetLevel(activity);
			string first = string.Empty;
			Color second = Color.white;
			if (level <= 0f)
			{
				first = "None".Translate();
				second = HealthUtility.DarkRedColor;
			}
			else if (level < 0.4f)
			{
				first = "VeryPoor".Translate();
				second = rjwHealthCardUtility.VeryPoorColor;
			}
			else if (level < 0.7f)
			{
				first = "Poor".Translate();
				second = rjwHealthCardUtility.PoorColor;
			}
			else if (level < 1f && !Mathf.Approximately(level, 1f))
			{
				first = "Weakened".Translate();
				second = rjwHealthCardUtility.WeakenedColor;
			}
			else if (Mathf.Approximately(level, 1f))
			{
				first = "GoodCondition".Translate();
				second = HealthUtility.GoodConditionColor;
			}
			else
			{
				first = "Enhanced".Translate();
				second = rjwHealthCardUtility.EnhancedColor;
			}
			return new Pair<string, Color>(first, second);
		}

		public static Pair<string, Color> GetPainLabel(Pawn pawn)
		{
			float painTotal = pawn.health.hediffSet.PainTotal;
			string first = string.Empty;
			Color second = Color.white;
			if (Mathf.Approximately(painTotal, 0f))
			{
				first = "NoPain".Translate();
				second = HealthUtility.GoodConditionColor;
			}
			else if (painTotal < 0.15f)
			{
				first = "LittlePain".Translate();
				second = Color.gray;
			}
			else if (painTotal < 0.4f)
			{
				first = "MediumPain".Translate();
				second = rjwHealthCardUtility.MediumPainColor;
			}
			else if (painTotal < 0.8f)
			{
				first = "SeverePain".Translate();
				second = rjwHealthCardUtility.SeverePainColor;
			}
			else
			{
				first = "ExtremePain".Translate();
				second = HealthUtility.DarkRedColor;
			}
			return new Pair<string, Color>(first, second);
		}
	}
}


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

namespace rjw
{
	public class AgeConfigDef : Def
	{
		public SimpleCurve attractivenessByAgeFemale;
		public SimpleCurve attractivenessByAgeMale;
		public SimpleCurve lovinIntervalHoursByAge;
		public SimpleCurve rigidityByAge;
		public SimpleCurve whoringPriceByAge;

		static readonly Lazy<AgeConfigDef> instance = new Lazy<AgeConfigDef>(() => DefDatabase<AgeConfigDef>.AllDefs.Single());

		public static AgeConfigDef Instance
		{
			get
			{
				return instance.Value;
			}
		}
	}
}


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

namespace rjw
{
	public class BedData : IExposable
	{
		public Building_Bed bed = null;
		public bool allowedForWhoringOwner = true;
		public bool allowedForWhoringAll = false;
		public int reservedUntilGameTick = 0;
		public int reservedForPawnID = 0;

		public int lastScoreUpdateTick = -70; // GenTicks.TicksGame
		public float bedScore = -1f;
		public int scoreUpdateTickDelay = 60;

		public BedData() { }
		public BedData(Building_Bed bed)
		{
			this.bed = bed;
		}

		public void ExposeData()
		{
			Scribe_References.Look(ref bed, "Bed");
			Scribe_Values.Look(ref allowedForWhoringOwner, "allowedForWhoringOwner", true, true);
			Scribe_Values.Look(ref allowedForWhoringAll, "allowedForWhoringAll", false, true);
			Scribe_Values.Look(ref reservedUntilGameTick, "lastUsed", 0, true);
			Scribe_Values.Look(ref reservedForPawnID, "lastUsedBy", 0, true);
		}

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


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

namespace rjw
{
	/// <summary>
	/// Hugslib Utility Data object storing the RJW info
	/// also implements extensions to Pawn method
	/// is used as a static field in PawnData
	/// </summary>
	public class DataStore : WorldComponent
	{
		public DataStore(World world) : base(world)
		{
		}

		public Dictionary<int, PawnData> PawnData = new Dictionary<int, PawnData> ();
		//public Dictionary<int, PartsData> PartsData = new Dictionary<int, PartsData> ();
		public Dictionary<int, BedData> bedData = new Dictionary<int, BedData>();

		public override void ExposeData()
		{
			if (Scribe.mode == LoadSaveMode.Saving)
			{
				PawnData.RemoveAll(item => item.Value == null || !item.Value.IsValid);
				bedData.RemoveAll(item => item.Value == null || !item.Value.IsValid);
			}

			base.ExposeData();
			Scribe_Collections.Look(ref PawnData, "Data", LookMode.Value, LookMode.Deep);
			Scribe_Collections.Look(ref bedData, "BedData", LookMode.Value, LookMode.Deep);
			if (Scribe.mode == LoadSaveMode.LoadingVars)
			{
				if (PawnData == null) PawnData = new Dictionary<int, PawnData>();
				if (bedData == null) bedData = new Dictionary<int, BedData>();
			}
		}

		public PawnData GetPawnData(Pawn pawn)
		{
			PawnData res;
			//--Log.Message("Getting data for " + pawn);
			//--Log.Message("Pawn " + pawn + " id " + pawn.thingIDNumber);
			//--Log.Message("PawnData isn't null " + !(PawnData == null));
			var filled = PawnData.TryGetValue(pawn.thingIDNumber, out res);
			//--Log.Message("Output is not null" + PawnData.TryGetValue(pawn.thingIDNumber, out res));
			//--Log.Message("Out is not null " + (res != null));
			//--Log.Message("Out is valid " + (res != null && res.IsValid));
			if ((res==null) || (!res.IsValid))
			{
				if (filled)
				{
					//--Log.Message("Clearing incorrect data for " + pawn);
					PawnData.Remove(pawn.thingIDNumber);
				}
				//--Log.Message("PawnData missing, creating for " + pawn);
				res = new PawnData(pawn);
				PawnData.Add(pawn.thingIDNumber, res);
			}
			//--Log.Message("Finishing");
			//--Log.Message("PawnData is " + res.Comfort + " " + res.Service + " " + res.Breeding);
			return res;
		}
		public BedData GetBedData(Building_Bed bed)
		{
			BedData res;
			var filled = bedData.TryGetValue(bed.thingIDNumber, out res);
			if ((res == null) || (!res.IsValid))
			{
				if (filled)
				{
					bedData.Remove(bed.thingIDNumber);
				}
				res = new BedData(bed);
				bedData.Add(bed.thingIDNumber, res);
			}
			return res;
		}

		void SetPawnData(Pawn pawn, PawnData data)
		{
			PawnData.Add(pawn.thingIDNumber, data);
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Collection of pawn designators lists
	/// </summary>
	public class DesignatorsData : WorldComponent
	{
		public DesignatorsData(World world) : base(world)
		{
		}

		public static List<Pawn> rjwHero = new List<Pawn>();
		public static List<Pawn> rjwComfort = new List<Pawn>();
		public static List<Pawn> rjwService = new List<Pawn>();
		public static List<Pawn> rjwMilking = new List<Pawn>();
		public static List<Pawn> rjwBreeding = new List<Pawn>();
		public static List<Pawn> rjwBreedingAnimal = new List<Pawn>();

		//public static Dictionary<string, List<Pawn>> Designators = new Dictionary<string, List<Pawn>>();

		/// <summary>
		/// update designators on game load
		/// </summary>
		public void Update()
		{
			//if (RJWSettings.DevMode)
				//ModLog.Message("DesignatorsData::Update()");
			rjwHero = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedHero()).ToList();
			rjwComfort = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedComfort()).ToList();
			rjwService = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedService()).ToList();
			rjwMilking = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedMilking()).ToList();
			rjwBreeding = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedBreeding()).ToList();
			rjwBreedingAnimal = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedBreedingAnimal()).ToList();
			//ModLog.Message("rjwHero "+rjwHero.Count());
			//ModLog.Message("rjwComfort "+rjwComfort.Count());
			//ModLog.Message("rjwService "+rjwService.Count());
			//ModLog.Message("rjwMilking "+rjwMilking.Count());
			//ModLog.Message("rjwBreeding "+rjwBreeding.Count());
			//ModLog.Message("rjwBreedingAnimal "+rjwBreedingAnimal.Count());

			//Designators = new Dictionary<string, List<Pawn>>();
			//Designators.Add("rjwHero", rjwHero);
			//Designators.Add("rjwComfort", rjwComfort);
			//Designators.Add("rjwService", rjwService);
			//Designators.Add("rjwMilking", rjwMilking);
			//Designators.Add("rjwBreeding", rjwBreeding);
			//Designators.Add("rjwBreedingAnimal", rjwBreedingAnimal);
		}
	}
}


code:
using HugsLib;
using RimWorld;
using Verse;

namespace rjw
{
	/// <summary>
	/// Rjw settings store
	/// </summary>
	public class SaveStorage : ModBase
	{
		public override string ModIdentifier => ModId;
		public static string ModId => "SJW";

		public static DataStore DataStore;//reference to savegame data, hopefully
		public static DesignatorsData DesignatorsData;//reference to savegame data, hopefully

		public override void SettingsChanged()
		{
			ToggleTabIfNeeded();
		}

		public override void WorldLoaded()
		{
			DataStore = Find.World.GetComponent<DataStore>();
			DesignatorsData = Find.World.GetComponent<DesignatorsData>();
			DesignatorsData.Update();
			ToggleTabIfNeeded();
			FixRjwHediffsOnlLoad();
		}
		protected override bool HarmonyAutoPatch { get => false; }//first.cs creates harmony and does some convoulted stuff with it

		private void ToggleTabIfNeeded()
		{
			DefDatabase<MainButtonDef>.GetNamed("Brothel").buttonVisible = RJWSettings.whoringtab_enabled;
		}
		private void FixRjwHediffsOnlLoad()
		{
			foreach (var pawn in PawnsFinder.All_AliveOrDead)
			{
				foreach (var hd in pawn.health.hediffSet.hediffs)
				{
					if (hd is Hediff_PartBaseNatural || hd is Hediff_PartBaseArtifical)
					{
						hd.TryGetComp<CompHediffBodyPart>().updatepartposition();
					}
				}
			}
		}
	}
}


code:
using System.Collections.Generic;
using Verse;
using System;
using System.ComponentModel;
using System.Linq;
using Verse.Noise;

namespace rjw
{
	/// <summary>
	/// Data about part sizes that is not tied to an individual hediffdef.
	/// </summary>
	public class PartStagesDef : Def
	{
		public float bandSizeBase;
		public float bandSizeInterval;
		public float cupSizeInterval;
		public List<string> cupSizeLabels;

		static readonly Lazy<PartStagesDef> instance = new Lazy<PartStagesDef>(() => DefDatabase<PartStagesDef>.AllDefs.Single());

		public static PartStagesDef Instance
		{
			get
			{
				return instance.Value;
			}
		}

		public static string GetCupSizeLabel(float size)
		{
			var i = Math.Max(0, Math.Min(Instance.cupSizeLabels.Count - 1, (int)size));
			return Instance.cupSizeLabels[i];
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Utility data object and a collection of extension methods for Pawn
	/// </summary>
	public class PawnData : IExposable
	{
		public Pawn Pawn = null;
		public bool Comfort = false;
		public bool Service = false;
		public bool Breeding = false;
		public bool Milking = false;
		public bool Hero = false;
		public bool Ironman = false;
		public string HeroOwner = "";
		public bool BreedingAnimal = false;
		public bool CanChangeDesignationColonist = false;
		public bool CanChangeDesignationPrisoner = false;
		public bool CanDesignateService = false;
		public bool CanDesignateMilking = false;
		public bool CanDesignateComfort = false;
		public bool CanDesignateBreedingAnimal = false;
		public bool CanDesignateBreeding = false;
		public bool CanDesignateHero = false;
		public bool ShowRMB_Menu = false;

		public bool isSlime = false;
		public bool isDemon = false;
		public bool oviPregnancy = false;

		public float raceSexDrive = 1.0f;

		public PawnData() { }

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

			if (RaceGroupDef_Helper.TryGetRaceGroupDef(Pawn, out var raceGroupDef))
			{
				oviPregnancy = raceGroupDef.oviPregnancy;
				raceSexDrive = raceGroupDef.raceSexDrive;
			}

			isDemon = Pawn.Has(RaceTag.Demon);
			isSlime = Pawn.Has(RaceTag.Slime);
			//Log.Warning("PawnData:: Pawn:" + xxx.get_pawnname(pawn));
			//Log.Warning("PawnData:: isSlime:" + isSlime);
			//Log.Warning("PawnData:: isDemon:" + isDemon);
			//Log.Warning("PawnData:: oviPregnancy:" + oviPregnancy);
		}

		public void ExposeData()
		{
			Scribe_References.Look(ref Pawn, "Pawn");
			Scribe_Values.Look(ref Comfort, "Comfort", false, true);
			Scribe_Values.Look(ref Service, "Service", false, true);
			Scribe_Values.Look(ref Breeding, "Breeding", false, true);
			Scribe_Values.Look(ref Milking, "Milking", false, true);
			Scribe_Values.Look(ref Hero, "Hero", false, true);
			Scribe_Values.Look(ref Ironman, "Ironman", false, true);
			Scribe_Values.Look(ref HeroOwner, "HeroOwner", "", true);
			Scribe_Values.Look(ref BreedingAnimal, "BreedingAnimal", false, true);
			Scribe_Values.Look(ref CanChangeDesignationColonist, "CanChangeDesignationColonist", false, true);
			Scribe_Values.Look(ref CanChangeDesignationPrisoner, "CanChangeDesignationPrisoner", false, true);
			Scribe_Values.Look(ref CanDesignateService, "CanDesignateService", false, true);
			Scribe_Values.Look(ref CanDesignateMilking, "CanDesignateMilking", false, true);
			Scribe_Values.Look(ref CanDesignateComfort, "CanDesignateComfort", false, true);
			Scribe_Values.Look(ref CanDesignateBreedingAnimal, "CanDesignateBreedingAnimal", false, true);
			Scribe_Values.Look(ref CanDesignateBreeding, "CanDesignateBreeding", false, true);
			Scribe_Values.Look(ref CanDesignateHero, "CanDesignateHero", false, true);
			Scribe_Values.Look(ref ShowRMB_Menu, "ShowRMB_Menu", false, true);
			Scribe_Values.Look(ref isSlime, "isSlime", false, true);
			Scribe_Values.Look(ref isDemon, "isDemon", false, true);
			Scribe_Values.Look(ref oviPregnancy, "oviPregnancy", false, true);
			Scribe_Values.Look(ref raceSexDrive, "raceSexDrive", 1.0f, true);
	}

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


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

namespace rjw
{
	/// <summary>
	/// Defines all RJW configuration related to a specific race or group of races.
	/// Core races should have RaceGroupDefs in RJW.
	/// Non-core races should have RaceGroupDefs in the separate RJWRaceSupport mod.
	/// Technically any mod could add a RaceGroupDef for its own races but we expect that to be rare.
	/// </summary>
	public class RaceGroupDef : Def
	{
		public List<string> raceNames = null;
		public List<string> pawnKindNames = null;

		public List<PartAdder> partAdders;
		public List<string> anuses = null;
		public List<float> chanceanuses = null;
		public List<string> femaleBreasts = null;
		public List<float> chancefemaleBreasts = null;
		public List<string> femaleGenitals = null;
		public List<float> chancefemaleGenitals = null;
		public List<string> maleBreasts = null;
		public List<float> chancemaleBreasts = null;
		public List<string> maleGenitals = null;
		public List<float> chancemaleGenitals = null;

		public List<string> hybridRaceParents = null;
		public List<string> hybridChildKindDef = null;

		public List<string> tags = null;
		public bool hasSingleGender = false;
		public bool hasSexNeed = true;
		public bool hasFertility = true;
		public bool hasPregnancy = true;
		public bool oviPregnancy = false;
		public bool ImplantEggs = false;
		public bool HasUdder = false;
		[Obsolete("isDemon is obsolete, use tags instead.")]
		public bool isDemon = false;
		[Obsolete("isSlime is obsolete, use tags instead.")]
		public bool isSlime = false;
		public float raceSexDrive = 1.0f;

		public string eggFertilizedDef = "RJW_EggFertilized";
		public string eggUnfertilizedDef = "RJW_EggUnfertilized";
		public float eggProgressUnfertilizedMax = 1.0f;
		public float eggLayIntervalDays = 3.5f;

		//public float eggCountRange = 3.5f;
		//public float eggFertilizationCountMax = 3.5f;
		//public float eggLayFemaleOnly = 3.5f;

		public List<string> GetRacePartDefNames(SexPartType sexPartType)
		{
			return sexPartType switch
			{
				SexPartType.Anus => anuses,
				SexPartType.FemaleBreast => femaleBreasts,
				SexPartType.FemaleGenital => femaleGenitals,
				SexPartType.MaleBreast => maleBreasts,
				SexPartType.MaleGenital => maleGenitals,
				_ => throw new ApplicationException($"Unrecognized sexPartType: {sexPartType}"),
			};
		}

		public List<float> GetChances(SexPartType sexPartType)
		{
			return sexPartType switch
			{
				SexPartType.Anus => chanceanuses,
				SexPartType.FemaleBreast => chancefemaleBreasts,
				SexPartType.FemaleGenital => chancefemaleGenitals,
				SexPartType.MaleBreast => chancemaleBreasts,
				SexPartType.MaleGenital => chancemaleGenitals,
				_ => throw new ApplicationException($"Unrecognized sexPartType: {sexPartType}"),
			};
		}
	}
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;

namespace rjw
{
	/// <summary>
	/// Defines how to create a single sex part on a newly created pawn.
	/// </summary>
	public class RacePartDef : Def
	{
		public bool IsNone => string.IsNullOrEmpty(hediffName);
		public static readonly RacePartDef None = new RacePartDef();

		/// <summary>
		/// The name of the hediff to create.
		/// Doesn't use the hediff directly because that causes issues when another mod wants to
		/// create and reference custom parts inheriting from rjw base defs.
		/// </summary>
		public string hediffName;
		public string fluidType;
		public float? fluidModifier;
		public SimpleCurve severityCurve;

		public bool TryGetHediffDef(out HediffDef hediffDef)
		{
			hediffDef = DefDatabase<HediffDef>.GetNamedSilentFail(hediffName);
			if (hediffDef == null)
			{
				ModLog.Error($"Could not find a HediffDef named {hediffName} referenced by RacePartDef named {defName}.");
				return false;
			}
			else
			{
				return true;
			}
		}
	}
}


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

namespace rjw
{
	public class RaceTag
	{
		// I only created tags for RaceGroupDef properties that seemed like keywords (like slime) rather than behavior (like oviPregnancy).
		public readonly static RaceTag Chitin = new RaceTag("Chitin");
		public readonly static RaceTag Demon = new RaceTag("Demon");
		public readonly static RaceTag Feathers = new RaceTag("Feathers");
		public readonly static RaceTag Fur = new RaceTag("Fur");
		public readonly static RaceTag Plant = new RaceTag("Plant");
		public readonly static RaceTag Robot = new RaceTag("Robot");
		public readonly static RaceTag Scales = new RaceTag("Scales");
		public readonly static RaceTag Skin = new RaceTag("Skin");
		public readonly static RaceTag Slime = new RaceTag("Slime");

		public string Key { get; }

		RaceTag(string key)
		{
			Key = key;
		}

		/// <summary>
		/// For backwards compatability only. Shouldn't add more special cases here.
		/// </summary>
		public bool DefaultWhenNoRaceGroupDef(Pawn pawn)
		{
			if (this == Demon)
			{
				return xxx.is_demon(pawn);
			}
			else if (this == Slime)
			{
				return xxx.is_slime(pawn);
			}
			else if (this == Skin)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Just a simplest form of passing data from xml to the code
	/// </summary>
	class StringListDef : Def
	{
		public List<string> strings = new List<string>();
	}
}


code:
///Better not leave it be, this mod is not intended to reimpelement base functionality and break other mods by that.
//using Harmony;
//using RimWorld;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Reflection;
//using System.Text;
//using UnityEngine;
//using Verse;
//using Verse.Sound;

//namespace rjw.Source.Common
//{
//	public static class ExpandedPawnCharacterCard
//	{
//		/// <summary>
//		/// Better to leave it be, since it doesn't affect anything much.
//		/// </summary>
//		public static float cardX = 570f;  // vanilla is 570

//		/// <summary>
//		/// Basically, you want to increase this value if you want character info card be taller (thus allowing to have more
//		/// traits and skills shown). Height is in pixels, increase by ~25 pixels for each additional row of skill/trait.
//		/// </summary>
//		public static float cardY = 470f;  // vanilla is 470

//		[HarmonyPatch(typeof(CharacterCardUtility), "DrawCharacterCard", new[] { typeof(Rect), typeof(Pawn), typeof(Action), typeof(Rect), })]
//		public static class CharacterCardUtilityPatch
//		{
//			private static IEnumerable<WorkTags> WorkTagsFrom(WorkTags tags)
//			{
//				foreach (WorkTags workTag in tags.GetAllSelectedItems<WorkTags>())
//				{
//					if (workTag != WorkTags.None)
//					{
//						yield return workTag;
//					}
//				}
//			}

//			[HarmonyPrefix]
//			public static bool DrawCharacterCardP(ref Rect rect, ref Pawn pawn, ref Action randomizeCallback, ref Rect creationRect)
//			{
//				rect.position = new Vector2(17f, 17f);
//				rect.size = new Vector2(cardX, cardY);
//				bool flag = randomizeCallback != null;
//				GUI.BeginGroup((!flag) ? rect : creationRect);
//				Rect rectLabel = new Rect(0f, 0f, 300f, 30f);
//				NameTriple nameTriple = pawn.Name as NameTriple;
//				if (flag && nameTriple != null)
//				{
//					Rect rect3 = new Rect(rectLabel);
//					rect3.width *= 0.333f;
//					Rect rect4 = new Rect(rectLabel);
//					rect4.width *= 0.333f;
//					rect4.x += rect4.width;
//					Rect rect5 = new Rect(rectLabel);
//					rect5.width *= 0.333f;
//					rect5.x += rect4.width * 2f;
//					string first = nameTriple.First;
//					string nick = nameTriple.Nick;
//					string last = nameTriple.Last;
//					CharacterCardUtility.DoNameInputRect(rect3, ref first, 12);
//					if (nameTriple.Nick == nameTriple.First || nameTriple.Nick == nameTriple.Last)
//					{
//						GUI.color = new Color(1f, 1f, 1f, 0.5f);
//					}
//					CharacterCardUtility.DoNameInputRect(rect4, ref nick, 9);
//					GUI.color = Color.white;
//					CharacterCardUtility.DoNameInputRect(rect5, ref last, 12);
//					if (nameTriple.First != first || nameTriple.Nick != nick || nameTriple.Last != last)
//					{
//						pawn.Name = new NameTriple(first, nick, last);
//					}
//					TooltipHandler.TipRegion(rect3, "FirstNameDesc".Translate());
//					TooltipHandler.TipRegion(rect4, "ShortIdentifierDesc".Translate());
//					TooltipHandler.TipRegion(rect5, "LastNameDesc".Translate());
//				}
//				else
//				{
//					rectLabel.width = 999f;
//					Text.Font = GameFont.Medium;
//					Widgets.Label(rectLabel, pawn.Name.ToStringFull);
//					Text.Font = GameFont.Small;
//				}
//				if (randomizeCallback != null)
//				{
//					Rect rectRandomise = new Rect(creationRect.width - 24f - 100f, 0f, 100f, rectLabel.height);
//					if (Widgets.ButtonText(rectRandomise, "Randomize".Translate(), true, false, true))
//					{
//						SoundDefOf.TickTiny.PlayOneShotOnCamera(null);
//						randomizeCallback();
//					}
//					UIHighlighter.HighlightOpportunity(rectRandomise, "RandomizePawn");
//				}
//				if (flag)
//				{
//					Widgets.InfoCardButton(creationRect.width - 24f, 0f, pawn);
//				}
//				else if (!pawn.health.Dead)
//				{
//					float num = CharacterCardUtility.PawnCardSize.x - 85f;
//					if ((pawn.Faction == Faction.OfPlayer || pawn.IsPrisonerOfColony) && pawn.Spawned)
//					{
//						Rect rectBanish = new Rect(num, 0f, 30f, 30f);
//						TooltipHandler.TipRegion(rectBanish, PawnBanishUtility.GetBanishButtonTip(pawn));
//						if (Widgets.ButtonImage(rectBanish, ContentFinder<Texture2D>.Get("UI/Buttons/Banish", true)))
//						{
//							if (pawn.Downed)
//							{
//								Messages.Message("MessageCantBanishDownedPawn".Translate(new object[]
//								{
//								pawn.LabelShort
//								}).AdjustedFor(pawn), pawn, MessageTypeDefOf.RejectInput);
//							}
//							else
//							{
//								PawnBanishUtility.ShowBanishPawnConfirmationDialog(pawn);
//							}
//						}
//						num -= 40f;
//					}
//					if (pawn.IsColonist)
//					{
//						Rect rect8 = new Rect(num, 0f, 30f, 30f);
//						TooltipHandler.TipRegion(rect8, "RenameColonist".Translate());
//						if (Widgets.ButtonImage(rect8, ContentFinder<Texture2D>.Get("UI/Buttons/Rename", true)))
//						{
//							Find.WindowStack.Add(new Dialog_ChangeNameTriple(pawn));
//						}
//						num -= 40f;
//					}
//				}
//				string label = pawn.MainDesc(true);
//				Rect rectMainDesc = new Rect(0f, 45f, rect.width, 60f);
//				Widgets.Label(rectMainDesc, label);
//				Pawn p = pawn;
//				TooltipHandler.TipRegion(rectMainDesc, () => p.ageTracker.AgeTooltipString, 6873641);
//				Rect positionLeftHalf = new Rect(0f, 100f, 250f, cardY);
//				Rect positionRightHalf = new Rect(positionLeftHalf.xMax, 100f, 258f, cardY);
//				GUI.BeginGroup(positionLeftHalf);
//				float currentY = 0f;
//				Text.Font = GameFont.Medium;
//				Widgets.Label(new Rect(0f, 0f, 200f, 30f), "Backstory".Translate());
//				currentY += 30f;
//				Text.Font = GameFont.Small;
//				foreach (BackstorySlot backstorySlot in Enum.GetValues(typeof(BackstorySlot)))
//				{
//					Backstory backstory = pawn.story.GetBackstory(backstorySlot);
//					if (backstory != null)
//					{
//						Rect rect10 = new Rect(0f, currentY, positionLeftHalf.width, 24f);
//						if (Mouse.IsOver(rect10))
//						{
//							Widgets.DrawHighlight(rect10);
//						}
//						TooltipHandler.TipRegion(rect10, backstory.FullDescriptionFor(pawn));
//						Text.Anchor = TextAnchor.MiddleLeft;
//						string str = (backstorySlot != BackstorySlot.Adulthood) ? "Childhood".Translate() : "Adulthood".Translate();
//						Widgets.Label(rect10, str + ":");
//						Text.Anchor = TextAnchor.UpperLeft;
//						Rect rect11 = new Rect(rect10);
//						rect11.x += 90f;
//						rect11.width -= 90f;
//						string title = backstory.Title;
//						Widgets.Label(rect11, title);
//						currentY += rect10.height + 2f;
//					}
//				}
//				currentY += 25f;
//				Text.Font = GameFont.Small;
//				Widgets.Label(new Rect(0f, currentY, 200f, 30f), "IncapableOf".Translate());
//				currentY += 30f;
//				Text.Font = GameFont.Small;
//				StringBuilder stringBuilder = new StringBuilder();
//				WorkTags combinedDisabledWorkTags = pawn.story.CombinedDisabledWorkTags;
//				if (combinedDisabledWorkTags == WorkTags.None)
//				{
//					stringBuilder.Append("(" + "NoneLower".Translate() + "), ");
//				}
//				else
//				{
//					List<WorkTags> list = WorkTagsFrom(combinedDisabledWorkTags).ToList<WorkTags>();
//					bool flag2 = true;
//					foreach (WorkTags current in list)
//					{
//						if (flag2)
//						{
//							stringBuilder.Append(current.LabelTranslated().CapitalizeFirst());
//						}
//						else
//						{
//							stringBuilder.Append(current.LabelTranslated());
//						}
//						stringBuilder.Append(", ");
//						flag2 = false;
//					}
//				}
//				string text = stringBuilder.ToString();
//				text = text.Substring(0, text.Length - 2);
//				Rect rect12 = new Rect(0f, currentY, positionLeftHalf.width, 999f);
//				Widgets.Label(rect12, text);
//				currentY += 100f;
//				Text.Font = GameFont.Medium;
//				Widgets.Label(new Rect(0f, currentY, 200f, 30f), "Traits".Translate());
//				currentY += 30f;
//				Text.Font = GameFont.Small;
//				for (int i = 0; i < pawn.story.traits.allTraits.Count; i++)
//				{
//					Trait trait = pawn.story.traits.allTraits[i];
//					Rect rectCurrentTrait = new Rect(0f, currentY, positionLeftHalf.width, 24f);
//					if (Mouse.IsOver(rectCurrentTrait))
//					{
//						Widgets.DrawHighlight(rectCurrentTrait);
//					}
//					Widgets.Label(rectCurrentTrait, trait.LabelCap);
//					currentY += rectCurrentTrait.height + 2f;
//					Trait trLocal = trait;
//					TipSignal tip = new TipSignal(() => trLocal.TipString(p), (int)currentY * 37);
//					TooltipHandler.TipRegion(rectCurrentTrait, tip);
//				}
//				GUI.EndGroup();
//				GUI.BeginGroup(positionRightHalf);
//				Text.Font = GameFont.Medium;
//				Widgets.Label(new Rect(0f, 0f, 200f, 30f), "Skills".Translate());
//				SkillUI.SkillDrawMode mode;
//				if (Current.ProgramState == ProgramState.Playing)
//				{
//					mode = SkillUI.SkillDrawMode.Gameplay;
//				}
//				else
//				{
//					mode = SkillUI.SkillDrawMode.Menu;
//				}
//				SkillUI.DrawSkillsOf(pawn, new Vector2(0f, 35f), mode);
//				GUI.EndGroup();
//				GUI.EndGroup();

//				return false;
//			}
//		}
//		[HarmonyPatch(typeof(ITab_Pawn_Character), "FillTab")]
//		public static class ITab_Pawn_CharacterPatch
//		{
//			[HarmonyPrefix]
//			public static bool FillTabP(ITab_Pawn_Character __instance)
//			{

//				FieldInfo fi = typeof(ITab_Pawn_Character).GetField("size", Unprivater.flags);
//				fi.SetValue(__instance, new Vector2(cardX+34f, cardY+34f));

//				var p = Unprivater.GetProtectedProperty<Pawn>("PawnToShowInfoAbout", __instance);

//				Rect rect = new Rect(17f, 17f, 570f, cardY);
//				CharacterCardUtility.DrawCharacterCard(rect, p, null, default(Rect));

//				return false;
//			}
//		}

//	}
//}


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

namespace rjw
{
	public static class BreastSize_Helper
	{
		public static int NipplesOnlyBreastSize = -1;

		static HediffDef[] BreastsInOrder = new[] {
			//Genital_Helper.flat_breasts,
			//Genital_Helper.small_breasts,
			Genital_Helper.average_breasts,
			//Genital_Helper.large_breasts,
			//Genital_Helper.huge_breasts
		};

		public static int MaxSize = BreastsInOrder.Length - 1;

		static IDictionary<HediffDef, int> SizeByHediffDef = BreastsInOrder
			.Select((hed, i) => new { hed, i })
			.ToDictionary(pair => pair.hed, pair => pair.i);

		/// <summary>
		/// Returns true and sets size if pawn has natural breasts.
		/// Otherwise returns false.
		/// </summary>
		public static bool TryGetBreastSize(Pawn pawn, out int size)
		{
			return TryGetBreastSize(pawn, out size, out var hediff);
		}

		/// <summary>
		/// Returns true and sets size and hediff if pawn has natural breasts.
		/// Hediff will still be null for nipples only.
		/// Otherwise returns false.
		/// </summary>
		public static bool TryGetBreastSize(Pawn pawn, out int size, out Hediff hediff)
		{
			var chest = Genital_Helper.get_breastsBPR(pawn);

			if (pawn.health.hediffSet.PartIsMissing(chest))
			{
				size = 0;
				hediff = null;
				return false;
			}

			foreach(var candidate_hediff in pawn.health.hediffSet.hediffs)
			{
				if (SizeByHediffDef.TryGetValue(candidate_hediff.def, out size))
				{
					hediff = candidate_hediff;
					return true;
				}
			}

			if (HasNipplesOnly(pawn, chest))
			{
				size = NipplesOnlyBreastSize;
				hediff = null;
				return true;
			}

			size = 0;
			hediff = null;
			return false;
		}

		public static int GetSize(HediffDef hediffDef)
		{
			return SizeByHediffDef[hediffDef];
		}

		public static HediffDef GetHediffDef(int size)
		{
			return BreastsInOrder[size];
		}

		public static bool IsMammal(Pawn pawn)
		{
			// In theory should not apply to lizards etc either.
			return !xxx.is_mechanoid(pawn);
		}

		/// <summary>
		/// Returns true if pawn has nipples but no breast development or implants.
		/// </summary>
		public static bool HasNipplesOnly(Pawn pawn, BodyPartRecord chest)
		{
			var alreadyHasBoobs = pawn.health.hediffSet.hediffs.Any(hediff =>
				hediff.Part == chest &&
				(hediff is Hediff_Implant || hediff is Hediff_AddedPart));
			return IsMammal(pawn) && !alreadyHasBoobs;
		}

		/// <summary>
		/// Adds two bruises with amount up to the given max.
		/// </summary>
		[SyncMethod]
		public static void HurtBreasts(Pawn pawn, BodyPartRecord part, int max)
		{
			if (max <= 0)
			{
				return;
			}

			// Two bruises.
			for (var i = 0; i < 2; i++)
			{
				pawn.TakeDamage(new DamageInfo(
					DamageDefOf.Blunt,
					Rand.RangeInclusive(max / 4, max),
					999f,
					-1f,
					null,
					part,
					null,
					DamageInfo.SourceCategory.ThingOrUnknown,
					null));
			}
		}
	}
}


code:
//#define TESTMODE // Uncomment to enable logging.

using Verse;
using Verse.AI;
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using System.Diagnostics;
using Multiplayer.API;

namespace rjw
{
	/// <summary>
	/// Helper for sex with animals
	/// </summary>
	public class BreederHelper
	{
		public const int max_animals_at_once = 1; // lets not forget that the purpose is procreation, not sodomy

		[Conditional("TESTMODE")]
		private static void DebugText(string msg)
		{
			ModLog.Message(msg);
		}

		//animal try to find best designated pawn to breed
		[SyncMethod]
		public static Pawn find_designated_breeder(Pawn pawn, Map m)
		{
			if (!DesignatorsData.rjwBreeding.Any())
				return null;

			DebugText("BreederHelper::find_designated_breeder( " + xxx.get_pawnname(pawn) + " ) called");

			float min_fuckability = 0.10f;							// Don't rape pawns with <10% fuckability
			float avg_fuckability = 0f;								// Average targets fuckability, choose target higher than that
			var valid_targets = new Dictionary<Pawn, float>();		// Valid pawns and their fuckability
			Pawn chosentarget = null;                               // Final target pawn

			DebugText(" breeder.Faction( " + pawn.Faction + " )");
			if (pawn.Faction == null)// HostileTo causes error on fresh colony(w/o name)
				return null;

			DebugText(" DesignatorsData.rjwBreeding.Count( " + DesignatorsData.rjwBreeding.Count() + " )");
			IEnumerable<Pawn> targets = DesignatorsData.rjwBreeding.Where(x
				=> x != pawn
				&& xxx.is_not_dying(x)
				&& xxx.can_get_raped(x)
				&& !x.IsForbidden(pawn)
				&& !x.Suspended
				&& !x.HostileTo(pawn)
				&& !(x.IsPregnant() && xxx.is_animal(x))
				&& pawn.CanReserveAndReach(x, PathEndMode.Touch, Danger.Some, max_animals_at_once)
				&& ((RJWSettings.bestiality_enabled && xxx.is_human(x)) || (RJWSettings.animal_on_animal_enabled && xxx.is_animal(x)))
				);

			DebugText(" initial targets( " + targets.Count() + " )");

			var partBPR = Genital_Helper.get_genitalsBPR(pawn);
			var parts = Genital_Helper.get_PartsHediffList(pawn, partBPR);

			foreach (Pawn target in targets)
			{
				DebugText(" Checking target " + target.kindDef.race.defName.ToLower());
				if (!xxx.cells_to_target_rape(pawn, target.Position))
					continue;// too far

				var fuc = SexAppraiser.would_fuck(pawn, target, invert_opinion: true, ignore_gender: (Genital_Helper.has_penis_fertile(pawn, parts) || Genital_Helper.has_penis_infertile(pawn, parts) || xxx.is_insect(pawn)));
				DebugText(" target score( " + xxx.get_pawnname(pawn) + " -> " + xxx.get_pawnname(target) + " (" + fuc.ToString() + " / " + min_fuckability.ToString() + ")");

				if (fuc > min_fuckability)
					if (xxx.can_path_to_target(pawn, target.Position))
						valid_targets.Add(target, fuc);
			}

			DebugText(" valid_targets( " + valid_targets.Count() + " )");

			if (valid_targets.Any())
			{
				//avg_fuckability = valid_targets.Average(x => x.Value);

				// choose pawns to fuck with above average fuckability
				var valid_targetsFilteredAnimals = valid_targets.Where(x => x.Value >= avg_fuckability);

				if (valid_targetsFilteredAnimals.Any())
					chosentarget = valid_targetsFilteredAnimals.RandomElement().Key;
			}

			DebugText(" chosentarget( " + xxx.get_pawnname(chosentarget) + " )");
			return chosentarget;
		}

		//animal or human try to find animals to breed (non designation)
		//public static Pawn find_breeder_animal(Pawn pawn, Map m, bool SameRace = true)
		[SyncMethod]
		public static Pawn find_breeder_animal(Pawn pawn, Map m)
		{
			DebugText("BreederHelper::find_breeder_animal( " + xxx.get_pawnname(pawn) + " ) called");

			float min_fuckability = 0.10f;							// Don't rape pawns with <10% fuckability
			float avg_fuckability = 0f;								// Average targets fuckability, choose target higher than that
			var valid_targets = new Dictionary<Pawn, float>();		// Valid pawns and their fuckability
			Pawn chosentarget = null;                               // Final target pawn

			DebugText(" m.mapPawns.AllPawnsSpawned.Count( " + m.mapPawns.AllPawnsSpawned.Count() + " )");
			//Pruning initial pawn list.
			IEnumerable<Pawn> targets = m.mapPawns.AllPawnsSpawned.Where(x
				=> x != pawn
				&& xxx.is_animal(x)
				&& xxx.can_get_raped(x)
				&& !x.IsForbidden(pawn)
				&& !x.Suspended
				&& !x.HostileTo(pawn)
				&& pawn.CanReserveAndReach(x, PathEndMode.Touch, Danger.Some, max_animals_at_once)
				&& ((RJWSettings.bestiality_enabled && xxx.is_human(pawn)) || (RJWSettings.animal_on_animal_enabled && xxx.is_animal(pawn)))
				//&& SameRace ? pawn.kindDef.race == x.kindDef.race : true
				);

			DebugText(" initial targets( " + targets.Count() + " )");

			if (targets.Any())
			{
				var partBPR = Genital_Helper.get_genitalsBPR(pawn);
				var parts = Genital_Helper.get_PartsHediffList(pawn, partBPR);

				//filter pawns for female, who can fuck her
				//not sure if faction check should be but w/e
				if (!Genital_Helper.has_penis_fertile(pawn, parts) && !Genital_Helper.has_penis_infertile(pawn, parts) && (Genital_Helper.has_vagina(pawn, parts) || Genital_Helper.has_anus(pawn)))
				{
					targets = targets.Where(x => xxx.can_fuck(x) && x.Faction == pawn.Faction);
				}

				//for humans, animals dont have need - always = 3f
				//if not horny, seek only targets with safe temp
				if (xxx.need_some_sex(pawn) < 3.0f)
				{
					targets = targets.Where(x => pawn.CanReach(x, PathEndMode.Touch, Danger.None));
				}

				//Used for interspecies animal-on-animal.
				//Animals will only go for targets they can see.
				if (xxx.is_animal(pawn))
				{
					targets = targets.Where(x => pawn.CanSee(x) && pawn.def.defName != x.def.defName);
				}
				else
				{
					// Pickier about the targets if the pawn has no prior experience.
					if (pawn.records.GetValue(xxx.CountOfSexWithAnimals) < 3 && !xxx.is_zoophile(pawn))
					{
						min_fuckability *= 2f;
					}

					if (xxx.is_frustrated(pawn))
					{   // Less picky when frustrated...
						min_fuckability *= 0.6f;
					}
					else if (!xxx.is_hornyorfrustrated(pawn))
					{   // ...and far more picky when satisfied.
						min_fuckability *= 2.5f;
					}
				}
			}

			if (!targets.Any())
			{
				DebugText(" valid_targets( " + targets.Count() + " )");
				return null; //None found.
			}

			foreach (Pawn target in targets)
			{
				DebugText(" Checking target " + target.kindDef.race.defName.ToLower());

				if (!xxx.cells_to_target_rape(pawn, target.Position))
					continue;// too far

				float fuc = SexAppraiser.would_fuck_animal(pawn, target); // 0.0 to ~3.0, orientation checks etc.
				DebugText(" target score( " + xxx.get_pawnname(pawn) + " -> " + xxx.get_pawnname(target) + " (" + fuc.ToString() + " / " + min_fuckability.ToString() + ")");

				if (fuc > min_fuckability)
					if (xxx.can_path_to_target(pawn, target.Position))
						valid_targets.Add(target, fuc);
			}

			DebugText(" valid_targets( " + valid_targets.Count() + " )");
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			if (valid_targets.Any())
			{
				avg_fuckability = valid_targets.Average(x => x.Value);

				// choose pawns to fuck with above average fuckability
				var valid_targetsFilteredAnimals = valid_targets.Where(x => x.Value >= avg_fuckability);

				if (valid_targetsFilteredAnimals.Any())
					chosentarget = valid_targetsFilteredAnimals.RandomElement().Key;
			}

			DebugText(" chosentarget( " + xxx.get_pawnname(chosentarget) + " )");
			return chosentarget;
		}
	}
}