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

namespace rjw
{
	// TODO: Add option for logging pregnancy chance after sex (dev mode only?)
	// TODO: Add an alernate more complex system for pregnancy calculations, by using bodyparts, genitalia, and size (similar species -> higher chance, different -> lower chance)

	// TODO: Old settings that are not in use - evalute if they're needed and either convert these to settings, or delete them.
	/*
	public float significant_pain_threshold; // Updated
	public float extreme_pain_threshold; // Updated
	public float base_chance_to_hit_prisoner; // Updated
	public int min_ticks_between_hits; // Updated
	public int max_ticks_between_hits; // Updated
	public float max_nymph_fraction; // Updated
	public float comfort_prisoner_rape_mtbh_mul; // Updated
	public float whore_mtbh_mul; // Updated
	public static bool comfort_prisoners_enabled; // Updated //this one is in config.cs as well!
	public static bool ComfortColonist; // New
	public static bool ComfortAnimal; // New
	public static bool rape_me_sticky_enabled; // Updated
	public static bool bondage_gear_enabled; // Updated
	public static bool nymph_joiners_enabled; // Updated
	public static bool always_accept_whores; // Updated
	public static bool nymphs_always_JoinInBed; // Updated
	public static bool zoophis_always_rape; // Updated
	public static bool rapists_always_rape; // Updated
	public static bool pawns_always_do_fapping; // Updated
	public static bool whores_always_findjob; // Updated
	public bool show_regular_dick_and_vag; // Updated
	*/

	public class RJWPreferenceSettings : ModSettings
	{
		public static float vaginal = 1.20f;
		public static float anal = 0.80f;
		public static float fellatio = 0.80f;
		public static float cunnilingus = 0.80f;
		public static float rimming = 0.40f;
		public static float double_penetration = 0.60f;
		public static float breastjob = 0.50f;
		public static float handjob = 0.80f;
		public static float mutual_masturbation = 0.70f;
		public static float fingering = 0.50f;
		public static float footjob = 0.30f;
		public static float scissoring = 0.50f;
		public static float fisting = 0.30f;
		public static float sixtynine = 0.69f;

		public static float asexual_ratio = 0.02f;
		public static float pansexual_ratio = 0.03f;
		public static float heterosexual_ratio = 0.7f;
		public static float bisexual_ratio = 0.15f;
		public static float homosexual_ratio = 0.1f;

		public static bool FapEverywhere = false;
		public static bool FapInBed = true;
		public static bool FapInBelts = false;
		public static bool FapInArmbinders = false;
		public static bool ShowForCP = true;
		public static bool ShowForBreeding = true;

		public static Clothing sex_wear = Clothing.Nude;
		public static RapeAlert rape_attempt_alert = RapeAlert.Humanlikes;
		public static RapeAlert rape_alert = RapeAlert.Humanlikes;
		public static Rjw_sexuality sexuality_distribution = Rjw_sexuality.Vanilla;

		public static AllowedSex Malesex = AllowedSex.All;
		public static AllowedSex FeMalesex = AllowedSex.All;

		private static Vector2 scrollPosition;
		private static float height_modifier = 0f;

		public enum AllowedSex
		{
			All,
			Homo,
			Nohomo
		};

		public enum Clothing
		{
			Nude,
			Headgear,
			Clothed
		};

		public enum RapeAlert
		{
			Enabled,
			Colonists,
			Humanlikes,
			Silent,
			Disabled
		};

		public enum Rjw_sexuality
		{
			Vanilla,
			RimJobWorld,
			Psychology,
			SYRIndividuality
		};

