code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "AssaultColony"]/thinkNode/subNodes/li[@Class="JobGiver_AIFightEnemies"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "AssaultColony"]/thinkNode/subNodes/li[@Class="JobGiver_AITrashColonyClose"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "Sapper"]/thinkNode/subNodes/li[@Class="JobGiver_AIFightEnemies"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "Defend"]/thinkNode/subNodes/li[@Class="ThinkNode_ForbidOutsideFlagRadius"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendBase"]/thinkNode/subNodes/li[@Class="JobGiver_AIDefendPoint"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "HuntEnemiesIndividual"]/thinkNode/subNodes/li[@Class="JobGiver_AIFightEnemies"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendAndExpandHive"]/thinkNode/subNodes/li[@Class="ThinkNode_Tagger"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendBase"]/thinkNode/subNodes/li[@Class="ThinkNode_ForbidOutsideFlagRadius"]/subNodes/li[@Class="ThinkNode_Subtree"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/ThinkTreeDef[defName="MentalStateNonCritical"]/thinkRoot[@Class="ThinkNode_Tagger"]/subNodes/li[stateClass="MentalState_Manhunter"]/subNodes/li[@Class="ThinkNode_Priority"]/subNodes/li[@Class="JobGiver_Manhunter"]</xpath>

		<value>

		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThinkTreeDef[defName="MentalStateCritical"]/thinkRoot[@Class="ThinkNode_Tagger"]/subNodes</xpath>
		<value>

				<state>RandomRape</state>
				<subNodes>

						<need>Rest</need>
						<threshold>0.05</threshold>
						<invert>true</invert>
						<subNodes>

						</subNodes>

						<minPriority>0.5</minPriority>
						<subNodes>

								<subNodes>

								</subNodes>

						</subNodes>

				</subNodes>

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


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

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

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

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

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

license: mit


code:
And why would you read me?

You can support current Dev(Me) here:
https://www.patreon.com/Ed86

Mod git:
https://gitgud.io/Ed86/rjw

Discord:
https://discord.gg/CXwHhv8

LoversLab:
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 .7z into "...steam/steamapps/common/rimworld/mods/RJW", you will see RimJobWorld.Main.csproj
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

Contibuting:
use TABS not SPACES for xml/cs, please?
do comments in code for other people

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


code:
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{22F82FFF-8BD4-4CEE-9F22-C7DA71281E72}</ProjectGuid>
    <OutputType>Library</OutputType>
    <NoStandardLibraries>false</NoStandardLibraries>
    <AssemblyName>RJW</AssemblyName>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <TargetFrameworkProfile />
    <ShouldCreateLogs>True</ShouldCreateLogs>
    <AdvancedSettingsExpanded>True</AdvancedSettingsExpanded>
    <UpdateAssemblyVersion>True</UpdateAssemblyVersion>
    <UpdateAssemblyFileVersion>True</UpdateAssemblyFileVersion>
    <UpdateAssemblyInfoVersion>True</UpdateAssemblyInfoVersion>
    <AssemblyVersionSettings>None.None.IncrementOnDemand.Increment</AssemblyVersionSettings>
    <AssemblyFileVersionSettings>None.None.IncrementOnDemand.None</AssemblyFileVersionSettings>
    <AssemblyInfoVersionSettings>None.None.IncrementOnDemand.None</AssemblyInfoVersionSettings>
    <PrimaryVersionType>AssemblyVersionAttribute</PrimaryVersionType>
    <AssemblyVersion>1.6.0.493</AssemblyVersion>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>Assemblies\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <FileAlignment>4096</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>none</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>Assemblies\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <LangVersion>latest</LangVersion>
  </PropertyGroup>
  <PropertyGroup>
    <RootNamespace>rjw</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Source\Common\CondomUtility.cs" />
    <Compile Include="Source\Common\Data\DesignatorsData.cs" />
    <Compile Include="Source\Common\Data\RaceGroupDef.cs" />
    <Compile Include="Source\Common\Data\RaceTag.cs" />
    <Compile Include="Source\Common\Helpers\BreastSize_Helper.cs" />
    <Compile Include="Source\Common\Data\PawnData.cs" />
    <Compile Include="Source\Common\Helpers\HediffHelper.cs" />
    <Compile Include="Source\Common\Helpers\RaceGroupDef_Helper.cs" />
    <Compile Include="Source\Common\Helpers\Sexualizer.cs" />
    <Compile Include="Source\Common\Helpers\SexPartAdder.cs" />
    <Compile Include="Source\Common\Logger.cs" />
    <Compile Include="Source\Common\PawnExtensions.cs" />
    <Compile Include="Source\Common\SexAppraiser.cs" />
    <Compile Include="Source\Common\SexPartType.cs" />
    <Compile Include="Source\Common\TraitComparer.cs" />
    <Compile Include="Source\Comps\Orientation.cs" />
    <Compile Include="Source\Comps\QuirkAdder.cs" />
    <Compile Include="Source\Comps\SexProps.cs" />
    <Compile Include="Source\Comps\Quirk.cs" />
    <Compile Include="Source\Designators\Breeder.cs" />
    <Compile Include="Source\Designators\Breedee.cs" />
    <Compile Include="Source\Designators\Comfort.cs" />
    <Compile Include="Source\Designators\Hero.cs" />
    <Compile Include="Source\Designators\Milking.cs" />
    <Compile Include="Source\Designators\Utility.cs" />
    <Compile Include="Source\Designators\Service.cs" />
    <Compile Include="Source\Harmony\Patch_PawnGenerator_GenerateNewPawnInternal.cs" />
    <Compile Include="Source\Harmony\patch_races.cs" />
    <Compile Include="Source\Harmony\patch_selector.cs" />
    <Compile Include="Source\Harmony\patch_surgery.cs" />
    <Compile Include="Source\Harmony\patch_ui_hero.cs" />
    <Compile Include="Source\Harmony\patch_ui_rjw_buttons.cs" />
    <Compile Include="Source\Harmony\SocialCardUtilityPatch.cs" />
    <Compile Include="Source\Hediffs\Hediff_PartBase.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_Sex.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_WhoreExperience.cs" />
    <Compile Include="Source\Modules\Androids\AndroidsCompatibility.cs" />
    <Compile Include="Source\Modules\Bondage\bondage_gear.cs" />
    <Compile Include="Source\Common\Helpers\Breeder_Helper.cs" />
    <Compile Include="Source\Modules\Multiplayer\Multiplayer.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\RJWAssociatedHediffAttribute.cs" />
    <Compile Include="Source\Modules\SemenOverlay\BukkakeContent.cs" />
    <Compile Include="Source\Modules\STD\std_def.cs" />
    <Compile Include="Source\Modules\STD\std_spreader.cs" />
    <Compile Include="Source\Modules\STD\std_updater.cs" />
    <Compile Include="Source\Settings\config.cs" />
    <Compile Include="Source\Common\CORE_EXPOSED\CORE_EXPOSED.cs" />
    <Compile Include="Source\Common\Data\DataStore.cs" />
    <Compile Include="Source\Common\Helpers\Gender_Helper.cs" />
    <Compile Include="Source\Common\Helpers\Genital_Helper.cs" />
    <Compile Include="Source\Common\MapCom_Injector.cs" />
    <Compile Include="Source\Common\MiscTranslationDef.cs" />
    <Compile Include="Source\Common\Data\ModData.cs" />
    <Compile Include="Source\Modules\Pregnancy\Pregnancy_Helper.cs" />
    <Compile Include="Source\Modules\SemenOverlay\SemenHelper.cs" />
    <Compile Include="Source\Common\Helpers\SexUtility.cs" />
    <Compile Include="Source\Modules\STD\std.cs" />
    <Compile Include="Source\Common\Data\StringListDef.cs" />
    <Compile Include="Source\Common\Unprivater.cs" />
    <Compile Include="Source\Modules\Whoring\Whoring_Helper.cs" />
    <Compile Include="Source\Common\xxx.cs" />
    <Compile Include="Source\Comps\CompAdder.cs" />
    <Compile Include="Source\Modules\Bondage\Comps\CompBondageGear.cs" />
    <Compile Include="Source\Modules\Bondage\Comps\CompGetBondageGear.cs" />
    <Compile Include="Source\Modules\Bondage\Comps\CompHoloCryptoStamped.cs" />
    <Compile Include="Source\Comps\CompProperties_RJW.cs" />
    <Compile Include="Source\Comps\CompRJW.cs" />
    <Compile Include="Source\Modules\Bondage\Comps\CompStampedApparelKey.cs" />
    <Compile Include="Source\Modules\Bondage\Comps\CompUnlockBondageGear.cs" />
    <Compile Include="Source\Modules\SemenOverlay\DefOf\RJW_HediffDefOf.cs" />
    <Compile Include="Source\Modules\SemenOverlay\DefOf\RJW_JobDefOf.cs" />
    <Compile Include="Source\Designators\_RJWdesignationsWidget.cs" />
    <Compile Include="Source\Harmony\First.cs" />
    <Compile Include="Source\Harmony\patch_ABF.cs" />
    <Compile Include="Source\Harmony\Patch_PawnGenerator_GenerateTraits.cs" />
    <Compile Include="Source\Harmony\patch_bondage_gear.cs" />
    <Compile Include="Source\Harmony\patch_DubsBadHygiene.cs" />
    <Compile Include="Source\Harmony\patch_lovin.cs" />
    <Compile Include="Source\Harmony\patch_pregnancy.cs" />
    <Compile Include="Source\Harmony\patch_semenOverlay.cs" />
    <Compile Include="Source\Harmony\SexualityCard.cs" />
    <Compile Include="Source\Harmony\SexualityCardInternal.cs" />
    <Compile Include="Source\Hediffs\HediffComp_FeelingBroken.cs" />
    <Compile Include="Source\Modules\SemenOverlay\Hediffs\Hediff_Bukkake.cs" />
    <Compile Include="Source\Hediffs\Hediff_Cocoon.cs" />
    <Compile Include="Source\Modules\SemenOverlay\Hediffs\Hediff_Semen.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\HediffDef_EnemyImplants.cs" />
    <Compile Include="Source\Hediffs\Hediff_ID.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_InsectEggPregnancy.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_MCEvents.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_MechanoidPregnancy.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_MechImplants.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\HeDiff_MicroComputer.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_ParasitePregnancy.cs" />
    <Compile Include="Source\Hediffs\Hediff_Submitting.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_BasePregnancy.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_BestialPregnancy.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_HumanlikePregnancy.cs" />
    <Compile Include="Source\Modules\Pregnancy\Hediffs\Hediff_SimpleBaby.cs" />
    <Compile Include="Source\Modules\Nymphs\Incidents\IncidentWorker_NymphJoins.cs" />
    <Compile Include="Source\Modules\Nymphs\Incidents\IncidentWorker_NymphVisitorGroup.cs" />
    <Compile Include="Source\Modules\Nymphs\Incidents\IncidentWorker_TestInc.cs" />
    <Compile Include="Source\Modules\Nymphs\Incidents\IncidentWorker_TestInc2.cs" />
    <Compile Include="Source\Interactions\InteractionWorker_SexAttempt.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_BestialityForMale.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_BestialityForFemale.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_Breeding.cs" />
    <Compile Include="Source\Modules\SemenOverlay\JobDrivers\JobDriver_CleanSelf.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_Fappin.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_GettinLoved.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_GettinRaped.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_JoinInBed.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_QuickFap.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RapeEnemyByHumanlike.cs" />
    <Compile Include="Source\Modules\Whoring\JobDrivers\JobDriver_WhoreInvitingVisitors.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_PrisonerComfortRapin.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RandomRape.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_Rape.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RapeEnemy.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RapeEnemyByAnimal.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RapeEnemyByInsect.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RapeEnemyByMech.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_RapeEnemyToParasite.cs" />
    <Compile Include="Source\Modules\Bondage\JobDrivers\JobDriver_StruggleInBondageGear.cs" />
    <Compile Include="Source\Modules\Bondage\JobDrivers\JobDriver_UseItemOn.cs" />
    <Compile Include="Source\JobDrivers\JobDriver_ViolateCorpse.cs" />
    <Compile Include="Source\Modules\Whoring\JobDrivers\JobDriver_WhoreIsServingVisitors.cs" />
    <Compile Include="Source\JobGivers\JobGiver_AIRapePrisoner.cs" />
    <Compile Include="Source\JobGivers\JobGiver_Bestiality.cs" />
    <Compile Include="Source\JobGivers\JobGiver_Breed.cs" />
    <Compile Include="Source\JobGivers\JobGiver_ComfortPrisonerRape.cs" />
    <Compile Include="Source\JobGivers\JobGiver_DoFappin.cs" />
    <Compile Include="Source\JobGivers\JobGiver_JoinInBed.cs" />
    <Compile Include="Source\JobGivers\JobGiver_RandomRape.cs" />
    <Compile Include="Source\JobGivers\JobGiver_RapeEnemy.cs" />
    <Compile Include="Source\JobGivers\JobGiver_ViolateCorpse.cs" />
    <Compile Include="Source\Modules\Whoring\JobGivers\JobGiver_WhoreInvitingVisitors.cs" />
    <Compile Include="Source\MentalStates\MentalState_RandomRape.cs" />
    <Compile Include="Source\MentalStates\SexualMentalState.cs" />
    <Compile Include="Source\Needs\Need_Sex.cs" />
    <Compile Include="Source\PawnCapacities\BodyPartTagDefOf.cs" />
    <Compile Include="Source\PawnCapacities\PawnCapacityWorker_Fertility.cs" />
    <Compile Include="Source\Modules\Nymphs\Pawns\Nymph_Backstories.cs" />
    <Compile Include="Source\Modules\Nymphs\Pawns\Nymph_Generator.cs" />
    <Compile Include="Source\Recipes\Recipe_GrowBreasts.cs" />
    <Compile Include="Source\Recipes\Install_Part\Recipe_InstallPart.cs" />
    <Compile Include="Source\Modules\Pregnancy\Recipes\Recipe_Abortion.cs" />
    <Compile Include="Source\Modules\Bondage\Recipes\Recipe_ChastityBelt.cs" />
    <Compile Include="Source\Modules\Pregnancy\Recipes\Recipe_ClaimChild.cs" />
    <Compile Include="Source\Modules\Pregnancy\Recipes\Recipe_DeterminePregnancy.cs" />
    <Compile Include="Source\Modules\Bondage\Recipes\Recipe_ForceOffGear.cs" />
    <Compile Include="Source\Modules\Pregnancy\Recipes\Recipe_InstallIUD.cs" />
    <Compile Include="Source\Modules\Pregnancy\Recipes\Recipe_PregnancyHackMech.cs" />
    <Compile Include="Source\Modules\Pregnancy\Recipes\Recipe_Sterilize.cs" />
    <Compile Include="Source\Recipes\Recipe_Restraints.cs" />
    <Compile Include="Source\Recipes\Recipe_ShrinkBreasts.cs" />
    <Compile Include="Source\Recipes\Remove_Part\Recipe_RemoveAnus.cs" />
    <Compile Include="Source\Recipes\Remove_Part\Recipe_RemoveBreasts.cs" />
    <Compile Include="Source\Recipes\Remove_Part\Recipe_RemoveGenitals.cs" />
    <Compile Include="Source\Recipes\Remove_Part\Recipe_RemovePart.cs" />
    <Compile Include="Source\Recipes\Transgender\Recipe_MakeFuta.cs" />
    <Compile Include="Source\Settings\RJWDebugSettings.cs" />
    <Compile Include="Source\Settings\RJWHookupSettings.cs" />
    <Compile Include="Source\Settings\RJWPregnancySettings.cs" />
    <Compile Include="Source\Settings\RJWSettings.cs" />
    <Compile Include="Source\Settings\RJWSettingsController.cs" />
    <Compile Include="Source\Settings\RJWSexSettings.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ChancePerHour_Bestiality.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ChancePerHour_Breed.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ChancePerHour_Fappin.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ChancePerHour_Necro.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ChancePerHour_RapeCP.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalBestiality.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalCanBreed.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalCanRapeCP.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalFrustrated.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalHorny.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalMate.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalNecro.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalNympho.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalRapist.cs" />
    <Compile Include="Source\ThinkTreeNodes\ThinkNode_ConditionalSexChecks.cs" />
    <Compile Include="Source\Modules\Whoring\ThinkTreeNodes\ThinkNode_ConditionalWhore.cs" />
    <Compile Include="Source\Modules\Bondage\Thoughts\ThoughtWorker_Bound.cs" />
    <Compile Include="Source\Thoughts\ThoughtWorker_FeelingBroken.cs" />
    <Compile Include="Source\Modules\STD\Thoughts\ThoughtWorker_ItchyCrotch.cs" />
    <Compile Include="Source\Thoughts\ThoughtWorker_NeedSex.cs" />
    <Compile Include="Source\Thoughts\ThoughtWorker_SexChange.cs" />
    <Compile Include="Source\Modules\STD\Thoughts\ThoughtWorker_SyphiliticThoughts.cs" />
    <Compile Include="Source\Modules\STD\Thoughts\ThoughtWorker_WastingAway.cs" />
    <Compile Include="Source\Modules\Whoring\Thoughts\ThoughtWorker_Whore.cs" />
    <Compile Include="Source\Triggers\Trigger_SexSatisfy.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_BestialityForFemale.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_BestialityForMale.cs" />
    <Compile Include="Source\Modules\SemenOverlay\WorkGivers\WorkGiver_CleanSelf.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_Fap.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_Fap_Bed.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_Rape.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_RapeCP.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_RapeEnemy.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_Sex.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_Sexchecks.cs" />
    <Compile Include="Source\WorkGivers\WorkGiver_ViolateCorpse.cs" />
    <Content Include=".gitattributes" />
    <Content Include=".gitignore" />
    <Compile Include="Source\Settings\Settings.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_CountOfWhore.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_IsWhore.cs" />
    <Compile Include="Source\MainTab\MainTabWindow_Brothel.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_Mood.cs" />
    <Compile Include="Source\MainTab\PawnTable_Whores.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_RoomAdjustmentOfWhore.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_PriceRangeOfWhore.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_AverageMoneyByWhore.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_TextCenter.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_IsPrisoner.cs" />
    <Compile Include="Source\MainTab\PawnColumnWorker_EarnedMoneyByWhore.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="LICENSE" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="%24HugsLibChecker, Version=0.5.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\UnlimitedHugs.Rimworld.HugsLibChecker.5.0.0\lib\net35\$HugsLibChecker.dll</HintPath>
      <SpecificVersion>False</SpecificVersion>
      <Private>False</Private>
    </Reference>
    <Reference Include="0Harmony, Version=1.2.0.1, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\UnlimitedHugs.Rimworld.HugsLib.6.1.1\lib\net35\0Harmony.dll</HintPath>
      <SpecificVersion>False</SpecificVersion>
      <Private>True</Private>
    </Reference>
    <Reference Include="0MultiplayerAPI">
      <HintPath>packages\Multiplayer\Assemblies\0MultiplayerAPI.dll</HintPath>
    </Reference>
    <Reference Include="Assembly-CSharp">
      <HintPath>..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="HugsLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\UnlimitedHugs.Rimworld.HugsLib.6.1.1\lib\net35\HugsLib.dll</HintPath>
      <SpecificVersion>False</SpecificVersion>
      <Private>False</Private>
    </Reference>
    <Reference Include="NAudio">
      <HintPath>..\..\RimWorldWin64_Data\Managed\NAudio.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="NVorbis">
      <HintPath>..\..\RimWorldWin64_Data\Managed\NVorbis.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Psychology">
      <HintPath>packages\Psychology.2018-11-18\Assemblies\Psychology.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="RimWorldChildren">
      <HintPath>packages\ChildrenAndPregnancy.0.4e\Assemblies\RimWorldChildren.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="SyrTraits">
      <HintPath>packages\SYR.Individuality.1.1.4\Assemblies\SyrTraits.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="System" />
    <Reference Include="UnityEngine">
      <HintPath>..\..\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.UI">
      <HintPath>..\..\RimWorldWin64_Data\Managed\UnityEngine.UI.dll</HintPath>
      <Private>False</Private>
    </Reference>
  </ItemGroup>
  <ItemGroup />
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSHARP.Targets" />
  <ProjectExtensions>
    <VisualStudio AllowExistingFolder="true" />
  </ProjectExtensions>
</Project>


code:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProjectView>ShowAllFiles</ProjectView>
  </PropertyGroup>
</Project>


code:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2024
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RimJobWorld.Main", "RimJobWorld.Main.csproj", "{22F82FFF-8BD4-4CEE-9F22-C7DA71281E72}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{22F82FFF-8BD4-4CEE-9F22-C7DA71281E72}.Debug|Any CPU.ActiveCfg = Release|Any CPU
		{22F82FFF-8BD4-4CEE-9F22-C7DA71281E72}.Debug|Any CPU.Build.0 = Release|Any CPU
		{22F82FFF-8BD4-4CEE-9F22-C7DA71281E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{22F82FFF-8BD4-4CEE-9F22-C7DA71281E72}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {16BA61E5-4C97-4E73-926D-6718DE8E4776}
	EndGlobalSection
EndGlobal


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

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

namespace rjw_CORE_EXPOSED
{
	public static class JobDriver_Lovin
	{
		public static readonly SimpleCurve LovinIntervalHoursFromAgeCurve = new SimpleCurve
		{
			new CurvePoint(1f,  12f),
			new CurvePoint(16f, 6f),
			new CurvePoint(22f, 9f),
			new CurvePoint(30f, 12f),
			new CurvePoint(50f, 18f),
			new CurvePoint(75f, 24f)
		};
	}

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

		private float bonusPerLevel = 0.05f;

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

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

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

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

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

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

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

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

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

		// spawn rjw stuff
		public static void SpawnThingsFromHediffs(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			if (!pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Contains(part))
			{
				return;
			}
			if (pawn.Dead)
			{
				return;
			}
			IEnumerable<Hediff> enumerable = from x in pawn.health.hediffSet.hediffs
											 where x.Part == part
											 select x;
			//RJW parts and other implants?
			foreach (Hediff current in enumerable)
			{
				if (current.def.spawnThingOnRemoved != null)
				{
					//rjw implants/parts
					Thing thing = GenSpawn.Spawn(current.def.spawnThingOnRemoved, pos, map);
					//Log.Message("SpawnThingsFromHediffs test 1 " + current);
					//current.ExposeData();
					//thing.ExposeData();
					//Log.Message("SpawnThingsFromHediffs test 2 " + current);
					//Scribe_Values.Look<float>(ref part.Size, "size", 1);
					//Log.Message("SpawnThingsFromHediffs test 3 " + current);
				}
			}
			//spawn sub parts? not sure why would it call itself but w/e
			for (int i = 0; i < part.parts.Count; i++)
			{
				MedicalRecipesUtility.SpawnThingsFromHediffs(pawn, part.parts[i], pos, map);
			}
		}
	}

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

		private const int ViolationGoodwillImpact = -15;

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

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

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

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						BodyPartRecord record = bpList[j];
						if (record.def == part)
						{
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record
														select x;
							if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

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

	public class Recipe_AddBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						BodyPartRecord record = bpList[j];
						if (record.def == part)
						{
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record
														select x;
							if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

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


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

namespace rjw
{
	public class CondomUtility
	{
		public static readonly RecordDef CountOfCondomsUsed = DefDatabase<RecordDef>.GetNamed("CountOfCondomsUsed");

		// TryUseCondom returns whether it was able to remove one condom from the pawn
		public static bool TryUseCondom(Pawn pawn)
		{
			if (!xxx.is_human(pawn)) return false;
			if (xxx.has_quirk(pawn, "ImpregnationFetish")) return false;
			List<Thing> pawn_condoms = pawn.inventory.innerContainer.ToList().FindAll(obj => obj.def == ThingDef.Named("Condom"));
			if (pawn_condoms.Any())
			{
				var stack = pawn_condoms.Pop();
				stack.stackCount--;
				if (stack.stackCount <= 0)
				{
					stack.Destroy();
				}
				return true;
			}
			return false;
		}

		// UseCondom applies the effects of having used a condom.
		public static void useCondom(Pawn pawn)
		{
			if (!xxx.is_human(pawn)) return;
			pawn.records.Increment(CountOfCondomsUsed);
			pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("SexWithCondom"));
		}

		public static void GetCondomFromRoom(Pawn pawn)
		{
			if (!xxx.is_human(pawn)) return;
			if (xxx.has_quirk(pawn, "ImpregnationFetish")) return;
			List<Thing> condoms_in_room = pawn.GetRoom().ContainedAndAdjacentThings.FindAll(obj => obj.def == ThingDef.Named("Condom") && pawn.Position.DistanceToSquared(obj.Position) < 10);
			//List<Thing> condoms_in_room = pawn.ownership.OwnedRoom?.ContainedAndAdjacentThings.FindAll(obj => obj.def == ThingDef.Named("Condom"));
			if (condoms_in_room.Any())
			{
				pawn.inventory.innerContainer.TryAdd(condoms_in_room.Pop().SplitOff(1));
			}
		}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Hugslib Utility Data object storing the RJW info
	/// also implements extensions to Pawn method
	/// is used as a static field in PawnData
	/// </summary>
	public class DataStore : UtilityWorldObject
	{
		public Dictionary<int, PawnData> PawnData = new Dictionary<int, PawnData> ();
		//public Dictionary<int, PartsData> PartsData = new Dictionary<int, PartsData> ();

		public override void ExposeData()
		{
			if (Scribe.mode==LoadSaveMode.Saving)
				PawnData.RemoveAll(item => item.Value==null || !item.Value.IsValid);
			base.ExposeData();
			Scribe_Collections.Look(ref PawnData, "Data", LookMode.Value, LookMode.Deep);
			//Scribe_Collections.Look(ref PartsData, "Data", LookMode.Value, LookMode.Deep);
			if (Scribe.mode == LoadSaveMode.LoadingVars)
			{
				if (PawnData == null) PawnData = new Dictionary<int, PawnData>();
				//if (PartsData == null) PartsData = new Dictionary<int, PartsData>();
			}
		}

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

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

		//public PartsData GetPartsData(Thing thing)
		//{
		//	PartsData res;
		//	//--Log.Message("Getting data for " + thing);
		//	//--Log.Message("Pawn " + thing + " id " + thing.thingIDNumber);
		//	//--Log.Message("PartsData isn't null " + !(PartsData == null));
		//	var filled = PartsData.TryGetValue(thing.thingIDNumber, out res);
		//	//--Log.Message("Output is not null" + PartsData.TryGetValue(thing.thingIDNumber, out res));
		//	//--Log.Message("Out is not null " + (res != null));
		//	//--Log.Message("Out is valid " + (res != null && res.IsValid));
		//	if ((res==null) || (!res.IsValid))
		//	{
		//		if (filled)
		//		{
		//			//--Log.Message("Clearing incorrect data for " + thing);
		//			PartsData.Remove(thing.thingIDNumber);
		//		}
		//		//--Log.Message("PartsData missing, creating for " + thing);
		//		res = new PartsData(thing);
		//		PartsData.Add(thing.thingIDNumber, res);
		//	}
		//	//--Log.Message("Finishing");
		//	return res;
		//}

		//void SetPartsData(Thing thing, PartsData data)
		//{
		//	PartsData.Add(thing.thingIDNumber, data);
		//}
	}
}


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

namespace rjw
{
	/// <summary>
	/// Collection of Designated pawns lists
	/// </summary>
	public class DesignatorsData : UtilityWorldObject
	{
		public static List<Pawn> rjwHero = new List<Pawn>();
		public static List<Pawn> rjwComfort = new List<Pawn>();
		public static List<Pawn> rjwService = new List<Pawn>();
		public static List<Pawn> rjwMilking = new List<Pawn>();
		public static List<Pawn> rjwBreeding = new List<Pawn>();
		public static List<Pawn> rjwBreedingAnimal = new List<Pawn>();

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

		public void Update()
		{
			rjwHero = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedHero()).ToList();
			rjwComfort = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedComfort()).ToList();
			rjwService = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedService()).ToList();
			rjwMilking = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedMilking()).ToList();
			rjwBreeding = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedBreeding()).ToList();
			rjwBreedingAnimal = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedBreedingAnimal()).ToList();

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


code:
using HugsLib;
using HugsLib.Utils;
using System;
using RimWorld;
using Verse;

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

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

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

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

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

		private void ToggleTabIfNeeded()
		{
			DefDatabase<MainButtonDef>.GetNamed("Brothel").buttonVisible = RJWSettings.whoringtab_enabled;
		}
	}
}


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

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

		public PartsData() { }

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

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

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


