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

namespace rjw.MainTab
{
	public class RJW_PawnTable_Humanlikes : PawnTable_PlayerPawns
	{
		public RJW_PawnTable_Humanlikes(PawnTableDef def, Func<IEnumerable<Pawn>> pawnsGetter, int uiWidth, int uiHeight) : base(def, pawnsGetter, uiWidth, uiHeight) { }

		//default sorting
		protected override IEnumerable<Pawn> LabelSortFunction(IEnumerable<Pawn> input)
		{
			//return input.OrderBy(p => p.Name);
			foreach (Pawn p in input)
				p.UpdatePermissions();
			return input.OrderByDescending(p => (p.IsPrisonerOfColony || p.IsSlaveOfColony) != false).ThenBy(p => xxx.get_pawnname(p));
			//return input.OrderByDescending(p => (p.IsPrisonerOfColony || p.IsSlaveOfColony) != false).ThenBy(p => (p.Name.ToStringShort.Colorize(Color.yellow)));
			//return input.OrderBy(p => xxx.get_pawnname(p));
		}

		protected override IEnumerable<Pawn> PrimarySortFunction(IEnumerable<Pawn> input)
		{
			foreach (Pawn p in input)
				p.UpdatePermissions();
			return input;
			//return base.PrimarySortFunction(input);
		}

		//public static IEnumerable<Pawn> FilterPawns()
		//{
		//	return Find.CurrentMap.mapPawns.PawnsInFaction(Faction.OfPlayer).Where(p => xxx.is_animal(p));
		//}
	}
}


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

namespace rjw
{
	public class Recipe_InstallAnus : Recipe_InstallPrivates
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			var gen_blo = Genital_Helper.anus_blocked(p);
			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if ((!gen_blo) || (part != xxx.anus))
					yield return part;
		}
	}
}

repo_name: Euclidean/rjw

license: mit


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

namespace rjw
{
	public class Recipe_InstallBreasts : Recipe_InstallPrivates
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			var gen_blo = Genital_Helper.breasts_blocked(p);
			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if ((!gen_blo) || (part != xxx.breasts))
					yield return part;
		}
	}
}


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

namespace rjw
{
	public class Recipe_InstallGenitals : Recipe_InstallPrivates
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			var gen_blo = Genital_Helper.genitals_blocked(p);
			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if ((!gen_blo) || (part != xxx.genitals))
					yield return part;

		}
	}
}


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

namespace rjw
{
	public class Recipe_InstallPart : rjw_CORE_EXPOSED.Recipe_InstallOrReplaceBodyPart
	{
		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			GenderHelper.Sex before = GenderHelper.GetSex(pawn);

			base.ApplyOnPawn(pawn, part, billDoer, ingredients, bill);

			GenderHelper.Sex after = GenderHelper.GetSex(pawn);

			GenderHelper.ChangeSex(pawn, before, after);
		}
	}

	public class Recipe_InstallGenitals : Recipe_InstallPart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.genitals_blocked(p) || xxx.is_slime(p));//|| xxx.is_demon(p)
		}
	}

	public class Recipe_InstallBreasts : Recipe_InstallPart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.breasts_blocked(p) || xxx.is_slime(p));//|| xxx.is_demon(p)
		}
	}

	public class Recipe_InstallAnus : Recipe_InstallPart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.anus_blocked(p) || xxx.is_slime(p));//|| xxx.is_demon(p)
		}
	}
}


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

namespace rjw
{
	public class Recipe_GrowBreasts : Recipe_Surgery
	{
		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
			}

			var oldBoobs = pawn.health.hediffSet.hediffs.FirstOrDefault(hediff => hediff.def == bill.recipe.removesHediff);
			var newBoobs = bill.recipe.addsHediff;
			var newSize = BreastSize_Helper.GetSize(newBoobs);