		public static void DoWindowContents(Rect inRect)
		{
			Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
			Rect viewRect = new Rect(0f, 0f, inRect.width - 16f, inRect.height + height_modifier);

			Widgets.BeginScrollView(outRect, ref scrollPosition, viewRect); // scroll

			Listing_Standard listingStandard = new Listing_Standard();
			listingStandard.maxOneColumn = true;
			listingStandard.ColumnWidth = viewRect.width / 3.15f;
			listingStandard.Begin(viewRect);
			listingStandard.Gap(4f);
			listingStandard.Label("SexTypeFrequency".Translate());
			listingStandard.Gap(6f);
			listingStandard.Label("  " + "vaginal".Translate() + ": " + Math.Round(vaginal * 100, 0), -1, "vaginal_desc".Translate());
			vaginal = listingStandard.Slider(vaginal, 0.01f, 3.0f);
			listingStandard.Label("  " + "anal".Translate() + ": " + Math.Round(anal * 100, 0), -1, "anal_desc".Translate());
			anal = listingStandard.Slider(anal, 0.01f, 3.0f);
			listingStandard.Label("  " + "double_penetration".Translate() + ": " + Math.Round(double_penetration * 100, 0), -1, "double_penetration_desc".Translate());
			double_penetration = listingStandard.Slider(double_penetration, 0.01f, 3.0f);
			listingStandard.Label("  " + "fellatio".Translate() + ": " + Math.Round(fellatio * 100, 0), -1, "fellatio_desc".Translate());
			fellatio = listingStandard.Slider(fellatio, 0.01f, 3.0f);
			listingStandard.Label("  " + "cunnilingus".Translate() + ": " + Math.Round(cunnilingus * 100, 0), -1, "cunnilingus_desc".Translate());
			cunnilingus = listingStandard.Slider(cunnilingus, 0.01f, 3.0f);
			listingStandard.Label("  " + "rimming".Translate() + ": " + Math.Round(rimming * 100, 0), -1, "rimming_desc".Translate());
			rimming = listingStandard.Slider(rimming, 0.01f, 3.0f);
			listingStandard.Label("  " + "sixtynine".Translate() + ": " + Math.Round(sixtynine * 100, 0), -1, "sixtynine_desc".Translate());
			sixtynine = listingStandard.Slider(sixtynine, 0.01f, 3.0f);
			listingStandard.CheckboxLabeled("FapEverywhere".Translate(), ref FapEverywhere, "FapEverywhere_desc".Translate());
			listingStandard.CheckboxLabeled("FapInBed".Translate(), ref FapInBed, "FapInBed_desc".Translate());
			listingStandard.CheckboxLabeled("FapInBelts".Translate(), ref FapInBelts, "FapInBelts_desc".Translate());
			listingStandard.CheckboxLabeled("FapInArmbinders".Translate(), ref FapInArmbinders, "FapInArmbinders_desc".Translate());

			listingStandard.NewColumn();
			listingStandard.Gap(4f);
			if (listingStandard.ButtonText("Reset".Translate()))
			{
				vaginal = 1.20f;
				anal = 0.80f;
				fellatio = 0.80f;
				cunnilingus = 0.80f;
				rimming = 0.40f;
				double_penetration = 0.60f;
				breastjob = 0.50f;
				handjob = 0.80f;
				mutual_masturbation = 0.70f;
				fingering = 0.50f;
				footjob = 0.30f;
				scissoring = 0.50f;
				fisting = 0.30f;
				sixtynine = 0.69f;
			}
			listingStandard.Gap(6f);
			listingStandard.Label("  " + "breastjob".Translate() + ": " + Math.Round(breastjob * 100, 0), -1, "breastjob_desc".Translate());
			breastjob = listingStandard.Slider(breastjob, 0.01f, 3.0f);
			listingStandard.Label("  " + "handjob".Translate() + ": " + Math.Round(handjob * 100, 0), -1, "handjob_desc".Translate());
			handjob = listingStandard.Slider(handjob, 0.01f, 3.0f);
			listingStandard.Label("  " + "fingering".Translate() + ": " + Math.Round(fingering * 100, 0), -1, "fingering_desc".Translate());
			fingering = listingStandard.Slider(fingering, 0.01f, 3.0f);
			listingStandard.Label("  " + "fisting".Translate() + ": " + Math.Round(fisting * 100, 0), -1, "fisting_desc".Translate());
			fisting = listingStandard.Slider(fisting, 0.01f, 3.0f);
			listingStandard.Label("  " + "mutual_masturbation".Translate() + ": " + Math.Round(mutual_masturbation * 100, 0), -1, "mutual_masturbation_desc".Translate());
			mutual_masturbation = listingStandard.Slider(mutual_masturbation, 0.01f, 3.0f);
			listingStandard.Label("  " + "footjob".Translate() + ": " + Math.Round(footjob * 100, 0), -1, "footjob_desc".Translate());
			footjob = listingStandard.Slider(footjob, 0.01f, 3.0f);
			listingStandard.Label("  " + "scissoring".Translate() + ": " + Math.Round(scissoring * 100, 0), -1, "scissoring_desc".Translate());
			scissoring = listingStandard.Slider(scissoring, 0.01f, 3.0f);

			if (listingStandard.ButtonText("Malesex".Translate() + Malesex.ToString()))
			{
				Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
				{
				  new FloatMenuOption("AllowedSex.All".Translate(), (() => Malesex = AllowedSex.All)),
				  new FloatMenuOption("AllowedSex.Homo".Translate(), (() => Malesex = AllowedSex.Homo)),
				  new FloatMenuOption("AllowedSex.Nohomo".Translate(), (() => Malesex = AllowedSex.Nohomo))
				}));
			}
			if (listingStandard.ButtonText("FeMalesex".Translate() + FeMalesex.ToString()))
			{
				Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
				{
				  new FloatMenuOption("AllowedSex.All".Translate(), (() => FeMalesex = AllowedSex.All)),
				  new FloatMenuOption("AllowedSex.Homo".Translate(), (() => FeMalesex = AllowedSex.Homo)),
				  new FloatMenuOption("AllowedSex.Nohomo".Translate(), (() => FeMalesex = AllowedSex.Nohomo))
				}));
			}

			listingStandard.NewColumn();
			listingStandard.Gap(4f);
			// TODO: Add translation
			if (listingStandard.ButtonText("SexClothing".Translate() + sex_wear.ToString()))
			{
				Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
				{
				  new FloatMenuOption("SexClothingNude".Translate(), (() => sex_wear = Clothing.Nude)),
				  new FloatMenuOption("SexClothingHeadwear".Translate(), (() => sex_wear = Clothing.Headgear)),
				  new FloatMenuOption("SexClothingFull".Translate(), (() => sex_wear = Clothing.Clothed))
				}));
			}
			listingStandard.Gap(4f);
			if (listingStandard.ButtonText("RapeAttemptAlert".Translate() + rape_attempt_alert.ToString()))
			{
				Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
				{
				  new FloatMenuOption("RapeAttemptAlertAlways".Translate(), (() => rape_attempt_alert = RapeAlert.Enabled)),
				  new FloatMenuOption("RapeAttemptAlertHumanlike".Translate(), (() => rape_attempt_alert = RapeAlert.Humanlikes)),
				  new FloatMenuOption("RapeAttemptAlertColonist".Translate(), (() => rape_attempt_alert = RapeAlert.Colonists)),
				  new FloatMenuOption("RapeAttemptAlertSilent".Translate(), (() => rape_attempt_alert = RapeAlert.Silent)),
				  new FloatMenuOption("RapeAttemptAlertDisabled".Translate(), (() => rape_attempt_alert = RapeAlert.Disabled))
				}));
			}
			if (listingStandard.ButtonText("RapeAlert".Translate() + rape_alert.ToString()))
			{
				Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
				{
				  new FloatMenuOption("RapeAlertAlways".Translate(), (() => rape_alert = RapeAlert.Enabled)),
				  new FloatMenuOption("RapeAlertHumanlike".Translate(), (() => rape_alert = RapeAlert.Humanlikes)),
				  new FloatMenuOption("RapeAlertColonist".Translate(), (() => rape_alert = RapeAlert.Colonists)),
				  new FloatMenuOption("RapeAlertSilent".Translate(), (() => rape_alert = RapeAlert.Silent)),
				  new FloatMenuOption("RapeAlertDisabled".Translate(), (() => rape_alert = RapeAlert.Disabled))
				}));
			}
			listingStandard.CheckboxLabeled("RapeAlertCP".Translate(), ref ShowForCP, "RapeAlertCP_desc".Translate());
			listingStandard.CheckboxLabeled("RapeAlertBreeding".Translate(), ref ShowForBreeding, "RapeAlertBreeding_desc".Translate());

			listingStandard.Gap(26f);
			listingStandard.Label("SexualitySpread1".Translate(), -1, "SexualitySpread2".Translate());
			if (listingStandard.ButtonText(sexuality_distribution.ToString()))
			{
				Find.WindowStack.Add(new FloatMenu(new List<FloatMenuOption>()
				{
					new FloatMenuOption("Vanilla", () => sexuality_distribution = Rjw_sexuality.Vanilla),
					//new FloatMenuOption("RimJobWorld", () => sexuality_distribution = Rjw_sexuality.RimJobWorld),
					new FloatMenuOption("SYRIndividuality", () => sexuality_distribution = Rjw_sexuality.SYRIndividuality),
					new FloatMenuOption("Psychology", () => sexuality_distribution = Rjw_sexuality.Psychology)
				}));
			}
			if (sexuality_distribution == Rjw_sexuality.RimJobWorld)
			{
				listingStandard.Label("SexualityAsexual".Translate() + Math.Round((asexual_ratio / GetTotal()) * 100, 1) + "%", -1, "SexualityAsexual_desc".Translate());
				asexual_ratio = listingStandard.Slider(asexual_ratio, 0.0f, 1.0f);
				listingStandard.Label("SexualityPansexual".Translate() + Math.Round((pansexual_ratio / GetTotal()) * 100, 1) + "%", -1, "SexualityPansexual_desc".Translate());
				pansexual_ratio = listingStandard.Slider(pansexual_ratio, 0.0f, 1.0f);
				listingStandard.Label("SexualityHeterosexual".Translate() + Math.Round((heterosexual_ratio / GetTotal()) * 100, 1) + "%", -1, "SexualityHeterosexual_desc".Translate());
				heterosexual_ratio = listingStandard.Slider(heterosexual_ratio, 0.0f, 1.0f);
				listingStandard.Label("SexualityBisexual".Translate() + Math.Round((bisexual_ratio / GetTotal()) * 100, 1) + "%", -1, "SexualityBisexual_desc".Translate());
				bisexual_ratio = listingStandard.Slider(bisexual_ratio, 0.0f, 1.0f);
				listingStandard.Label("SexualityGay".Translate() + Math.Round((homosexual_ratio / GetTotal()) * 100, 1) + "%", -1, "SexualityGay_desc".Translate());
				homosexual_ratio = listingStandard.Slider(homosexual_ratio, 0.0f, 1.0f);
			}
			else
			{
				if (!xxx.IndividualityIsActive && sexuality_distribution == Rjw_sexuality.SYRIndividuality)
					sexuality_distribution = Rjw_sexuality.Vanilla;
				else if (sexuality_distribution == Rjw_sexuality.SYRIndividuality)
					listingStandard.Label("SexualitySpreadIndividuality".Translate());

				else if (!xxx.PsychologyIsActive && sexuality_distribution == Rjw_sexuality.Psychology)
					sexuality_distribution = Rjw_sexuality.Vanilla;
				else if (sexuality_distribution == Rjw_sexuality.Psychology)
					listingStandard.Label("SexualitySpreadPsychology".Translate());

				else
					listingStandard.Label("SexualitySpreadVanilla".Translate());
			}

			listingStandard.End();
			height_modifier = listingStandard.CurHeight;
			Widgets.EndScrollView();
		}

		public static float GetTotal()
		{
			return asexual_ratio + pansexual_ratio + heterosexual_ratio + bisexual_ratio + homosexual_ratio;
		}

		public override void ExposeData()
		{
			base.ExposeData();
			Scribe_Values.Look(ref vaginal, "vaginal_frequency", vaginal, true);
			Scribe_Values.Look(ref anal, "anal_frequency", anal, true);
			Scribe_Values.Look(ref fellatio, "fellatio_frequency", fellatio, true);
			Scribe_Values.Look(ref cunnilingus, "cunnilingus_frequency", cunnilingus, true);
			Scribe_Values.Look(ref rimming, "rimming_frequency", rimming, true);
			Scribe_Values.Look(ref double_penetration, "double_penetration_frequency", double_penetration, true);
			Scribe_Values.Look(ref sixtynine, "sixtynine_frequency", sixtynine, true);
			Scribe_Values.Look(ref breastjob, "breastjob_frequency", breastjob, true);
			Scribe_Values.Look(ref handjob, "handjob_frequency", handjob, true);
			Scribe_Values.Look(ref footjob, "footjob_frequency", footjob, true);
			Scribe_Values.Look(ref fingering, "fingering_frequency", fingering, true);
			Scribe_Values.Look(ref fisting, "fisting_frequency", fisting, true);
			Scribe_Values.Look(ref mutual_masturbation, "mutual_masturbation_frequency", mutual_masturbation, true);
			Scribe_Values.Look(ref scissoring, "scissoring_frequency", scissoring, true);
			Scribe_Values.Look(ref asexual_ratio, "asexual_ratio", asexual_ratio, true);
			Scribe_Values.Look(ref pansexual_ratio, "pansexual_ratio", pansexual_ratio, true);
			Scribe_Values.Look(ref heterosexual_ratio, "heterosexual_ratio", heterosexual_ratio, true);
			Scribe_Values.Look(ref bisexual_ratio, "bisexual_ratio", bisexual_ratio, true);
			Scribe_Values.Look(ref homosexual_ratio, "homosexual_ratio", homosexual_ratio, true);
			Scribe_Values.Look(ref FapEverywhere, "FapEverywhere", FapEverywhere, true);
			Scribe_Values.Look(ref FapInBed, "FapInBed", FapInBed, true);
			Scribe_Values.Look(ref FapInBelts, "FapInBelts", FapInBelts, true);
			Scribe_Values.Look(ref FapInArmbinders, "FapInArmbinders", FapInArmbinders, true);
			Scribe_Values.Look(ref sex_wear, "sex_wear", sex_wear, true);
			Scribe_Values.Look(ref rape_attempt_alert, "rape_attempt_alert", rape_attempt_alert, true);
			Scribe_Values.Look(ref rape_alert, "rape_alert", rape_alert, true);
			Scribe_Values.Look(ref ShowForCP, "ShowForCP", ShowForCP, true);
			Scribe_Values.Look(ref ShowForBreeding, "ShowForBreeding", ShowForBreeding, true);
			Scribe_Values.Look(ref sexuality_distribution, "sexuality_distribution", sexuality_distribution, true);
			Scribe_Values.Look(ref Malesex, "Malesex", Malesex, true);
			Scribe_Values.Look(ref FeMalesex, "FeMalesex", FeMalesex, true);
		}
	}
}