code:
using System;
using Verse;

using System.Linq;

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

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

		public PawnData() { }

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

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

			isDemon = Pawn.Has(RaceTag.Demon);
			isSlime = Pawn.Has(RaceTag.Slime);

			//Log.Warning("PawnData:: Pawn:" + xxx.get_pawnname(pawn));
			//Log.Warning("PawnData:: isSlime:" + isSlime);
			//Log.Warning("PawnData:: isDemon:" + isDemon);
			//Log.Warning("PawnData:: oviPregnancy:" + oviPregnancy);
		}

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

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


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

namespace rjw
{
	// Used to list the defs themselves rather than strings, but that causes issues when another mod wants to
	// create and reference custom parts inheriting from rjw base defs.
	class RaceGroupDef : Def
	{
		public List<string> raceNames = null;
		public List<string> pawnKindNames = null;
		public List<string> anuses = null;
		public List<float> chanceanuses = null;
		public List<string> femaleBreasts = null;
		public List<float> chancefemaleBreasts = null;
		public List<string> femaleGenitals = null;
		public List<float> chancefemaleGenitals = null;
		public List<string> maleBreasts = null;
		public List<float> chancemaleBreasts = null;
		public List<string> maleGenitals = null;
		public List<float> chancemaleGenitals = null;
		public List<string> tags = null;
		public bool hasSingleGender = false;
		public bool hasSexNeed = true;
		public bool hasFertility = true;
		public bool hasPregnancy = true;
		public bool oviPregnancy = false;
		public bool ImplantEggs = false;
		[Obsolete("isDemon is obsolete, use tags instead.")]
		public bool isDemon = false;
		[Obsolete("isSlime is obsolete, use tags instead.")]
		public bool isSlime = false;
	}
}


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

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

		public string Key { get; }

		RaceTag(string key)
		{
			Key = key;
		}

		/// <summary>
		/// For backwards compatability only. Shouldn't add more special cases here.
		/// </summary>
		public bool DefaultWhenNoRaceGroupDef(Pawn pawn)
		{
			if (this == Demon)
			{
				return pawn.kindDef.race.defName.ToLower().Contains("demon");
			}
			else if (this == Slime)
			{
				return pawn.kindDef.race.defName.ToLower().Contains("slime");
			}
			else if (this == Skin)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
	}
}


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

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


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

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

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

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

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

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

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

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

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