			GenderHelper.ChangeSex(pawn, () =>
			{
				BreastSize_Helper.HurtBreasts(pawn, part, 3 * (newSize - 1));
				if (pawn.health.hediffSet.PartIsMissing(part))
				{
					return;
				}
				if (oldBoobs != null)
				{
					pawn.health.RemoveHediff(oldBoobs);
				}
				pawn.health.AddHediff(newBoobs, part);
			});
		}

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipeDef)
		{
			yield break;
			var chest = Genital_Helper.get_breastsBPR(pawn);

			if (pawn.health.hediffSet.PartIsMissing(chest)
				|| Genital_Helper.breasts_blocked(pawn))
			{
				yield break;
			}

			var old = recipeDef.removesHediff;
			if (old == null ? BreastSize_Helper.HasNipplesOnly(pawn, chest) : pawn.health.hediffSet.HasHediff(old, chest))
			{
				yield return chest;
			}
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Removes heddifs (restraints/cocoon)
	/// </summary>
	public class Recipe_RemoveRestraints : Recipe_RemoveHediff
	{
		public override bool AvailableOnNow(Thing pawn, BodyPartRecord part = null)
		{
			return true;
		}

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			List<Hediff> allHediffs = pawn.health.hediffSet.hediffs;
			int i = 0;
			while (true)
			{
				if (i >= allHediffs.Count)
				{
					yield break;
				}
				if (allHediffs[i].def == recipe.removesHediff && allHediffs[i].Visible)
				{
					break;
				}
				i++;
			}

			yield return allHediffs[i].Part;
		}
	}
}


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

namespace rjw
{
	public class Recipe_ShrinkBreasts : Recipe_Surgery
	{
		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
			}

			if (!BreastSize_Helper.TryGetBreastSize(pawn, out var oldSize))
			{
				throw new ApplicationException("Recipe_ShrinkBreasts could not find any breasts to shrink.");
			}

			var oldBoobs = pawn.health.hediffSet.GetFirstHediffOfDef(BreastSize_Helper.GetHediffDef(oldSize));
			var newSize = oldSize - 1;
			var newBoobs = BreastSize_Helper.GetHediffDef(newSize);

			// I can't figure out how to spawn a stack of 2 meat.
			for (var i = 0; i < 2; i++)
			{
				GenSpawn.Spawn(pawn.RaceProps.meatDef, billDoer.Position, billDoer.Map);
			}