code:
using Verse;

namespace rjw
{
	public class config : Def
	{
		// TODO: Clean these.

		public float minor_pain_threshold;	        // 0.3
		public float significant_pain_threshold;	// 0.6
		public float extreme_pain_threshold;		// 0.95
		public float base_chance_to_hit_prisoner;	// 50
		public int min_ticks_between_hits;			// 500
		public int max_ticks_between_hits;			// 700

		public float max_nymph_fraction;
		public float comfort_prisoner_rape_mtbh_mul;
	}
}

repo_name: Euclidean/rjw

license: mit


code:
using RimWorld;
using Verse;

namespace rjw
{
	// used in Vulnerability StatDef calculation
	public class SkillNeed_CapableOfResisting : SkillNeed_BaseBonus
	{
		public override float ValueFor(Pawn pawn)
		{
			if (pawn.skills == null)
			{
				return 1f;
			}

			int level = NegateSkillBonus(pawn) ? 0 : pawn.skills.GetSkill(skill).Level;
			return ValueAtLevel(level);
		}

		protected virtual bool NegateSkillBonus(Pawn pawn)
		{
			// remove melee bonus for pawns: downed, sleeping/resting/lying, wearing armbinder
			return pawn.Downed
				|| pawn.GetPosture() != PawnPosture.Standing
				// Simple verification on RJW side, but ideally this method should just be overridden in RJW-EX
				|| (xxx.RjwExIsActive && pawn.health.hediffSet.HasHediff(xxx.RjwEx_Armbinder));
		}
	}
}


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