//				return false;
//			}
//		}

//	}
//}


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

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

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

		public static int MaxSize = BreastsInOrder.Length - 1;

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

		//animal try to find best designated pawn to breed
		[SyncMethod]
		public static Pawn find_designated_breeder(Pawn pawn, Map m)
		{
			if (!DesignatorsData.rjwBreeding.Any()) return null;
			DebugText("BreederHelper::find_designated_breeder( " + xxx.get_pawnname(pawn) + " ) called");

			Pawn best_target = null;
			var best_fuckability = 0.10f; // Don't breed pawns with <10% fuckability

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

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

			foreach (Pawn target in targets)
			{
				if (!xxx.can_path_to_target(pawn, target.Position))
					continue;// too far

				var fuc = SexAppraiser.would_fuck(pawn, target, invert_opinion: true, ignore_gender: (Genital_Helper.has_penis(pawn) || Genital_Helper.has_penis_infertile(pawn) || xxx.is_insect(pawn)));
				DebugText("BreederHelper::find_designated_breeder( " + xxx.get_pawnname(pawn) + " -> " + xxx.get_pawnname(target) + " (" + fuc.ToString() + " / " + best_fuckability.ToString() + ")");

				if ((fuc > best_fuckability) && (Rand.Value < fuc))
				{
					best_target = target;
					best_fuckability = fuc;
				}
			}
			return best_target;
		}

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

			float base_fuckability = 0.1f; //Determines how picky the pawns are. Could be added as config.
			List<Pawn> valid_targets = new List<Pawn>();

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

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

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

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

					if (xxx.need_some_sex(pawn) > 2f)
					{   // Less picky when frustrated...
						base_fuckability *= 0.6f;
					}
					else if (xxx.need_some_sex(pawn) < 2f)
					{   // ...and far more picky when satisfied.
						base_fuckability *= 2.5f;
					}
				}
			}

			DebugText("[RJW]BreederHelper::find_breeder_animal::" + targets.Count() + " targets found on map.");

			if (!targets.Any())
			{
				return null; //None found.
			}

			foreach (Pawn target in targets)
			{
				DebugText("[RJW]BreederHelper::find_breeder_animal::Checking target " + target.kindDef.race.defName.ToLower());

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

				float fuc = SexAppraiser.would_fuck_animal(pawn, target); // 0.0 to ~3.0, orientation checks etc.

				if (!(fuc > base_fuckability)) continue;
				DebugText("Adding target" + target.kindDef.race.defName.ToLower());
				valid_targets.Add(target);
			}

			DebugText(valid_targets.Count() + " valid targets found on map.");
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			return valid_targets.Any() ? valid_targets.RandomElement() : null;
		}
	}
}


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

