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

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to fap in chair
	/// </summary>
	public class WorkGiver_Masturbate_Chair : WorkGiver_Sexchecks
	{
		public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial);

		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			if (pawn.Position == t.Position)
			{
				//use quickfap
				return false;
			}
			//ModLog.Message("" + this.GetType().ToString() + " base checks: pass");
			Building target = t as Building;
			if (!(target is Building))
			{
				if (RJWSettings.DevMode) JobFailReason.Is("not a building");
				return false;
			}
			if (!(target.def.building.isSittable))
			{
				if (RJWSettings.DevMode) JobFailReason.Is("not a sittable building");
				return false;
			}
			if (!pawn.CanReserve(target))
			{
				//if (RJWSettings.DevMode) JobFailReason.Is("not a bed");
				return false;
			}

			if (!(pawn.IsDesignatedHero() || RJWSettings.override_control))
				if (!RJWSettings.WildMode)
				{
					if (!xxx.is_nympho(pawn))
						if (!xxx.is_hornyorfrustrated(pawn))
						{
							if (RJWSettings.DevMode) JobFailReason.Is("not horny enough");
							return false;
						}

					//TODO: more exhibitionsts checks?
					bool canbeseen = false;
					foreach (Pawn bystander in pawn.Map.mapPawns.AllPawnsSpawned.Where(x => xxx.is_human(x) && x != pawn))
					{
						// dont see through walls, dont see whole map, only 15 cells around
						if (bystander.CanSee(target) && bystander.Position.DistanceTo(target.Position) < 15)
						{
							//if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, bystander))
							canbeseen = true;
						}
					}
					if (!xxx.has_quirk(pawn, "Exhibitionist") && canbeseen)
					{
						if (RJWSettings.DevMode) JobFailReason.Is("can be seen");
						return false;
					}
					if (xxx.has_quirk(pawn, "Exhibitionist") && !canbeseen)
					{
						if (RJWSettings.DevMode) JobFailReason.Is("can not be seen");
						return false;
					}
				}

			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.Masturbate, pawn, t, t.Position);
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to fap
	/// </summary>
	public class WorkGiver_Masturbate : WorkGiver_Sexchecks
	{
		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			//ModLog.Message("" + this.GetType().ToString() + " base checks: pass");
			Pawn target = t as Pawn;
			if (target != pawn)
			{
				return false;
			}

			if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0))
				return false;

			if (!(pawn.IsDesignatedHero() || RJWSettings.override_control))
				if (!RJWSettings.WildMode)
				{
					if (!xxx.is_nympho(pawn))
						if (!xxx.is_hornyorfrustrated(pawn))
						{
							if (RJWSettings.DevMode) JobFailReason.Is("not horny enough");
							return false;
						}

					//TODO: more exhibitionsts checks?
					bool canbeseen = false;
					foreach (Pawn bystander in pawn.Map.mapPawns.AllPawnsSpawned.Where(x => xxx.is_human(x) && x != pawn))
					{
						// dont see through walls, dont see whole map, only 15 cells around
						if (pawn.CanSee(bystander) && pawn.Position.DistanceTo(bystander.Position) < 15)
						{
							//if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, bystander))
							canbeseen = true;
						}
					}
					if (!xxx.has_quirk(pawn, "Exhibitionist") && canbeseen)
					{
						if (RJWSettings.DevMode) JobFailReason.Is("can be seen");
						return false;
					}
					if (xxx.has_quirk(pawn, "Exhibitionist") && !canbeseen)
					{
						if (RJWSettings.DevMode) JobFailReason.Is("can not be seen");
						return false;
					}
				}
			//experimental change textures of bed to whore bed
			//ModLog.Message(" bed " + t.GetType().ToString() + " path " + t.Graphic.data.texPath);
			//t.Graphic.data.texPath = "Things/Building/Furniture/Bed/DoubleBedWhore";
			//t.Graphic.path = "Things/Building/Furniture/Bed/DoubleBedWhore";
			//t.DefaultGraphic.data.texPath = "Things/Building/Furniture/Bed/DoubleBedWhore";
			//t.DefaultGraphic.path = "Things/Building/Furniture/Bed/DoubleBedWhore";
			//ModLog.Message(" bed " + t.GetType().ToString() + " texPath " + t.Graphic.data.texPath);
			//ModLog.Message(" bed " + t.GetType().ToString() + " drawSize " + t.Graphic.data.drawSize);
			//t.Draw();
			//t.ExposeData();
			//Scribe_Values.Look(ref t.Graphic.data.texPath, t.Graphic.data.texPath, "Things/Building/Furniture/Bed/DoubleBedWhore", true);

			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.Masturbate, pawn, null, t.Position);
		}
	}
}