namespace rjw
{
	public class ThinkNode_ChancePerHour_Bestiality : ThinkNode_ChancePerHour
	{
		protected override float MtbHours(Pawn pawn)
		{
			float base_mtb = xxx.config.comfort_prisoner_rape_mtbh_mul; // Default is 4.0

			float desire_factor;
			{
				Need_Sex need_sex = pawn.needs.TryGetNeed<Need_Sex>();

				if (need_sex != null)
				{
					if (need_sex.CurLevel <= need_sex.thresh_frustrated())
						desire_factor = 0.40f;
					else if (need_sex.CurLevel <= need_sex.thresh_horny())
						desire_factor = 0.80f;
					else
						desire_factor = 1.00f;
				}
				else
					desire_factor = 1.00f;
			}

			float personality_factor;
			{
				personality_factor = 1.0f;

				if (xxx.is_nympho(pawn))
					personality_factor *= 0.5f;
				else if (xxx.is_prude(pawn) || pawn.story.traits.HasTrait(TraitDefOf.BodyPurist))
					personality_factor *= 2f;

				if (pawn.story.traits.HasTrait(TraitDefOf.Nudist))
					personality_factor *= 0.9f;

				// Pawns with no zoophile trait should first try to find other outlets.
				if (!xxx.is_zoophile(pawn))
					personality_factor *= 8f;

				// Less likely to engage in bestiality if the pawn has a lover... unless the lover is an animal (there's mods for that, so need to check).
				if (!xxx.IsSingleOrPartnersNotHere(pawn) && !xxx.is_animal(LovePartnerRelationUtility.ExistingMostLikedLovePartner(pawn, false)) && !xxx.is_lecher(pawn) && !xxx.is_nympho(pawn))
					personality_factor *= 2.5f;

				// Pawns with few or no prior animal encounters are more reluctant to engage in bestiality.
				if (pawn.records.GetValue(xxx.CountOfSexWithAnimals) < 3)
					personality_factor *= 3f;
				else if (pawn.records.GetValue(xxx.CountOfSexWithAnimals) > 10)
					personality_factor *= 0.8f;
			}

			float fun_factor;
			{
				if ((pawn.needs.joy != null) && (xxx.is_bloodlust(pawn)))
					fun_factor = Mathf.Clamp01(0.50f + pawn.needs.joy.CurLevel);
				else
					fun_factor = 1.00f;
			}

			return base_mtb * desire_factor * personality_factor * fun_factor;
		}

		public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
		{
			try
			{
				return base.TryIssueJobPackage(pawn, jobParams);
			}
			catch (NullReferenceException)
			{
				//--ModLog.Message("ThinkNode_ChancePerHour_Bestiality:TryIssueJobPackage - error message" + e.Message);
				//--ModLog.Message("ThinkNode_ChancePerHour_Bestiality:TryIssueJobPackage - error stacktrace" + e.StackTrace);
				return ThinkResult.NoJob; ;
			}
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Cooldown for breeding
	/// something like 4.0*0.2 = 0.8 hours
	/// </summary>
	public class ThinkNode_ChancePerHour_Breed : ThinkNode_ChancePerHour
	{
		protected override float MtbHours(Pawn pawn)
		{
			return xxx.config.comfort_prisoner_rape_mtbh_mul * 0.20f ;
		}

		public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
		{
			try
			{
				return base.TryIssueJobPackage(pawn, jobParams);
			}
			catch (NullReferenceException)
			{
				return ThinkResult.NoJob; ;
			}
		}
	}
}


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

namespace rjw
{
	public class ThinkNode_ChancePerHour_Fappin : ThinkNode_ChancePerHour
	{
		public static float get_fappin_mtb_hours(Pawn pawn)
		{
			float result = 1f;
			result /= 1f - pawn.health.hediffSet.PainTotal;

			float efficiency = pawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness);
			if (efficiency < 0.5f)
			{
				result /= efficiency * 2f;
			}