//This one is helper lib for handling all the trans surgery.
namespace rjw
{
	public static class GenderHelper
	{
		public enum Sex { male, female, trap, futa, none }//there is Verse,Gender but it is shit
		//These would probably be better packed in some enumerable structure, so that functions below weren't if-trees, but I don't know C#, sry.
		public static HediffDef was_boy = HediffDef.Named("hediff_was_boy");
		public static HediffDef was_girl = HediffDef.Named("hediff_was_girl");
		public static HediffDef was_futa = HediffDef.Named("hediff_was_futa");
		public static HediffDef was_trap = HediffDef.Named("hediff_was_trap");

		static List<HediffDef> old_sex_list = new List<HediffDef> { was_boy, was_girl, was_futa, was_trap };
		static Dictionary<Sex, HediffDef> sex_to_old_sex = new Dictionary<Sex, HediffDef>() {
			{Sex.male, was_boy },{Sex.female, was_girl},{Sex.trap, was_trap},{Sex.futa, was_futa}
		};
		static Dictionary<HediffDef,Sex> old_sex_to_sex = sex_to_old_sex.ToDictionary(x => x.Value, x => x.Key);

		public static HediffDef m2t = HediffDef.Named("hediff_male2trap");
		public static HediffDef m2f = HediffDef.Named("hediff_male2female");
		public static HediffDef m2h = HediffDef.Named("hediff_male2futa");