license: mit


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to rape
	/// </summary>
	public class WorkGiver_Quickie : WorkGiver_Sexchecks
	{
		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{

			Pawn target = t as Pawn;
			if (target == pawn)
			{
				//JobFailReason.Is("no self rape", null);
				return false;
			}
			if (!WorkGiverChecks(pawn, t, forced))
				return false;

			if (!xxx.is_human(target))
			{
				return false;
			}

			if(target.GetPosture() == PawnPosture.LayingInBed)
			{
				return false;
			}
			if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0))
				return false;

			if (!(pawn.IsDesignatedHero() || RJWSettings.override_control))
				return false;
			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			Pawn target = t as Pawn;
			if (pawn.HostileTo(target))
			{
				return false;
			}
			return true;
		}
		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.quick_sex, t as Pawn);
		}
	}
}


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to rape
	/// </summary>
	public class WorkGiver_Rape : WorkGiver_Sexchecks
	{
		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			if (RJWSettings.DebugRape) ModLog.Message("" + this.GetType().ToString() + " base checks: pass");
			if (!RJWSettings.rape_enabled) return false;

			Pawn target = t as Pawn;
			if (target == pawn)
			{
				//JobFailReason.Is("no self rape", null);
				return false;
			}
			if (!WorkGiverChecks(pawn, t, forced))
				return false;

			if (!xxx.is_human(target))
			{
				return false;
			}
			if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0))
				return false;

			if (!(pawn.IsDesignatedHero() || RJWSettings.override_control))
				if (!RJWSettings.WildMode)
				{
					if (xxx.is_kind(pawn) || xxx.is_masochist(pawn))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("refuses to rape");
						return false;
					}
					if (pawn.relations.OpinionOf(target) > 50 && !xxx.is_rapist(pawn) && !xxx.is_psychopath(pawn) && !xxx.is_masochist(target))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("refuses to rape a friend");
						return false;
					}
					if (!xxx.can_get_raped(target))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("cannot rape target");
						return false;
					}
					//fail for:
					//satisfied pawns
					//horny non rapists
					if ((xxx.need_some_sex(pawn) <= 1f)
						|| (xxx.need_some_sex(pawn) <= 2f && !(xxx.is_rapist(pawn) || xxx.is_psychopath(pawn) || xxx.is_nympho(pawn))))
						{
						if (RJWSettings.DevMode) JobFailReason.Is("not horny enough");
							return false;
						}
					if (!xxx.can_rape(pawn))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("cannot rape");
						return false;
					}
					if (!xxx.is_healthy_enough(target)
						|| !xxx.is_not_dying(target) && (xxx.is_bloodlust(pawn) || xxx.is_psychopath(pawn) || xxx.is_rapist(pawn) || xxx.has_quirk(pawn, "Somnophile")))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("target not healthy enough");
						return false;
					}
					if (!xxx.is_lecher(pawn) && !xxx.is_psychopath(pawn) && !xxx.is_nympho(pawn))
						if (!xxx.isSingleOrPartnerNotHere(pawn))
							if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target))
							{
								if (RJWSettings.DevMode) JobFailReason.Is("cannot rape while partner around");
								return false;
							}
					//ModLog.Message("WorkGiver_RapeCP::" + SexAppraiser.would_fuck(pawn, target));
					if (SexAppraiser.would_fuck(pawn, target) < 0.1f)
					{
						return false;
					}
				}

			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			Pawn target = t as Pawn;
			if (pawn.HostileTo(target) || target.IsDesignatedComfort())
			{
				return false;
			}
			return true;
		}
		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.RapeRandom, t);
		}
	}
}


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to rape a comfort prisoner
	/// </summary>
	public class WorkGiver_RapeCP : WorkGiver_Rape
	{
		public override bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			Pawn target = t as Pawn;
			if (!target.IsDesignatedComfort())
			{
				if (RJWSettings.DevMode) JobFailReason.Is("not designated for comfort", null);
					return false;
			}
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.RapeCP, t);
		}
	}
}


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to rape enemy
	/// </summary>
	public class WorkGiver_RapeEnemy : WorkGiver_Rape
	{
		public override bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			Pawn target = t as Pawn;
			if (!pawn.HostileTo(target))
			{
				if (RJWSettings.DevMode) JobFailReason.Is("not hostile", null);
					return false;
			}
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.RapeEnemy, t);
		}
	}
}


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to have sex with
	/// </summary>
	public class WorkGiver_Sex : WorkGiver_Sexchecks
	{
		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			//ModLog.Message("" + this.GetType().ToString() + " base checks: pass");

			Pawn target = t as Pawn;
			if (target == pawn)
			{
				//JobFailReason.Is("no self sex", null);
				return false;
			}
			if (!WorkGiverChecks(pawn, t, forced))
				return false;

			if (!xxx.is_human(target))
			{
				return false;
			}
			if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0))
				return false;

			if (!(pawn.IsDesignatedHero() || RJWSettings.override_control))
				if (!RJWSettings.WildMode)
				{
					//check initiator
					//fail for:
					//satisfied non nymph pawns
					if (xxx.need_some_sex(pawn) <= 1f && !xxx.is_nympho(pawn))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("not horny enough");
						return false;
					}
					if (!xxx.IsTargetPawnOkay(target))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("target not healthy enough");
						return false;
					}
					if (!xxx.is_lecher(pawn) && !xxx.is_psychopath(pawn) && !xxx.is_nympho(pawn))
						if (!xxx.isSingleOrPartnerNotHere(pawn))
							if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target))
							{
								if (RJWSettings.DevMode) JobFailReason.Is("cannot have sex while partner around");
								return false;
							}

					float relations = 0;
					float attraction = 0;
					if (!xxx.is_animal(target))
					{
						relations = pawn.relations.OpinionOf(target);
						if (relations < RJWHookupSettings.MinimumRelationshipToHookup)
						{
							if (!(relations > 0 && xxx.is_nympho(pawn)))
							{
								if (RJWSettings.DevMode) JobFailReason.Is($"i don't like them:({relations})");
								return false;
							}
						}

						attraction = pawn.relations.SecondaryRomanceChanceFactor(target);
						if (attraction < RJWHookupSettings.MinimumAttractivenessToHookup)
						{
							if (!(attraction > 0 && xxx.is_nympho(pawn)))
							{
								if (RJWSettings.DevMode) JobFailReason.Is($"i don't find them attractive:({attraction})");
								return false;
							}
						}
					}
					//ModLog.Message("WorkGiver_Sex::" + SexAppraiser.would_fuck(pawn, target));
					if (SexAppraiser.would_fuck(pawn, target) < 0.1f)
					{
						return false;
					}

					if (!xxx.is_animal(target))
					{
						//check partner
						if (xxx.need_some_sex(target) <= 1f && !xxx.is_nympho(target))
						{
							if (RJWSettings.DevMode) JobFailReason.Is("partner not horny enough");
							return false;
						}
						if (!xxx.is_lecher(target) && !xxx.is_psychopath(target) && !xxx.is_nympho(target))
							if (!xxx.isSingleOrPartnerNotHere(target))
								if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target))
								{
									if (RJWSettings.DevMode) JobFailReason.Is("partner cannot have sex while their partner around");
									return false;
								}

						relations = target.relations.OpinionOf(pawn);
						if (relations <= RJWHookupSettings.MinimumRelationshipToHookup)
						{
							if (!(relations > 0 && xxx.is_nympho(target)))
							{
								if (RJWSettings.DevMode) JobFailReason.Is($"don't like me:({relations})");
								return false;
							}
						}

						attraction = target.relations.SecondaryRomanceChanceFactor(pawn);
						if (attraction <= RJWHookupSettings.MinimumAttractivenessToHookup)
						{
							if (!(attraction > 0 && xxx.is_nympho(target)))
							{
								if (RJWSettings.DevMode) JobFailReason.Is($"doesn't find me attractive:({attraction})");
								return false;
							}
						}
					}

					//ModLog.Message("WorkGiver_Sex::" + SexAppraiser.would_fuck(target, pawn));
					if (SexAppraiser.would_fuck(target, pawn) < 0.1f)
					{
						return false;
					}
				}

			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			Pawn target = t as Pawn;
			if (pawn.HostileTo(target) || target.IsDesignatedComfort())
			{
				return false;
			}
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			//TODO:: fix bed stealing during join other pawn
			//Building_Bed bed = pawn.ownership.OwnedBed;
			//if (bed == null)
			//	bed = (t as Pawn).ownership.OwnedBed;

			Building_Bed bed = (t as Pawn).CurrentBed();

			if (bed == null)
				return null;

			//if (pawn.CurrentBed() != (t as Pawn).CurrentBed())
			//	return null;

			return JobMaker.MakeJob(xxx.casual_sex, t as Pawn, bed);
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Allow pawn to have sex
	/// dunno if this should be used to allow manual sex start or limit it behind sort of "hero" designator for RP purposes, so player can only control 1 pawn directly?
	/// </summary>
	public class WorkGiver_Sexchecks : WorkGiver_Scanner
	{
		public override int MaxRegionsToScanBeforeGlobalSearch => 4;
		public override PathEndMode PathEndMode => PathEndMode.OnCell;
		public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.Pawn);

		public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			if (!forced)
			//if (!(forced || RJWSettings.WildMode))
			{
				//ModLog.Message("WorkGiver_RJW_Sexchecks::not player interaction, exit:" + forced);
				return false;
			}
			var isHero = RJWSettings.RPG_hero_control && pawn.IsDesignatedHero();
			if (!(RJWSettings.override_control || isHero))
			{
				//ModLog.Message("WorkGiver_RJW_Sexchecks::direct_control disabled or not hero, exit");
				return false;
			}
			//!
			if (!isHero)
			{
				if (!RJWSettings.override_control || MP.IsInMultiplayer)
				{
					//ModLog.Message("WorkGiver_RJW_Sexchecks::direct_control disabled or is in MP , exit");
					return false;
				}
			}
			else if (!pawn.IsHeroOwner())
			{
				//ModLog.Message("WorkGiver_RJW_Sexchecks::not hero owner, exit");
				return false;
			}
			Pawn target = t as Pawn;
			if (t is Corpse)
			{
				Corpse corpse = t as Corpse;
				target = corpse.InnerPawn;
				//ModLog.Message("WorkGiver_RJW_Sexchecks::Pawn(" + xxx.get_pawnname(pawn) + "), Target corpse(" + xxx.get_pawnname(target) + ")");
			}
			else
			{
				//ModLog.Message("WorkGiver_RJW_Sexchecks::Pawn(" + xxx.get_pawnname(pawn) + "), Target pawn(" + xxx.get_pawnname(target) + ")");
			}

			//Log.Message("1");
			if (t == null || t.Map == null)
			{
				return false;
			}
			//Log.Message("2");
			if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn)))
			{
				//ModLog.Message("WorkGiver_RJW_Sexchecks::JobOnThing(" + xxx.get_pawnname(pawn) + ") is cannot fuck or be fucked.");
				return false;
			}
			//Log.Message("3");
			if (t is Pawn)
				if (!(xxx.can_fuck(target) || xxx.can_be_fucked(target)))
				{
					//ModLog.Message("WorkGiver_RJW_Sexchecks::JobOnThing(" + xxx.get_pawnname(target) + ") is cannot fuck or be fucked.");
					return false;
				}
			//Log.Message("4");

			if (!RJWSettings.bestiality_enabled && xxx.is_animal(target))
			{
				//if (RJWSettings.DevMode) JobFailReason.Is("bestiality disabled");
				return false;
			}
			//investigate AoA, someday
			//move this?
			//if (xxx.is_animal(pawn) && xxx.is_animal(target) && !RJWSettings.animal_on_animal_enabled)
			//{
			//	return false;
			//}
			if (!xxx.is_human(pawn) && !(xxx.RoMIsActive && pawn.health.hediffSet.HasHediff(xxx.TM_ShapeshiftHD)))
			{
				return false;
			}

			//Log.Message("5");
			if (!pawn.CanReach(t, PathEndMode, Danger.Some))
			{
				if (RJWSettings.DevMode) JobFailReason.Is(
					pawn.CanReach(t, PathEndMode, Danger.Deadly)
						? "unable to reach target safely" : "target unreachable");
				return false;
			}
			//Log.Message("6");
			if (t.IsForbidden(pawn))
			{
				if (RJWSettings.DevMode) JobFailReason.Is("target is outside of allowed area");
				return false;
			}
			//Log.Message("7");
			if (!pawn.IsDesignatedHero())
			{
				if (!RJWSettings.WildMode)
				{
					if (pawn.IsDesignatedComfort() || pawn.IsDesignatedBreeding())
					{
						if (RJWSettings.DevMode) JobFailReason.Is("designated pawns cannot initiate sex");
						return false;
					}
					if (!xxx.is_healthy_enough(pawn))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("not healthy enough for sex");
						return false;
					}
					if (xxx.is_asexual(pawn))
					{
						if (RJWSettings.DevMode) JobFailReason.Is("refuses to have sex");
						return false;
					}
				}
			}
			else
			{
				if (!pawn.IsHeroOwner())
				{
					//ModLog.Message("WorkGiver_Sexchecks::player interaction for not owned hero, exit");
					return false;
				}
			}

			if (!MoreChecks(pawn, t, forced))
				return false;

			return true;
		}

		public virtual bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			return false;
		}

		public virtual bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return null;
		}
	}
}


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Try to solicit pawn to have sex with
	/// </summary>
	public class WorkGiver_Solicit : WorkGiver_Sexchecks
	{
		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			//ModLog.Message("" + this.GetType().ToString() + " base checks: pass");

			Pawn target = t as Pawn;
			if (target == pawn)
			{
				//JobFailReason.Is("no self solicit", null);
				return false;
			}
			if (!WorkGiverChecks(pawn, t, forced))
				return false;

			if (!xxx.is_human(target))
			{
				return false;
			}
			//if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0))
			//	return false;

			//ModLog.Message("WorkGiver_Sex::" + SexAppraiser.would_fuck(target, pawn));
			//if (SexAppraiser.would_fuck(target, pawn) < 0.1f)
			//{
			//	return false;
			//}

			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override bool WorkGiverChecks(Pawn pawn, Thing t, bool forced = false)
		{
			Pawn target = t as Pawn;
			if (pawn.HostileTo(target) || target.IsDesignatedComfort())
			{
				return false;
			}
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			//TODO:: fix bed stealing during join other pawn
			//Building_Bed bed = pawn.ownership.OwnedBed;
			//if (bed == null)
			//	bed = (t as Pawn).ownership.OwnedBed;

			Building_Bed bed = (pawn as Pawn).ownership.OwnedBed;

			if (bed == null)
				return null;

			//if (pawn.CurrentBed() != (t as Pawn).CurrentBed())
			//	return null;

			return JobMaker.MakeJob(xxx.whore_inviting_visitors, t as Pawn, bed);
		}
	}
}