			if (!pawn.RaceProps.Humanlike)
			{
				return result * 4f;
			}
			if (RimWorld.LovePartnerRelationUtility.ExistingLovePartner(pawn) != null)
			{
				result *= 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)
			{
				result /= 1.25f; //This accounts for single men
			}

			result /= GenMath.FlatHill(0.0001f, 8f, 13f, 28f, 50f, 0.15f, pawn.ageTracker.AgeBiologicalYearsFloat);//this needs to be changed

			if (xxx.is_nympho(pawn))
			{
				result /= 2f;
			}

			return result;
		}

		private float GetAloneFactor(Pawn p)
		{
			bool isAlone = !p.Map.mapPawns.AllPawnsSpawned.Any(x => p.CanSee(x) && xxx.is_human(x));
			// More likely to fap if alone.
			return isAlone ? 0.6f : 1.2f;
		}

		protected override float MtbHours(Pawn p)
		{
			// No fapping for animals... for now, at least.
			// Maybe enable this for monsters girls and such in future, but that'll need code changes to avoid errors.
			if (xxx.is_animal(p))
				return -1.0f;

			bool is_horny = xxx.is_hornyorfrustrated(p);
			if (is_horny)
			{
				// More likely to fap if nude.
				float clothingFactor = p.apparel.PsychologicallyNude ? 0.8f : 1.0f;

				float SexNeedFactor = (4 - xxx.need_some_sex(p)) / 2f;
				return get_fappin_mtb_hours(p) * SexNeedFactor * GetAloneFactor(p) * clothingFactor;
			}

			return -1.0f;
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Cooldown for breeding
	/// something like 4.0*0.2 = 0.8 hours
	/// </summary>
	public class ThinkNode_ChancePerHour_MateBonded : ThinkNode_ChancePerHour
	{
		protected override float MtbHours(Pawn pawn)
		{
			return xxx.config.comfort_prisoner_rape_mtbh_mul * 0.20f ;
		}

		public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
		{
			try
			{
				return base.TryIssueJobPackage(pawn, jobParams);
			}
			catch (NullReferenceException)
			{
				return ThinkResult.NoJob; ;
			}
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Necro rape corpse
	/// </summary>
	public class ThinkNode_ChancePerHour_Necro : ThinkNode_ChancePerHour
	{
		protected override float MtbHours(Pawn pawn)
		{
			float base_mtb = xxx.config.comfort_prisoner_rape_mtbh_mul; // Default of 4.0

			float desire_factor;
			{
				var need_sex = pawn.needs.TryGetNeed<Need_Sex>();
				if (need_sex != null)
				{
					if (need_sex.CurLevel <= need_sex.thresh_frustrated())
						desire_factor = 0.15f;
					else if (need_sex.CurLevel <= need_sex.thresh_horny())
						desire_factor = 0.60f;
					else if (need_sex.CurLevel <= need_sex.thresh_satisfied())
						desire_factor = 1.00f;
					else // Recently had sex.
						desire_factor = 2.00f;
				}
				else
					desire_factor = 1.00f;
			}

			float personality_factor;
			{
				personality_factor = 1.0f;

				if (xxx.is_nympho(pawn))
					personality_factor *= 0.8f;
				if (xxx.is_prude(pawn) || pawn.story.traits.HasTrait(TraitDefOf.BodyPurist))
					personality_factor *= 2f;
				if (xxx.is_psychopath(pawn))
					personality_factor *= 0.5f;

				// Pawns with no necrophiliac trait should first try to find other outlets.
				if (!xxx.is_necrophiliac(pawn))
					personality_factor *= 8f;
				else
					personality_factor *= 0.5f;

				// Less likely to engage in necrophilia if the pawn has a lover.
				if (!xxx.IsSingleOrPartnersNotHere(pawn))
					personality_factor *= 1.25f;

				// Pawns with no records of prior necrophilia are less likely to engage in it.
				if (pawn.records.GetValue(xxx.CountOfSexWithCorpse) == 0)
					personality_factor *= 16f;
				else if (pawn.records.GetValue(xxx.CountOfSexWithCorpse) > 10)
					personality_factor *= 0.8f;
			}

			float fun_factor;
			{
				if ((pawn.needs.joy != null) && (xxx.is_necrophiliac(pawn)))
					fun_factor = Mathf.Clamp01(0.50f + pawn.needs.joy.CurLevel);
				else
					fun_factor = 1.00f;
			}

			// I'm normally against gender factors, but necrophilia is far more frequent among males. -Zaltys
			float gender_factor = (pawn.gender == Gender.Male) ? 1.0f : 3.0f;

			return base_mtb * desire_factor * personality_factor * fun_factor * gender_factor;
		}

		public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
		{
			try
			{
				return base.TryIssueJobPackage(pawn, jobParams);
			}
			catch (NullReferenceException)
			{
				return ThinkResult.NoJob;
			}
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Colonists and prisoners try to rape CP
	/// </summary>
	public class ThinkNode_ChancePerHour_RapeCP : ThinkNode_ChancePerHour
	{
		protected override float MtbHours(Pawn pawn)
		{
			var base_mtb = xxx.config.comfort_prisoner_rape_mtbh_mul; //Default 4.0

			float desire_factor;
			{
				var need_sex = pawn.needs.TryGetNeed<Need_Sex>();
				if (need_sex != null)
				{
					if (need_sex.CurLevel <= need_sex.thresh_frustrated())
						desire_factor = 0.10f;
					else if (need_sex.CurLevel <= need_sex.thresh_horny())
						desire_factor = 0.50f;
					else
						desire_factor = 1.00f;
				}
				else
					desire_factor = 1.00f;
			}

			float personality_factor;
			{
				personality_factor = 1.0f;
				if (xxx.has_traits(pawn))
				{
					// Most of the checks are done in the SexAppraiser.would_rape method.

					personality_factor = 1.0f;

					if (!RJWSettings.rape_beating)
					{
						if (xxx.is_bloodlust(pawn))
							personality_factor *= 0.5f;
					}

					if (xxx.is_nympho(pawn))
						personality_factor *= 0.5f;
					else if (xxx.is_prude(pawn) || pawn.story.traits.HasTrait(TraitDefOf.BodyPurist))
						personality_factor *= 2f;

					if (xxx.is_rapist(pawn))
						personality_factor *= 0.5f;
					if (xxx.is_psychopath(pawn))
						personality_factor *= 0.75f;
					else if (xxx.is_kind(pawn))
						personality_factor *= 5.0f;

					float rapeCount = pawn.records.GetValue(xxx.CountOfRapedHumanlikes) +
					                pawn.records.GetValue(xxx.CountOfRapedAnimals) +
					                pawn.records.GetValue(xxx.CountOfRapedInsects) +
					                pawn.records.GetValue(xxx.CountOfRapedOthers);

					// Pawns with few or no rapes are more reluctant to rape CPs.
					if (rapeCount < 3.0f)
						personality_factor *= 1.5f;
				}
			}

			float fun_factor;
			{
				if ((pawn.needs.joy != null) && (xxx.is_rapist(pawn) || xxx.is_psychopath(pawn)))
					fun_factor = Mathf.Clamp01(0.50f + pawn.needs.joy.CurLevel);
				else
					fun_factor = 1.00f;
			}

			float animal_factor = 1.0f;
			if (xxx.is_animal(pawn))
			{
				var parts = pawn.GetGenitalsList();
				// Much slower for female animals.
				animal_factor = Genital_Helper.has_male_bits(pawn, parts) ? 2.5f : 6f;
			}

			//if (xxx.is_animal(pawn)) { Log.Message("Chance for " + pawn + " : " + base_mtb * desire_factor * personality_factor * fun_factor * animal_factor); }
			return base_mtb * desire_factor * personality_factor * fun_factor * animal_factor;
		}

		public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
		{
			try
			{
				return base.TryIssueJobPackage(pawn, jobParams);
			}
			catch (NullReferenceException)
			{
				return ThinkResult.NoJob; ;
			}
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Called to determine if the non animal is eligible for a Bestiality job
	/// </summary>
	public class ThinkNode_ConditionalBestiality : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//if (p.Faction != null && p.Faction.IsPlayer)
			//	ModLog.Message("ThinkNode_ConditionalBestiality " + xxx.get_pawnname(p) + " is animal: " + xxx.is_animal(p));

			// No bestiality for animals, animal-on-animal is handled in Breed job.
			if (xxx.is_animal(p))
				return false;

			// Bestiality off
			if (!RJWSettings.bestiality_enabled)
				return false;

			// No free will while designated for rape.
			if (!RJWSettings.designated_freewill)
				if ((p.IsDesignatedComfort() || p.IsDesignatedBreeding()))
					return false;

			return true;
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Called to determine if the animal is eligible for a breed job
	/// </summary>
	public class ThinkNode_ConditionalCanBreed : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//ModLog.Message("ThinkNode_ConditionalCanBreed " + p);

			//Rimworld of Magic polymorphed humanlikes also get animal think node
			//if (p.Faction != null && p.Faction.IsPlayer)
			//	ModLog.Message("ThinkNode_ConditionalCanBreed " + xxx.get_pawnname(p) + " is animal: " + xxx.is_animal(p));

			// No Breed jobs for humanlikes, that's handled by bestiality.
			if (!xxx.is_animal(p))
				return false;

			// Animal stuff disabled.
			if (!RJWSettings.bestiality_enabled && !RJWSettings.animal_on_animal_enabled)
				return false;

			//return p.IsDesignatedBreedingAnimal() || RJWSettings.WildMode;
			return p.IsDesignatedBreedingAnimal();
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Called to determine if the animal is eligible for a mating with Bonded pawn
	/// </summary>
	public class ThinkNode_ConditionalCanMateBonded : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			if (!xxx.is_animal(p))
				return false;

			// Animal stuff disabled.
			if ((!RJWSettings.bestiality_enabled) || (!RJWSettings.animal_on_human_enabled))
				return false;

			if (xxx.HasBond(p))
				return true;

			else return false;
		}
	}
}


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

namespace rjw
{
	public class ThinkNode_ConditionalCanRapeCP : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//ModLog.Message("ThinkNode_ConditionalCanRapeCP " + pawn);

			if (!RJWSettings.rape_enabled)
				return false;

			// Hostiles cannot use CP.
			if (p.HostileTo(Faction.OfPlayer))
				return false;

			// Designated pawns are not allowed to rape other CP.
			if (!RJWSettings.designated_freewill)
				if ((p.IsDesignatedComfort() || p.IsDesignatedBreeding()))
					return false;

			// Animals cannot rape CP if the setting is disabled.
			//if (!(RJWSettings.bestiality_enabled && RJWSettings.animal_CP_rape) && xxx.is_animal(p) )
			//	return false;

			// Animals cannot rape CP
			if (xxx.is_animal(p))
				return false;

			// colonists(humans) cannot rape CP if the setting is disabled.
			if (!RJWSettings.colonist_CP_rape && p.IsColonist && xxx.is_human(p))
				return false;

			// Visitors(humans) cannot rape CP if the setting is disabled.
			if (!RJWSettings.visitor_CP_rape && p.Faction?.IsPlayer == false && xxx.is_human(p))
				return false;

			// Visitors(animals/caravan) cannot rape CP if the setting is disabled.
			if (!RJWSettings.visitor_CP_rape && p.Faction?.IsPlayer == false && p.Faction != Faction.OfInsects && xxx.is_animal(p))
				return false;

			// Wild animals, insects cannot rape CP.
			//if ((p.Faction == null || p.Faction == Faction.OfInsects) && xxx.is_animal(p))
			//	return false;

			return true;
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Pawn frustrated
	/// </summary>
	public class ThinkNode_ConditionalFrustrated : ThinkNode_Conditional
	{
		protected override bool Satisfied (Pawn p)
		{
			return xxx.is_frustrated(p);
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Pawn is horny
	/// </summary>
	public class ThinkNode_ConditionalHorny : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			return xxx.is_horny(p);
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Pawn HornyOrFrustrated
	/// </summary>
	public class ThinkNode_ConditionalHornyOrFrustrated : ThinkNode_Conditional
	{
		protected override bool Satisfied (Pawn p)
		{
			return xxx.is_hornyorfrustrated(p);
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Called to determine if the animal can mate(vanilla reproductory sex) with animals.
	/// </summary>
	public class ThinkNode_ConditionalMate : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//ModLog.Message("ThinkNode_ConditionalMate " + xxx.get_pawnname(p));
			return (xxx.is_animal(p) && RJWSettings.animal_on_animal_enabled);
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Called to determine if the pawn can engage in necrophilia.
	/// </summary>
	public class ThinkNode_ConditionalNecro : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//ModLog.Message("ThinkNode_ConditionalNecro " + p);

			if (!RJWSettings.necrophilia_enabled)
				return false;

			// No necrophilia for animals. At least for now.
			// This would be easy to enable, if we actually want to add it.
			if (xxx.is_animal(p))
				return false;

			// No free will while designated for rape.
			if (!RJWSettings.designated_freewill)
				if ((p.IsDesignatedComfort() || p.IsDesignatedBreeding()))
					return false;

			return true;
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Nymph nothing to do, seek sex-> join in bed
	/// </summary>
	public class ThinkNode_ConditionalNympho : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//ModLog.Message("ThinkNode_ConditionalNympho " + p);

			if (xxx.is_nympho(p))
				if (p.Faction == null || !p.Faction.IsPlayer)
					return false;
				else
					return true;

			return false;
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Will nympho rape when frustrated?
	/// </summary>
	public class ThinkNode_ConditionalNymphoFrustratedRape : ThinkNode_Conditional
	{
		protected override bool Satisfied (Pawn p)
		{
			return RJWSettings.NymphFrustratedRape;
		}
	}
}


code:
using Verse;
using Verse.AI;

namespace rjw
{
	/// <summary>
	/// Rapist, chance to trigger random rape
	/// </summary>
	public class ThinkNode_ConditionalRapist : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			if (!RJWSettings.rape_enabled)
				return false;

			if (xxx.is_animal(p))
				return false;

			if (!xxx.is_rapist(p))
				return false;

			// No free will while designated for rape.
			if (!RJWSettings.designated_freewill)
				if ((p.IsDesignatedComfort() || p.IsDesignatedBreeding()))
					return false;

			if (!xxx.IsSingleOrPartnersNotHere(p))
			{
				return false;
			}
			else
				return true;
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Called to determine if the pawn can engage in sex.
	/// This should be used as the first conditional for sex-related thinktrees.
	/// </summary>
	public class ThinkNode_ConditionalSexChecks : ThinkNode_Conditional
	{
		protected override bool Satisfied(Pawn p)
		{
			//ModLog.Message("ThinkNode_ConditionalSexChecks " + xxx.get_pawnname(p));
			//if (p.Faction != null && p.Faction.IsPlayer)
			//	ModLog.Message("ThinkNode_ConditionalSexChecks " + xxx.get_pawnname(p) + " is animal: " + xxx.is_animal(p));

			// Downed, Drafted and Awake are checked in core ThinkNode_ConditionalCanDoConstantThinkTreeJobNow.
			if (p.Map == null)
				return false;

			// Pawn(animal) is fogged, no sex, save tps
			if (p.Fogged())
				return false;

			// Setting checks.
			if (!xxx.can_do_loving(p))
				return false;
			else if (xxx.is_animal(p) && !RJWSettings.bestiality_enabled && !RJWSettings.animal_on_animal_enabled)
				return false;

			// State checks. No sex while trying to leave map.
			if (p.mindState?.duty?.def != null)
				if (p.mindState.duty.def == DutyDefOf.SleepForever)
					return false;
				else if (p.mindState.duty.def == VanillaDutyDefOf.EnterTransporter)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.EnterTransporterAndDefendSelf)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.ExitMapBest)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.ExitMapBestAndDefendSelf)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.ExitMapNearDutyTarget)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.ExitMapRandom)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.PrepareCaravan_CollectAnimals)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.PrepareCaravan_GatherAnimals)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.PrepareCaravan_GatherDownedPawns)
					return false;
				else if (p.mindState.duty.def == DutyDefOf.PrepareCaravan_GatherItems)
					return false;

			// No sex while starving or badly hurt.
			return ((!p.needs?.food?.Starving) ?? true && (xxx.is_healthy_enough(p) || !xxx.is_human(p)));
		}
	}
}


code:
using RimWorld;
using Verse;

namespace rjw
{
	public class ThoughtWorker_FeelingBroken : ThoughtWorker
	{
		public static int Clamp(int value, int min, int max)
		{
			return (value < min) ? min : (value > max) ? max : value;
		}