		public static HediffDef f2t = HediffDef.Named("hediff_female2trap");
		public static HediffDef f2m = HediffDef.Named("hediff_female2male");
		public static HediffDef f2h = HediffDef.Named("hediff_female2futa");

		public static HediffDef h2t = HediffDef.Named("hediff_futa2trap");
		public static HediffDef h2m = HediffDef.Named("hediff_futa2male");
		public static HediffDef h2f = HediffDef.Named("hediff_futa2female");

		public static HediffDef t2h = HediffDef.Named("hediff_trap2futa");
		public static HediffDef t2m = HediffDef.Named("hediff_trap2male");
		public static HediffDef t2f = HediffDef.Named("hediff_trap2female");

		static List<HediffDef> SexChangeThoughts = new List<HediffDef> { m2t, m2f, m2h, f2t, f2m, f2h, h2t, h2m, h2f };

		private static readonly SimpleCurve rigidity_from_age = new SimpleCurve//relative to max age
		{
			new CurvePoint(0f, 0.1f),
			new CurvePoint(0.2f, 0.1f),
			new CurvePoint(0.5f, 1f),
			new CurvePoint(10f, 1f)
		};

		public static Sex GetSex(Pawn pawn)
		{
			bool has_vagina = Genital_Helper.has_vagina(pawn);
			bool has_penis = Genital_Helper.has_penis(pawn);
			bool has_penis_infertile = Genital_Helper.has_penis_infertile(pawn);
			bool has_breasts = Genital_Helper.has_breasts(pawn);
			bool has_male_breasts = Genital_Helper.has_male_breasts(pawn);
			//BodyType? bt = pawn.story?.bodyType;
			//if (bt != null)
			//	bt = BodyType.Undefined;

			Sex res;
			if (has_vagina && !has_penis && !has_penis_infertile)
				res = Sex.female;
			else if (has_vagina && (has_penis || has_penis_infertile))
				res = Sex.futa;
			else if ((has_penis || has_penis_infertile) && has_breasts && !has_male_breasts)
				res = Sex.trap;
			else if (has_penis || has_penis_infertile) //probably should change this later
				res = Sex.male;
			else if (pawn.gender == Gender.Male)
				res = Sex.male;
			else if (pawn.gender == Gender.Female)
				res = Sex.female;
			else
				res = Sex.none;
			return res;
		}
		/*
		public static HediffDef GetReactionHediff(Sex before, Sex after)
		{
			if (before == after)
				return null;

			if (before == Sex.male)
				return (after == Sex.female) ? m2f : m2t;
			else if (before == Sex.female)
			{
				if (after == Sex.male)
					return f2m;
				else if (after == Sex.trap)
					return f2t;
				else if (after == Sex.futa)
					return f2h;
				else
					return null;
			}
			else if (before == Sex.futa && (after == Sex.female || after == Sex.none))
				return h2f;
			else//trap to anything, futa to trap; probably won't even be reached ever
				return null;
		}
		*/