code:
using RimWorld;
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Assigns a pawn to rape a corpse
	/// </summary>
	public class WorkGiver_ViolateCorpse : WorkGiver_Sexchecks
	{
		public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.Corpse);

		public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false)
		{
			//ModLog.Message("" + this.GetType().ToString() + " base checks: pass");
			if (!RJWSettings.necrophilia_enabled) return false;

			//Pawn target = (t as Corpse).InnerPawn;
			if (!pawn.CanReserve(t, xxx.max_rapists_per_prisoner, 0))
				return false;

			if (!(pawn.IsDesignatedHero() || RJWSettings.override_control))
				if (!RJWSettings.WildMode)
				{
					if (xxx.is_necrophiliac(pawn) && !xxx.is_hornyorfrustrated(pawn))
						{
						if (RJWSettings.DevMode) JobFailReason.Is("not horny enough");
							return false;
						}
					if (!xxx.is_necrophiliac(pawn))
						if ((t as Corpse).CurRotDrawMode != RotDrawMode.Fresh)
						{
							if (RJWSettings.DevMode) JobFailReason.Is("refuse to rape rotten");
							return false;
						}
						else if (!xxx.is_frustrated(pawn))
							{
							if (RJWSettings.DevMode) JobFailReason.Is("not horny enough");
								return false;
							}
					//ModLog.Message("WorkGiver_ViolateCorpse::" + SexAppraiser.would_fuck(pawn, t as Corpse));
					if (SexAppraiser.would_fuck(pawn, t as Corpse) > 0.1f)
					{
						return false;
					}
				}
			//ModLog.Message("" + this.GetType().ToString() + " extended checks: can start sex");
			return true;
		}

		public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
		{
			return JobMaker.MakeJob(xxx.RapeCorpse, t as Corpse);
		}
	}
}