			GenderHelper.ChangeSex(pawn, () =>
			{
				BreastSize_Helper.HurtBreasts(pawn, part, 5);
				if (pawn.health.hediffSet.PartIsMissing(part))
				{
					return;
				}
				pawn.health.RemoveHediff(oldBoobs);
				pawn.health.AddHediff(newBoobs, part);
			});
		}

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipeDef)
		{
			yield break;
			var chest = Genital_Helper.get_breastsBPR(pawn);

			if (Genital_Helper.breasts_blocked(pawn))
			{
				yield break;
			}

			if (BreastSize_Helper.TryGetBreastSize(pawn, out var size)
				//&& size > BreastSize_Helper.GetSize(Genital_Helper.flat_breasts))
				)
			{
				yield return chest;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_RemoveAnus : Recipe_RemovePart
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			if (Genital_Helper.has_anus(p))
			{
				bool blocked = Genital_Helper.anus_blocked(p) || xxx.is_slime(p);//|| xxx.is_demon(p)

				foreach (BodyPartRecord part in p.health.hediffSet.GetNotMissingParts())
					if (r.appliedOnFixedBodyParts.Contains(part.def) && (!blocked))
						yield return part;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_RemoveBreasts : Recipe_RemovePart
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			if (Genital_Helper.has_breasts(p))
			{
				bool blocked = Genital_Helper.breasts_blocked(p) || xxx.is_slime(p);//|| xxx.is_demon(p)

				foreach (BodyPartRecord part in p.health.hediffSet.GetNotMissingParts())
					if (r.appliedOnFixedBodyParts.Contains(part.def) && (!blocked))
						yield return part;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_RemoveGenitals : Recipe_RemovePart
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			if (Genital_Helper.has_genitals(p))
			{
				bool blocked = Genital_Helper.genitals_blocked(p) || xxx.is_slime(p);//|| xxx.is_demon(p)

				foreach (BodyPartRecord part in p.health.hediffSet.GetNotMissingParts())
					if (r.appliedOnFixedBodyParts.Contains(part.def) && (!blocked))
						yield return part;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_RemovePart : rjw_CORE_EXPOSED.Recipe_RemoveBodyPart
	{
		// Quick and dirty method to guess whether the player is harvesting the genitals or amputating them
		// due to infection. The core code can't do this properly because it considers the private part
		// hediffs as "unclean".
		public override bool blocked(Pawn p)
		{
			return xxx.is_slime(p);//|| xxx.is_demon(p)
		}

		public bool is_harvest(Pawn p, BodyPartRecord part)
		{
			foreach (Hediff hed in p.health.hediffSet.hediffs)
			{
				if ((hed.Part?.def == part.def) && hed.def.isBad && (hed.Severity >= 0.70f))
					return false;
			}
			return true;
		}

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
			{
				if (r.appliedOnFixedBodyParts.Contains(part.def) && !blocked(p))
					yield return part;
			}
		}

		public override void ApplyOnPawn(Pawn p, BodyPartRecord part, Pawn doer, List<Thing> ingredients, Bill bill)
		{
			var har = is_harvest(p, part);

			base.ApplyOnPawn(p, part, doer, ingredients, bill);

			if (har)
			{
				if (!p.Dead)
				{
					//Log.Message("alive harvest " + part);
					ThoughtUtility.GiveThoughtsForPawnOrganHarvested(p, doer);
				}
				else
				{
					//Log.Message("dead harvest " + part);
					ThoughtUtility.GiveThoughtsForPawnExecuted(p, doer, PawnExecutionKind.OrganHarvesting);
				}
			}
		}

		public override string GetLabelWhenUsedOn(Pawn p, BodyPartRecord part)
		{
			return recipe.label.CapitalizeFirst();
		}
	}
	/*
	public class Recipe_RemovePenis : Recipe_RemovePart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.genitals_blocked(p)
				|| !(Genital_Helper.has_penis(p)
					&& Genital_Helper.has_penis_infertile(p)
					&& Genital_Helper.has_ovipositorF(p)));
		}
	}

	public class Recipe_RemoveVagina : Recipe_RemovePart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.genitals_blocked(p)
				|| !Genital_Helper.has_vagina(p));
		}
	}

	public class Recipe_RemoveGenitals : Recipe_RemovePart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.genitals_blocked(p)
				|| !Genital_Helper.has_genitals(p));
		}
	}

	public class Recipe_RemoveBreasts : Recipe_RemovePart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.breasts_blocked(p)
				|| !Genital_Helper.has_breasts(p));
		}
	}

	public class Recipe_RemoveAnus : Recipe_RemovePart
	{
		public override bool blocked(Pawn p)
		{
			return (Genital_Helper.anus_blocked(p)
				|| !Genital_Helper.has_anus(p));
		}
	}
	*/
}


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

namespace rjw
{
	public class Recipe_RemovePenis : Recipe_RemovePart
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			if (Genital_Helper.has_penis(p) || Genital_Helper.has_penis_infertile(p) || Genital_Helper.has_ovipositorF(p))
			{
				bool blocked = Genital_Helper.genitals_blocked(p) || xxx.is_slime(p);

				foreach (var part in p.health.hediffSet.GetNotMissingParts())
					if (r.appliedOnFixedBodyParts.Contains(part.def) && (!blocked))
						yield return part;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_RemoveUdder : Recipe_RemovePart
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{

			if (Genital_Helper.has_udder(p))
			{
				bool blocked = Genital_Helper.udder_blocked(p) || xxx.is_slime(p);//|| xxx.is_demon(p)

				foreach (BodyPartRecord part in p.health.hediffSet.GetNotMissingParts())
					if (r.appliedOnFixedBodyParts.Contains(part.def) && (!blocked))
						yield return part;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_RemoveVagina : Recipe_RemovePart
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			if (Genital_Helper.has_vagina(p) )
			{
				bool blocked = Genital_Helper.genitals_blocked(p) || xxx.is_slime(p);

				foreach (var part in p.health.hediffSet.GetNotMissingParts())
					if (r.appliedOnFixedBodyParts.Contains(part.def) && (!blocked))
						yield return part;
			}
		}
	}
}


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

namespace rjw
{
	public class Recipe_MakeFuta : rjw_CORE_EXPOSED.Recipe_AddBodyPart
	{
		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			GenderHelper.Sex before = GenderHelper.GetSex(pawn);

			base.ApplyOnPawn(pawn, part, billDoer, ingredients, bill);

			GenderHelper.Sex after = GenderHelper.GetSex(pawn);

			GenderHelper.ChangeSex(pawn, before, after);
		}
	}

	//Female to futa
	public class Recipe_MakeFutaF : Recipe_MakeFuta
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			var parts = p.GetGenitalsList();

			bool blocked = Genital_Helper.genitals_blocked(p) || xxx.is_slime(p); //|| xxx.is_demon(p);
			bool has_vag = Genital_Helper.has_vagina(p, parts);
			bool has_cock = Genital_Helper.has_penis_fertile(p, parts) || Genital_Helper.has_penis_infertile(p, parts) || Genital_Helper.has_ovipositorM(p, parts);

			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if (r.appliedOnFixedBodyParts.Contains(part.def) && !blocked && (has_vag && !has_cock))
					yield return part;
		}
	}

	//Male to futa
	public class Recipe_MakeFutaM : Recipe_MakeFuta
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			var parts = p.GetGenitalsList();

			bool blocked = Genital_Helper.genitals_blocked(p) || xxx.is_slime(p); //|| xxx.is_demon(p);
			bool has_vag = Genital_Helper.has_vagina(p, parts);
			bool has_cock = Genital_Helper.has_penis_fertile(p, parts) || Genital_Helper.has_penis_infertile(p, parts) || Genital_Helper.has_ovipositorM(p, parts);

			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if (r.appliedOnFixedBodyParts.Contains(part.def) && !blocked && (!has_vag && has_cock))
					yield return part;
		}
	}

	//TODO: maybe merge with above to make single recipe, but meh for now just copy-paste recipes or some filter to disable multiparts if normal part doesn't exist yet

	//add multi parts
	public class Recipe_AddMultiPart : Recipe_MakeFuta
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			//don't add artificial - peg, hydraulics, bionics, archo, ovi
			if (r.addsHediff.addedPartProps?.solid ?? false)
				yield break;

			//don't add if artificial parts present
			if (p.health.hediffSet.hediffs.Any((Hediff hed) =>
				(hed.Part != null) &&
				r.appliedOnFixedBodyParts.Contains(hed.Part.def) &&
				(hed.def.addedPartProps?.solid ?? false)))
				yield break;

			var parts = p.GetGenitalsList();

			//don't add if no ovi
			//if (Genital_Helper.has_ovipositorF(p, parts) || Genital_Helper.has_ovipositorM(p, parts))
			//	yield break;

			//don't add if same part type not present yet
			if (!Genital_Helper.has_vagina(p, parts) && r.defName.ToLower().Contains("vagina"))
				yield break;
			if (!Genital_Helper.has_penis_fertile(p, parts) && r.defName.ToLower().Contains("penis"))
				yield break;

			//cant install parts when part blocked, on slimes, on demons
			bool blocked = (xxx.is_slime(p) //|| xxx.is_demon(p)
				|| (Genital_Helper.genitals_blocked(p) && r.appliedOnFixedBodyParts.Contains(xxx.genitalsDef))
				|| (Genital_Helper.anus_blocked(p) && r.appliedOnFixedBodyParts.Contains(xxx.anusDef))
				|| (Genital_Helper.breasts_blocked(p) && r.appliedOnFixedBodyParts.Contains(xxx.breastsDef)));

			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if (r.appliedOnFixedBodyParts.Contains(part.def) && !blocked)
					yield return part;
		}
	}

	public class Recipe_AddSinglePart : Recipe_MakeFuta
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			//cant install parts when part blocked, on slimes, or when already has one
			bool blocked = xxx.is_slime(p) || p.health.hediffSet.HasHediff(r.addsHediff);

			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if (r.appliedOnFixedBodyParts.Contains(part.def) && !blocked)
					yield return part;
		}
	}

	public class Recipe_RemoveSinglePart : Recipe_MakeFuta
	{
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn p, RecipeDef r)
		{
			//cant install parts when part blocked, on slimes, or when already has one
			bool blocked = xxx.is_slime(p) || !p.health.hediffSet.HasHediff(r.removesHediff);

			foreach (BodyPartRecord part in base.GetPartsToApplyOn(p, r))
				if (r.appliedOnFixedBodyParts.Contains(part.def) && !blocked)
					yield return part;
		}
	}
}


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