		protected override ThoughtState CurrentStateInternal(Pawn p)
		{
			var brokenstages = p.health.hediffSet.GetFirstHediffOfDef(xxx.feelingBroken);
			if (brokenstages != null && brokenstages.CurStageIndex != 0)
			{
				if (xxx.is_masochist(p) && brokenstages.CurStageIndex >= 2)
				{
					return ThoughtState.ActiveAtStage(2); // begging for more
				}
				return ThoughtState.ActiveAtStage(Clamp(brokenstages.CurStageIndex - 1, 0, 1));
			}
			return ThoughtState.Inactive;
		}
	}
}


code:
using RimWorld;
using Verse;

namespace rjw
{
	public class ThoughtWorker_NeedSex : ThoughtWorker
	{
		protected override ThoughtState CurrentStateInternal(Pawn p)
		{
			var sex_need = p.needs.TryGetNeed<Need_Sex>();

			if (sex_need != null)
				if (xxx.can_do_loving(p))
			{
				var lev = sex_need.CurLevel;
				if (lev <= sex_need.thresh_frustrated())
					return ThoughtState.ActiveAtStage(0);
				else if (lev <= sex_need.thresh_horny())
					return ThoughtState.ActiveAtStage(1);
				else if (lev >= sex_need.thresh_satisfied())
					return ThoughtState.ActiveAtStage(2);
			}

			return ThoughtState.Inactive;
		}
	}
}


code:
using RimWorld;
using Verse;

namespace rjw
{
	//This thought system of RW is retarded AF. It needs separate thought handler for each hediff.
	public abstract class ThoughtWorker_SexChange : ThoughtWorker
	{
		public virtual HediffDef hediff_served { get; }
		protected override ThoughtState CurrentStateInternal(Pawn pawn)
		{
			//Log.Message(" "+this.GetType() + " is called for " + pawn +" and hediff" + hediff_served);
			Hediff denial = pawn.health.hediffSet.GetFirstHediffOfDef(hediff_served);
			//Log.Message("Hediff of the class is null " + (hediff_served == null));
			if (denial != null && denial.CurStageIndex!=0)
			{
				//Log.Message("Current denial level is  " + denial.CurStageIndex );
				return ThoughtState.ActiveAtStage(denial.CurStageIndex-1);
			}
			return ThoughtState.Inactive;
		}
	}
	public class ThoughtWorker_MtT : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.m2t; } }
	}
	public class ThoughtWorker_MtF:ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.m2f; }  }
	}
	public class ThoughtWorker_MtH : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.m2h; } }
	}
	public class ThoughtWorker_FtT : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.f2t; } }
	}
	public class ThoughtWorker_FtM : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.f2m; } }
	}
	public class ThoughtWorker_FtH : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.f2h; } }
	}
	public class ThoughtWorker_HtT : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.h2t; } }
	}
	public class ThoughtWorker_HtM : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.h2m; } }
	}
	public class ThoughtWorker_HtF : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.h2f; } }
	}
	public class ThoughtWorker_TtH : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.t2h; } }
	}
	public class ThoughtWorker_TtM : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.t2m; } }
	}
	public class ThoughtWorker_TtF : ThoughtWorker_SexChange
	{
		public override HediffDef hediff_served { get { return GenderHelper.t2f; } }
	}
}