code:
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]


projectName: RJW

projectStyle: PackageReference

enableAudit: true

auditLevel: low

auditMode: direct

include: Compile, Build, Native, ContentFiles, Analyzers, BuildTransitive

target: Package


code:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
    <RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
    <RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
    <ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
    <NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
    <NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\ivenl\.nuget\packages\</NuGetPackageFolders>
    <NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
    <NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.10.2</NuGetToolVersion>
  </PropertyGroup>
  <ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
    <SourceRoot Include="C:\Users\ivenl\.nuget\packages\" />
  </ItemGroup>
</Project>


code:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />


type: package

related: .xml


code:
<?xml version="1.0" encoding="utf-8"?>

<ModMetaData>
	<name>RimJobWorld</name>
	<author>Ed86</author>
	<url>https://gitgud.io/Ed86/rjw</url>
	<supportedVersions>

1.1

1.2

1.3

1.4

1.5

	</supportedVersions>
	<packageId>rim.job.world</packageId>
	<modDependencies>

			<packageId>brrainz.harmony</packageId>
			<displayName>Harmony</displayName>
			<steamWorkshopUrl>steam://url/CommunityFilePage/2009463077</steamWorkshopUrl>
			<downloadUrl>https://github.com/pardeike/HarmonyRimWorld/releases/latest</downloadUrl>

			<packageId>UnlimitedHugs.HugsLib</packageId>
			<displayName>HugsLib</displayName>
			<downloadUrl>https://github.com/UnlimitedHugs/RimworldHugsLib/releases/latest</downloadUrl>
			<steamWorkshopUrl>steam://url/CommunityFilePage/818773962</steamWorkshopUrl>

	</modDependencies>
	<loadAfter>