namespace rjw
{
	public class PawnRelationWorker_Child_Beast : PawnRelationWorker_Child
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isChildOf(other, me);
		}
	}

	public class PawnRelationWorker_Sibling_Beast : PawnRelationWorker_Sibling
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isSiblingOf(other, me);
		}
	}
	public class PawnRelationWorker_HalfSibling_Beast : PawnRelationWorker_HalfSibling
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isHalfSiblingOf(other, me);
		}
	}
	public class PawnRelationWorker_Grandparent_Beast : PawnRelationWorker_Grandparent
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGrandchildOf(me, other);
		}
	}
	public class PawnRelationWorker_Grandchild_Beast : PawnRelationWorker_Grandchild
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGrandparentOf(me, other);  //if other isGrandchildOf of me, me is their grandparent
		}
	}
	public class PawnRelationWorker_NephewOrNiece_Beast : PawnRelationWorker_NephewOrNiece
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isUncleOrAuntOf(me, other);
		}
	}
	public class PawnRelationWorker_UncleOrAunt_Beast : PawnRelationWorker_UncleOrAunt
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isNephewOrNieceOf(me, other);
		}
	}

	public class PawnRelationWorker_Cousin_Beast : PawnRelationWorker_Cousin
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isCousinOf(me, other);
		}
	}

	public class PawnRelationWorker_GreatGrandparent_Beast : PawnRelationWorker_GreatGrandparent
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGreatGrandChildOf(me, other);
		}
	}

	public class PawnRelationWorker_GreatGrandchild_Beast : PawnRelationWorker_GreatGrandchild
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGreatGrandparentOf(me, other);
		}
	}

	public class PawnRelationWorker_GranduncleOrGrandaunt_Beast : PawnRelationWorker_GranduncleOrGrandaunt
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGrandnephewOrGrandnieceOf(me, other);
		}
	}

	public class PawnRelationWorker_GrandnephewOrGrandniece_Beast : PawnRelationWorker_GrandnephewOrGrandniece
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGreatUncleOrAuntOf(me, other);
		}
	}

	public class PawnRelationWorker_CousinOnceRemoved_Beast : PawnRelationWorker_CousinOnceRemoved
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isCousinOnceRemovedOf(me, other);
		}
	}

	public class PawnRelationWorker_SecondCousin_Beast : PawnRelationWorker_SecondCousin
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isSecondCousinOf(me, other);
		}
	}
	/*
	public class PawnRelationWorker_Kin_Beast : PawnRelationWorker_Kin
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (!xxx.is_animal(other) || me == other)
			{
				return false;
			}

			if (base.InRelation(me, other) == true)
			{
				return true;
			}
			return false;
		}
	}
	*/
}


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