		//TODO: fix reactions
		public static HediffDef GetReactionHediff(Sex before, Sex after)
		{
			if (before == after)
				return null;
			else if (before == Sex.male)
			{
				if (after == Sex.female)
					return m2f;
				else if (after == Sex.trap)
					return m2t;
				else if (after == Sex.futa)
					return m2h;
				else
					return null;
			}
			else if (before == Sex.female)
			{
				if (after == Sex.male)
					return f2m;
				else if (after == Sex.trap)
					return f2t;
				else if (after == Sex.futa)
					return f2h;
				else
					return null;
			}
			else if (before == Sex.futa)
			{
				if (after == Sex.male)
					return h2m;
				else if (after == Sex.female)
					return h2f;
				else if (after == Sex.trap)
					return h2t;
				else
					return null;
			}
			else if (before == Sex.trap)
			{
				if (after == Sex.male)
					return t2m;
				else if (after == Sex.female)
					return t2f;
				else if (after == Sex.futa)
					return t2h;
				else
					return null;
			}
			else//unicorns?
				return null;
		}

		public static bool WasThisBefore(Pawn pawn, Sex after)
		{
			Hediff was = null;

			switch (after)
			{
				case Sex.male:
					was = pawn.health.hediffSet.GetFirstHediffOfDef(was_boy);
					break;
				case Sex.female:
					was = pawn.health.hediffSet.GetFirstHediffOfDef(was_girl);
					break;
				case Sex.trap:
					was = pawn.health.hediffSet.GetFirstHediffOfDef(was_trap);
					break;
				case Sex.futa:
					was = pawn.health.hediffSet.GetFirstHediffOfDef(was_futa);
					break;
			}
			return (was != null) ? true : false;
		}