UnlimitedHugs.HugsLib

brrainz.harmony

	</loadAfter>
	<incompatibleWith>

gregorycurrie.AnimalGenetics

EdB.PrepareCarefully

EdB.PrepareCarefully.UnofficialPatch

EdB.PrepareCarefully.alonske.fork

Dalrae.GaramRaceAddon

IGNI.LostForest

Sierra.RT.MedievalTalents

com.yayo.raceQuestPawn

Xenofell.HermaphroditeGene

	</incompatibleWith>
	<description>
M for Mature

Load mod at bottom of mod list:
	Harmony
	Core
	HugsLib
	++Mods
	RimJobWorld
	RJW mods and patches

Support dev:
https://subscribestar.adult/Ed86
https://ko-fi.com/caffeinated_ed
Forum:
https://www.loverslab.com/files/file/7257-rimjobworld/
Discord:
https://discord.gg/CXwHhv8
	</description>
</ModMetaData>


code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest>
	<identifier>RimJobWorld</identifier>
	<version>5.3.7.1</version>
	<dependencies>

HugsLib

	</dependencies>
	<incompatibleWith />
	<loadAfter>

HugsLib

	</loadAfter>
	<suggests>
	</suggests>
	<manifestUri>https://gitgud.io/Ed86/rjw/raw/master/About/Manifest.xml</manifestUri>
	<downloadUri>https://gitgud.io/Ed86/rjw</downloadUri>