namespace rjw
{
	public class PawnRelationWorker_Child_Humanlike : PawnRelationWorker_Child
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			if (base.InRelation(me, other) == true)
			{
				return true;
			}
			return false;
		}
	}

	public class PawnRelationWorker_Sibling_Humanlike : PawnRelationWorker_Sibling
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			if (base.InRelation(me, other) == true)
			{
				return true;
			}
			return false;
		}
	}
	public class PawnRelationWorker_HalfSibling_Humanlike : PawnRelationWorker_HalfSibling
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isHalfSiblingOf(other, me);
		}
	}
	public class PawnRelationWorker_Grandparent_Humanlike : PawnRelationWorker_Grandparent
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGrandchildOf(me, other);
		}
	}
	public class PawnRelationWorker_Grandchild_Humanlike : PawnRelationWorker_Grandchild
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGrandparentOf(me, other);
		}
	}
	public class PawnRelationWorker_NephewOrNiece_Humanlike : PawnRelationWorker_NephewOrNiece
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isUncleOrAuntOf(me, other);
		}
	}
	public class PawnRelationWorker_UncleOrAunt_Humanlike : PawnRelationWorker_UncleOrAunt
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isNephewOrNieceOf(me, other);
		}
	}

	public class PawnRelationWorker_Cousin_Humanlike : PawnRelationWorker_Cousin
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isCousinOf(me, other);
		}
	}

	public class PawnRelationWorker_GreatGrandparent_Humanlike : PawnRelationWorker_GreatGrandparent
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGreatGrandChildOf(me, other);
		}
	}

	public class PawnRelationWorker_GreatGrandchild_Humanlike : PawnRelationWorker_GreatGrandchild
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGreatGrandparentOf(me, other);
		}
	}

	public class PawnRelationWorker_GranduncleOrGrandaunt_Humanlike : PawnRelationWorker_GranduncleOrGrandaunt
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGrandnephewOrGrandnieceOf(me, other);
		}
	}

	public class PawnRelationWorker_GrandnephewOrGrandniece_Humanlike : PawnRelationWorker_GrandnephewOrGrandniece
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isGreatUncleOrAuntOf(me, other);
		}
	}

	public class PawnRelationWorker_CousinOnceRemoved_Humanlike : PawnRelationWorker_CousinOnceRemoved
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isCousinOnceRemovedOf(me, other);
		}
	}

	public class PawnRelationWorker_SecondCousin_Humanlike : PawnRelationWorker_SecondCousin
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			return RelationChecker.isSecondCousinOf(me, other);
		}
	}

	public class PawnRelationWorker_Kin_Humanlike : PawnRelationWorker_Kin
	{
		public override bool InRelation(Pawn me, Pawn other)
		{
			if (xxx.is_animal(other) || me == other)
			{
				return false;
			}

			if (base.InRelation(me, other) == true)
			{
				return true;
			}
			return false;
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Checks for relations, workaround for relation checks that rely on other relation checks, since the vanilla inRelation checks have been prefixed.
	///
	/// Return true if first pawn is specified relation of the second pawn
	///
	///  If "me" isRelationOf "other" return true
	/// </summary>
	///
	public static class RelationChecker
	{
		public static bool isChildOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (me.GetMother() != other)
			{
				return me.GetFather() == other;
			}
			//else "other" is mother
			return true;
		}

		public static bool isSiblingOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (me.GetMother() != null && me.GetFather() != null && me.GetMother() == other.GetMother() && me.GetFather() == other.GetFather())
			{
				return true;
			}
			return false;
		}

		public static bool isHalfSiblingOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (isSiblingOf(me, other))
			{
				return false;
			}
			return ((me.GetMother() != null && me.GetMother() == other.GetMother()) || (me.GetFather() != null && me.GetFather() == other.GetFather()));
		}

		public static bool isAnySiblingOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((me.GetMother() != null && me.GetMother() == other.GetMother()) || (me.GetFather() != null && me.GetFather() == other.GetFather()))
			{
				return true;
			}
			return false;
		}

		public static bool isGrandchildOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((me.GetMother() != null && isChildOf(me.GetMother(), other)) || (me.GetFather() != null && isChildOf(me.GetFather(), other)))
			{
				return true;
			}
			return false;
		}

		public static bool isGrandparentOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (isGrandchildOf(other, me))
			{
				return true;
			}
			return false;
		}

		public static bool isNephewOrNieceOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((me.GetMother() != null && (isAnySiblingOf(other, me.GetMother()))) || (me.GetFather() != null && (isAnySiblingOf(other, me.GetFather()))))
			{
				return true;
			}
			return false;
		}

		public static bool isUncleOrAuntOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (isNephewOrNieceOf(other, me))
			{
				return true;
			}
			return false;
		}

		public static bool isCousinOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			if ((other.GetMother() != null && isNephewOrNieceOf(me, other.GetMother())) || (other.GetFather() != null && isNephewOrNieceOf(me, other.GetFather())))
			{
				return true;
			}
			return false;
		}

		public static bool isGreatGrandparentOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			return isGreatGrandChildOf(other, me);
		}

		public static bool isGreatGrandChildOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			if ((me.GetMother() != null && isGrandchildOf(me.GetMother(), other)) || (me.GetFather() != null && isGrandchildOf(me.GetFather(), other)))
			{
				return true;
			}
			return false;
		}

		public static bool isGreatUncleOrAuntOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			return isGrandnephewOrGrandnieceOf(other, me);
		}

		public static bool isGrandnephewOrGrandnieceOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			if ((me.GetMother() != null && isUncleOrAuntOf(other, me.GetMother())) || (me.GetFather() != null && isUncleOrAuntOf(other, me.GetFather())))
			{
				return true;
			}
			return false;
		}

		public static bool isCousinOnceRemovedOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((other.GetMother() != null && isCousinOf(me, other.GetMother())) || (other.GetFather() != null && isCousinOf(me, other.GetFather())))
			{
				return true;
			}
			if ((other.GetMother() != null && isGrandnephewOrGrandnieceOf(me, other.GetMother())) || (other.GetFather() != null && isGrandnephewOrGrandnieceOf(me, other.GetFather())))
			{
				return true;
			}
			return false;
		}

		public static bool isSecondCousinOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			PawnRelationWorker worker = PawnRelationDefOf.GranduncleOrGrandaunt.Worker;
			Pawn mother = other.GetMother();
			if (mother != null && ((mother.GetMother() != null && isGrandnephewOrGrandnieceOf(me, mother.GetMother())) || (mother.GetFather() != null && isGrandnephewOrGrandnieceOf(me, mother.GetFather()))))
			{
				return true;
			}
			Pawn father = other.GetFather();
			if (father != null && ((father.GetMother() != null && isGrandnephewOrGrandnieceOf(me, father.GetMother())) || (father.GetFather() != null && isGrandnephewOrGrandnieceOf(me, father.GetFather()))))
			{
				return true;
			}
			return false;
		}
	}
}