		//Get one of the sexes that were on this pawn before
		public static Sex GetOriginalSex(Pawn pawn)
		{
			foreach (var os in old_sex_list)
			{
				if (pawn.health.hediffSet.GetFirstHediffOfDef(os) != null)
					return old_sex_to_sex[os];
			}
			return Sex.none;//it shouldnt reach here though
		}

		public static Hediff IsInDenial(Pawn pawn)
		{
			Hediff res = null;
			foreach (var h in SexChangeThoughts)
			{
				res = pawn.health.hediffSet.GetFirstHediffOfDef(h);
				if (res != null)
					break;
			}
			return res;
		}

		//roll how much gender fluid the pawn is.
		//In ideal world this would actually take into account from where to where transition is moving and so on.
		//Same applies to the thought hediffs themselves, but we get what we can get now
		static float RollSexChangeSeverity(Pawn pawn)
		{
			float res = 1;
			if (xxx.is_bisexual(pawn))
				res *= 0.5f;
			if (pawn.story != null && (pawn.story.bodyType == BodyTypeDefOf.Thin || pawn.story.bodyType == BodyTypeDefOf.Fat))
				res *= 0.8f;
			if (!pawn.ageTracker.CurLifeStage.reproductive)
				res *= 0.2f;
			else
				res *= rigidity_from_age.Evaluate(SexUtility.ScaleToHumanAge(pawn));

			return res;
		}

		//Quick hack to check if hediff is adding happiness
		static bool is_happy(this Hediff thought)
		{
			return thought.CurStageIndex == 0;
		}
		static void make_happy(this Hediff thought)
		{
			thought.Severity = 0.24f;//this is currently max severity for hediff, that is associated with positive mood
		}
		static void mix_thoughts(this Hediff newer, Hediff older)
		{
			newer.Severity = (newer.Severity + older.Severity) / 2f  ;
		}

		static void GiveThought(Pawn pawn, HediffDef thought, bool happy = false, Hediff old_thought=null)
		{
			pawn.health.AddHediff(thought);
			var new_thought = pawn.health.hediffSet.GetFirstHediffOfDef(thought);
			if (happy)
			{
				new_thought.make_happy();
				return;
			}
			new_thought.Severity = RollSexChangeSeverity(pawn);
			if (old_thought!=null)
			{
				new_thought.Severity = (new_thought.Severity + old_thought.Severity) / 2f;
			}
		}