</Manifest>


code:
# Environment setup

## RimWorld dependencies
The `.csproj` file has been configured to automatically detect standard Windows, Linux, and macOS Steam install
locations, and should link dependencies regardless of the project's location on your hard drive. If that works for you,
you don't need to read any farther.

These are the paths RimJobWorld will look for the RimWorld dlls:
- `../_RimWorldData/Managed/` (Custom)
- `C:\Program Files (x86)\Steam\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\` (Windows)
- `$(HOME)/.steam/steam/SteamApps/common/RimWorld/RimWorldLinux_Data/Managed/` (Linux)
- `$(HOME)/Library/Application Support/Steam/steamapps/common/RimWorld/RimWorldMac.app/Contents/Resources/Data/Managed/`
  (macOS)

### Custom project location
If you choose to place the RimJobWorld project somewhere other than your RimWorld mods directory, you'll need to create
a symlink in the RimWorld mods directory that points to the RimJobWorld project. Here are some examples of creating
symlinks on different platforms:
- Linux and macOS: Open the terminal and run this command (filling in the actual paths): `ln -s "~/where/you/put/rjw" "/your/RimWorld/Mods/rjw"`
- Windows: Run the Command Prompt as administrator, then run this command: `mklink /D "C:\Your\Rimworld\Mods\rjw" "C:\Where\you\put\rjw"`

### Custom RimWorld install
If you're using a custom RimWorld install, you'll want to create a symlink called `_RimWorldData` next to the `rjw`
folder that points `RimWorldWin64_Data`, `RimWorldLinux_Data`, or `RimWorldMac.app/Contents/Resources/Data`, as
appropriate. Refer to the previous section for how to create a symlink on your platform. In the end your file structure
should look like this:

- `where/you/put/`
  - `rjw/`
    - `RimJobWorld.Main.csproj`
    - ...
  - `_RimWorldData/` *(symlink)*
    - `Managed/`
      - `Assembly-CSharp.dll`
      - ...

## Deployment Notice
Deployment scripts now make use of PowerShell 7+, instead of Windows PowerShell 5.1, allowing for cross platform execution.
Please see [this document](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.2) if you don't have the new PowerShell on your device.


code:
@ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PSSctiptName=Deploy OLD.ps1
SET PowerShellScriptPath=%ThisScriptsDirectory%%PSSctiptName%
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%'";

path: Deploy/Deploy OLD.bat


code:
# Configurable variables
$repo           = '..'
$packing        = 'rjw_packing'
$outputFormat   = '..\..\RJW-{0}.7z'
$internalPath   = 'RJW'
$pathsToRemove = '.git', '.gitattributes', '.gitignore', '1.1\Source', '1.2\Source', '1.3\Source', 'Deploy'

[Console]::ResetColor()

# Progress Bar Variables
$Activity             = "Deploying"
$Id                   = 1

# Complex Progress Bar
$Step                 = 0
$TotalSteps           = 6
$StatusText           = '"Step $($Step.ToString().PadLeft($TotalSteps.ToString().Length)) of $TotalSteps | $Task"' # Single quotes need to be on the outside
$StatusBlock          = [ScriptBlock]::Create($StatusText) # This script block allows the string above to use the current values of embedded values each time it's run

# Read environvemt
$Task = "Collecting info..."
$Step++
##Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

$startupPath = Get-Location
$7z = (GET-ItemProperty 'HKLM:\SOFTWARE\7-Zip').Path + '7z.exe'
$packingRjw = $packing + "\" + $internalPath

Push-Location -Path $repo

try {
	[string]$version = git describe --tags
} catch {
	[string]$version = ""
}

if ($version -eq "") {
	$manifest = "./About/Manifest.xml"
	[string]$version = (Select-Xml -Path $manifest -XPath '/Manifest/version' | Select-Object -ExpandProperty Node).innerText
}

$output = $outputFormat -f $version

Pop-Location

# Cleanup
$Task = "Cleanup..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

if (Test-Path $packing) { Remove-Item -Recurse -Force $packing }
if (Test-Path $output) { Remove-Item $output }

# Prepating data
$Task = "Copying..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

$items = Get-ChildItem -Force -Path $repo
$items | Foreach-Object -Begin {
	$i = 0
} -Process {
    $i++

	if (-Not ($pathsToRemove -contains $_.Name)) {
		Copy-Item -Recurse $_.FullName -Destination ($packingRjw + "\" + $_.Name)
	}

	$p = $i * 100 / $items.Count
	Write-Progress -Id ($Id+1) -ParentId $Id -Activity 'Copying' -Status ('{0:0}% complete' -f $p) -PercentComplete $p
}
Write-Progress -Id ($Id+1) -ParentId $Id -Activity "Copying" -Status "Ready" -Completed

# removing files from subfolders
$Task = "Excluding..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

foreach ($path in $pathsToRemove) {
	$p = $packingRjw + '\' + $path
	if (Test-Path $p) { Remove-Item -Recurse -Force $p }
}

# archiving
$Task = "Archiving..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

Push-Location -Path  $packing
& $7z a -r -bsp1 ($startupPath.Path+'\'+$output) + $internalPath | Foreach-Object -Begin {
	Write-Progress -Id ($Id+1) -ParentId $Id -Activity 'Archiving' -Status "Starting..." -PercentComplete 0
} -Process {
	$line = $_.Trim()
	if ($line -ne "") {
		[int]$p = 0
		[bool]$result = [int]::TryParse($line.Split('%')[0], [ref]$p)
		if ($result) {
			Write-Progress -Id ($Id+1) -ParentId $Id -Activity 'Archiving' -Status $line -PercentComplete $p
		}
	}
}

Write-Progress -Id ($Id+1)  -Activity "Archiving" -Status "Ready" -Completed
Pop-Location

# cleanup
$Task = "Cleanup..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

if (Test-Path $packing) { Remove-Item -Recurse -Force $packing }

Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -Completed

# If running in the console, wait for input before closing.
if ($Host.Name -eq "ConsoleHost")
{
	Write-Host "Done"
    Write-Host "Press any key to continue..."
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}

path: Deploy/Deploy OLD.ps1


code:
@ECHO OFF
SET scriptDir=%~dp0
SET psScript=Deploy.ps1
SET pwshScriptPath=%scriptDir%%psScript%

pwsh -NoProfile -ExecutionPolicy Bypass -Command "& '%pwshScriptPath%'";


code:
# Configurable variables
$repo           = '..'
$packing        = 'rjw_packing'
$outputFormat   = Join-Path -Path '..\..' -ChildPath 'RJW-{0}.7z'
$internalPath   = 'RJW'
$pathsToRemove = '.git', '.gitattributes', '.gitignore', (Join-Path -Path '1.1' -ChildPath 'Source'), (Join-Path -Path '1.2' -ChildPath 'Source'), (Join-Path -Path '1.3' -ChildPath 'Source'), 'Deploy'

[Console]::ResetColor()

# Progress Bar Variables
$Activity             = "Deploying"
$Id                   = 1

# Complex Progress Bar
$Step                 = 0
$TotalSteps           = 6
$StatusText           = '"Step $($Step.ToString().PadLeft($TotalSteps.ToString().Length)) of $TotalSteps | $Task"' # Single quotes need to be on the outside
$StatusBlock          = [ScriptBlock]::Create($StatusText) # This script block allows the string above to use the current values of embedded values each time it's run

# Read environvemt
$Task = "Collecting info..."
$Step++
##Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

$startupPath = Get-Location
if ($IsWindows) {
	$7z = (GET-ItemProperty 'HKLM:\SOFTWARE\7-Zip').Path + '7z.exe'
}
else {
	$7z = &which 7z
}

$packingRjw = Join-Path -Path $packing -ChildPath $internalPath

Push-Location -Path $repo

try {
	[string]$version = git describe --tags
} catch {
	[string]$version = ""
}

if ($version -eq "") {
	$manifest = Join-Path -Path '.\About' -ChildPath 'Manifest.xml'
	[string]$version = (Select-Xml -Path $manifest -XPath '/Manifest/version' | Select-Object -ExpandProperty Node).innerText
}

$output = $outputFormat -f $version

Pop-Location

# Cleanup
$Task = "Cleanup..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

if (Test-Path $packing) { Remove-Item -Recurse -Force $packing }
if (Test-Path $output) { Remove-Item $output }

# Prepating data
$Task = "Copying..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

$items = Get-ChildItem -Force -Path $repo
$items | Foreach-Object -Begin {
	$i = 0
} -Process {
    $i++

	if (-Not ($pathsToRemove -contains $_.Name)) {
		Copy-Item -Recurse $_.FullName -Destination (Join-Path -Path $packingRjw -ChildPath $_.Name)
	}

	$p = $i * 100 / $items.Count
	Write-Progress -Id ($Id+1) -ParentId $Id -Activity 'Copying' -Status ('{0:0}% complete' -f $p) -PercentComplete $p
}
Write-Progress -Id ($Id+1) -ParentId $Id -Activity "Copying" -Status "Ready" -Completed

# removing files from subfolders
$Task = "Excluding..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

foreach ($path in $pathsToRemove) {
	$p = Join-Path -Path $packingRjw -ChildPath $path
	if (Test-Path $p) { Remove-Item -Recurse -Force $p }
}

# archiving
$Task = "Archiving..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

Push-Location -Path  $packing
& $7z a -r -bsp1 (Join-Path -Path $startupPath.Path -ChildPath $output) + $internalPath | Foreach-Object -Begin {
	Write-Progress -Id ($Id+1) -ParentId $Id -Activity 'Archiving' -Status "Starting..." -PercentComplete 0
} -Process {
	$line = $_.Trim()
	if ($line -ne "") {
		[int]$p = 0
		[bool]$result = [int]::TryParse($line.Split('%')[0], [ref]$p)
		if ($result) {
			Write-Progress -Id ($Id+1) -ParentId $Id -Activity 'Archiving' -Status $line -PercentComplete $p
		}
	}
}

Write-Progress -Id ($Id+1)  -Activity "Archiving" -Status "Ready" -Completed
Pop-Location

# cleanup
$Task = "Cleanup..."
$Step++
Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -CurrentOperation " " -PercentComplete ($Step / $TotalSteps * 100)

if (Test-Path $packing) { Remove-Item -Recurse -Force $packing }

Write-Progress -Id $Id -Activity $Activity -Status (& $StatusBlock) -Completed

# If running in the console, wait for input before closing.
if ($Host.Name -eq "ConsoleHost")
{
	Write-Host "Done"
    Write-Host "Press any key to continue..."
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}


code:
#!/usr/bin/env bash
set -e

scriptDir=$(pwd)
scriptName="Deploy.ps1"
scriptPath=$scriptDir/$scriptName
echo "Reminder: p7zip and PowerShell Core are required."
pwsh -NoProfile -ExecutionPolicy Bypass -Command "& '$scriptPath'"


code:
OwO what's this?
RimjobWorld is a sex mod that overhauls Rimworld loving, mating and pregnancy mechanics.
Mod supports various sex/hentai fetishes.
Mod is highly configurable and most feature turned off by default, so you can go from vanilla experience to your wild fantasies.
Many additional features(submods) can be found on LL forum and discord.

You can support current Dev(Me) here:
[SubscribeStar](https://subscribestar.adult/Ed86)
[Ko-fi](https://ko-fi.com/caffeinated_ed)

[Mod git]{https://gitgud.io/Ed86/rjw}

Feedback:
[Discord]{https://discord.gg/CXwHhv8}
[LoversLab Forum]{https://www.loverslab.com/files/file/7257-rimjobworld/}

Requirements:
Hugslib ([Steam](https://steamcommunity.com/sharedfiles/filedetails/?id=818773962)) ([GitHub](https://github.com/UnlimitedHugs/RimworldHugsLib))

Installation:
(if updating - Delete all files from previous RJW versions)
Unpack the the content from the downloaded archive into "...steam/steamapps/common/Rimworld/Mods/RJW"
You will see this folder structure - Rimworld/Mods/RJW/About
Start Game
Activate mod & the other required mods
Restart game

Load Order:
-Rimworld Core (that's the game)
--Hugslib
---your mods
--RimJobWorld
---addons for RimJobWorld

Contributing:
use TABS not SPACES for xml/cs, please?
do comments in code for other people(me?)

P.S.
im not a pro C# programmer or git user, so i might do weird stuff ;)