code:
using Verse;
using Verse.AI.Group;

namespace rjw
{
	public class Trigger_SexSatisfy : TriggerFilter
	{
		private const int CheckInterval = 120;
		private const int TickTimeout = 900;
		private int currentTick = 0;
		public float targetValue = 0.3f;

		public Trigger_SexSatisfy(float t)
		{
			this.targetValue = t;
			currentTick = 0;
		}

		public override bool AllowActivation(Lord lord, TriggerSignal signal)
		{
			currentTick++;
			if (signal.type == TriggerSignalType.Tick && Find.TickManager.TicksGame % CheckInterval == 0)
			{
				float? avgValue = null;
				foreach (var pawn in lord.ownedPawns)
				{
					/*foreach(Pawn p in lord.Map.mapPawns.PawnsInFaction(Faction.OfPlayer))
					{
					}*/
					Need_Sex n = pawn.needs.TryGetNeed<Need_Sex>();
					//if (n != null && pawn.gender == Gender.Male && !pawn.Downed)
					if(xxx.can_rape(pawn) && (xxx.is_healthy_enough(pawn) && xxx.IsTargetPawnOkay(pawn) || !xxx.is_human(pawn)) && Find.TickManager.TicksGame > pawn.mindState.canLovinTick)
					{
						avgValue = (avgValue == null) ? n.CurLevel : (avgValue + n.CurLevel) / 2f;
					}
				}
				//--Log.Message("[ABF]Trigger_SexSatisfy::ActivateOn Checked value :" + avgValue + "/" + targetValue);
				return avgValue == null || avgValue >= targetValue;
			}
			return currentTick >= TickTimeout;
		}
	}
}


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

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:
<?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>

	</modDependencies>
	<modDependenciesByVersion>
		<v1.1>

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

		</v1.1>
		<v1.2>

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

		</v1.2>
		<v1.3>

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

		</v1.3>
		<v1.4>

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

		</v1.4>
	</modDependenciesByVersion>
	<loadAfter>

UnlimitedHugs.HugsLib

brrainz.harmony

	</loadAfter>
	<incompatibleWith>

gregorycurrie.AnimalGenetics

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
for crypto bros:
USDT(TRC20):TAS9QbvuF6AquJ98TqG653bPDugC2a6mnk
USDT(ERC20):0x6c61085700f4ad941df80234fbfb8a861b14b0de
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.6.3</version>
	<dependencies/>
	<incompatibleWith/>
	<loadAfter/>
	<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', '.gitattributes', '.gitignore', '1.1\Source', '1.2\Source', '1.3\Source', '1.4\Source', '1.5\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)
for crypto bros:
USDT(TRC20):TAS9QbvuF6AquJ98TqG653bPDugC2a6mnk
USDT(ERC20):0x6c61085700f4ad941df80234fbfb8a861b14b0de

[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 ;)