		/// <summary>
		/// Executes action and then changes sex if necessary.
		/// </summary>
		public static void ChangeSex(Pawn pawn, Action action)
		{
			var before = GetSex(pawn);
			action();
			var after = GetSex(pawn);
			ChangeSex(pawn, before, after);
		}

		public static void ChangeSex(Pawn pawn, Sex oldsex, Sex newsex)
		{
			// Wakeup pawn sexuality if it has none before

			if (!(CompRJW.Comp(pawn).orientation == Orientation.Asexual || CompRJW.Comp(pawn).orientation == Orientation.None))
				if (oldsex == newsex)
					return;

			//update ingame genders
			if (newsex == Sex.none)
				return;
			else if (newsex == Sex.male || newsex == Sex.trap)
				pawn.gender = Gender.Male;
			else
				pawn.gender = Gender.Female;

			// Sexualize pawn after installation of parts if it was "not interested in".
			if (oldsex == Sex.none || CompRJW.Comp(pawn).orientation == Orientation.Asexual || CompRJW.Comp(pawn).orientation == Orientation.None)
				if (pawn.kindDef.race.defName.ToLower().Contains("droid") && !AndroidsCompatibility.IsAndroid(pawn))
				{
					//basic droids,they dont care
					return;
				}
				else
				{
					CompRJW.Comp(pawn).Sexualize(pawn, true);
				}

			var old_thought = IsInDenial(pawn);
			var react = GetReactionHediff(oldsex, newsex);

			if (old_thought==null || old_thought.is_happy())//pawn either liked it or got used already
			{
				//Log.Message("ChangeSex 1 old_thought" + old_thought);
				//Log.Message("ChangeSex 1 react" + react);
				if (react!=null)
					GiveThought(pawn, react, pawn.IsDesignatedHero());//give unhappy, if not hero
				if (old_thought!=null)
					pawn.health.RemoveHediff(old_thought);

				//add tracking hediff
				pawn.health.AddHediff(sex_to_old_sex[oldsex]);
			}
			else//pawn was unhappy
			{
				if (WasThisBefore(pawn, newsex))//pawn is happy to be previous self
				{
					GiveThought(pawn, react, happy:true);
					pawn.health.RemoveHediff(old_thought);
				}
				else//pawn is still unhappy mix the unhappiness from two
				{
					react = GetReactionHediff(GetOriginalSex(pawn), newsex);//check reaction from original sex
					if (react!=null)
					{
						GiveThought(pawn, react, old_thought: old_thought);
						pawn.health.RemoveHediff(old_thought);
					}
					//else pawn keeps old unhappy thought
				}
			}
		}
	}
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public static BodyPartRecord get_mouth(Pawn pawn)
		{
			//--Log.Message("[RJW] get_mouth( " + xxx.get_pawnname(pawn) + " ) called");
			BodyPartRecord Part = pawn?.RaceProps.body.AllParts.Find(bpr => bpr.def.defName.ToLower().ContainsAny("mouth", "teeth", "jaw", "beak"));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

			return !pawn.health.hediffSet.hediffs.Any((Hediff hed) =>
						   (hed.Part == Part) && (hed is Hediff_MissingPart));
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

			return pawn.health.hediffSet.hediffs.Find((Hediff hed) =>
							(hed.Part == Part) &&
							(!hed.def.defName.ToLower().Contains("vagina")) &&
							(penise.Contains(hed.def) ||
							hed.def.defName.ToLower().Contains("penis") ||
							hed.def.defName.ToLower().Contains("pegdick") ||
							hed.def.defName.ToLower().Contains("ovipositorm") ||
							hed.def.defName.ToLower().Contains("tentacle")));
		}

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

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

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

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

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


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

namespace rjw
{
	public class HediffHelper
	{
		/// <summary>
		/// Creates hediff with custom hediff class
		/// </summary>
		/// <typeparam name="T">hediff class. Should be class defined by hediff or subclass of that class</typeparam>
		/// <param name="def">hediffDef</param>
		/// <param name="pawn">owner of newly created hediff</param>
		/// <param name="partRecord">bodypart heduff assigned to</param>
		/// <returns>newly created hediff</returns>
		public static T MakeHediff<T>(HediffDef def, Pawn pawn, BodyPartRecord partRecord = null) where T : Hediff
		{
			if (!def.hediffClass.IsAssignableFrom(typeof(T)))
			{
				throw new InvalidOperationException($"trying to create hediff with incompatible class: {typeof(T).Name} is not a {def.hediffClass.Name} or its subclass");
			}

			T hediff = (T)Activator.CreateInstance(typeof(T));
			hediff.def = def;
			hediff.pawn = pawn;
			hediff.Part = partRecord;
			hediff.loadID = Find.UniqueIDsManager.GetNextHediffID();
			hediff.PostMake();

			return hediff;
		}

		/// <summary>
		/// Fill existing hediff class with data
		/// </summary>
		/// <typeparam name="T">hediff class. Should be class defined by hediff or subclass of that class</typeparam>
		/// <param name="def">hediffDef</param>
		/// <param name="hediff">empty hediff instance</Hediff>
		/// <param name="pawn">owner of newly created hediff</param>
		/// <param name="partRecord">bodypart heduff assigned to</param>
		/// <returns>newly created hediff</returns>
		public static T FillHediff<T>(HediffDef def, T hediff, Pawn pawn, BodyPartRecord partRecord = null) where T : Hediff
		{
			if (!def.hediffClass.IsAssignableFrom(typeof(T)))
			{
				throw new InvalidOperationException($"trying to create hediff with incompatible class: {typeof(T).Name} is not a {def.hediffClass.Name} or its subclass");
			}

			hediff.def = def;
			hediff.pawn = pawn;
			hediff.Part = partRecord;
			hediff.loadID = Find.UniqueIDsManager.GetNextHediffID();
			hediff.PostMake();

			return hediff;
		}
	}
}