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

<Patch>
	<Operation Class="PatchOperationAdd">
		<xpath>/Defs/rjw.HediffDef_PartBase[defName="ElfVagina"]</xpath>
		<value>
			<comps>

					<maxCumCapacity>10</maxCumCapacity>
					<baseImplantationChanceFactor>1.0</baseImplantationChanceFactor>
					<basefertilizationChanceFactor>1.0</basefertilizationChanceFactor>
					<follicularIntervalDays>1800</follicularIntervalDays>
					<lutealIntervalDays>1800</lutealIntervalDays>
					<bleedingIntervalDays>6</bleedingIntervalDays>
					<recoveryIntervalDays>30</recoveryIntervalDays>
					<eggLifespanDays>1</eggLifespanDays>
					<wombTex>Womb/Womb</wombTex>
					<vagTex>Genitals/Vagina</vagTex>
					<concealedEstrus>true</concealedEstrus>

			</comps>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>/Defs/rjw.HediffDef_PartBase[defName="ElfAnus"]</xpath>
		<value>
			<comps>

					<analTex>Genitals/Anal</analTex>

			</comps>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>/Defs/rjw.HediffDef_PartBase[defName="OrcVagina"]</xpath>
		<value>
			<comps>

					<maxCumCapacity>10</maxCumCapacity>
					<baseImplantationChanceFactor>1.0</baseImplantationChanceFactor>
					<basefertilizationChanceFactor>1.0</basefertilizationChanceFactor>
					<follicularIntervalDays>7</follicularIntervalDays>
					<lutealIntervalDays>10</lutealIntervalDays>
					<bleedingIntervalDays>0</bleedingIntervalDays>
					<recoveryIntervalDays>10</recoveryIntervalDays>
					<eggLifespanDays>1</eggLifespanDays>
					<wombTex>Womb/Womb</wombTex>
					<vagTex>Genitals/Vagina</vagTex>
					<concealedEstrus>true</concealedEstrus>

			</comps>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>/Defs/rjw.HediffDef_PartBase[defName="OrcAnus"]</xpath>
		<value>
			<comps>

					<analTex>Genitals/Anal</analTex>

			</comps>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>/Defs/rjw.HediffDef_PartBase[defName="GhoulVagina"]</xpath>
		<value>
			<comps>

					<maxCumCapacity>10</maxCumCapacity>
					<baseImplantationChanceFactor>0.2</baseImplantationChanceFactor>
					<basefertilizationChanceFactor>0.2</basefertilizationChanceFactor>
					<follicularIntervalDays>14</follicularIntervalDays>
					<lutealIntervalDays>14</lutealIntervalDays>
					<bleedingIntervalDays>0</bleedingIntervalDays>
					<recoveryIntervalDays>10</recoveryIntervalDays>
					<eggLifespanDays>1</eggLifespanDays>
					<wombTex>Womb/Womb</wombTex>
					<vagTex>Genitals/Vagina</vagTex>
					<concealedEstrus>true</concealedEstrus>

			</comps>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>/Defs/rjw.HediffDef_PartBase[defName="GhoulAnus"]</xpath>
		<value>
			<comps>

					<analTex>Genitals/Anal</analTex>

			</comps>
		</value>
	</Operation>

</Patch>

path: 1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Humanlike_RaceSupport.xml


code:
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
  <ThingDef ParentName="GatheredCum">
    <defName>GatheredCumMixture</defName>
    <label>cum mixture</label>
    <description>Gathered mixture of cum.</description>
	<thingClass>RJW_Menstruation.Sexperience.GatheredCumMixture</thingClass>
    <graphicData>
      <texPath>Things/Item/GatheredCum</texPath>
      <drawSize>1</drawSize>
	  <graphicClass>Graphic_StackCount</graphicClass>
    </graphicData>
  </ThingDef>
</Defs>

license: unknown


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

<Defs>
	<JobDef>
		<defName>VaginaWashingwithBucket</defName>
		<driverClass>RJW_Menstruation.Sexperience.JobDriver_VaginaWashingWithBucket</driverClass>
		<reportString>gather cum</reportString>
		<casualInterruptible>true</casualInterruptible>
	</JobDef>
</Defs>


code:
using Milk;
using RJW_Menstruation;
using Verse;

namespace MilkModule
{
    public class JobDriver_MilkSelf_MC : JobDriver_MilkSelf
    {
        HumanCompHasGatherableBodyResource comp;
        HediffComp_Breast breastcomp;

        protected override float Fullness
        {
            get
            {
                return comp?.Fullness ?? 0f;
            }
        }

        protected override void PreMakeNewToils()
        {
            comp = GetMilkComp(pawn);
            breastcomp = pawn.GetBreastComp();
        }

        protected override void Gathered()
        {
            comp?.Gathered(pawn);
        }

        protected override void PostTickAction()
        {
            breastcomp?.AdjustNippleProgress(Rand.Range(0.0f, 0.000005f) * Configurations.MaxNippleIncrementFactor);
        }

        public static HumanCompHasGatherableBodyResource GetMilkComp(Pawn pawn)
        {
            HumanCompHasGatherableBodyResource result;
            if (pawn.health.hediffSet.HasHediff(VariousDefOf.Hediff_Heavy_Lactating_Permanent))
            {
                result = pawn.TryGetComp<CompHyperMilkableHuman>();

            }
            else
            {
                result = pawn.TryGetComp<CompMilkableHuman>();
            }
            return result;
        }

    }

    //public class JobDriver_HumanMilkSelf : JobDriver
    //{
    //    const float milkingTime = 250f;//ticks - 120 = 2 real seconds, 3 in-game minutes
    //
    //    public override bool TryMakePreToilReservations(bool errorOnFailed)
    //    {
    //        return pawn.Reserve(pawn, job, 1, -1, null, errorOnFailed);
    //    }
    //
    //    protected override IEnumerable<Toil> MakeNewToils()
    //    {
    //
    //        HumanCompHasGatherableBodyResource Comp = GetMilkComp(pawn);
    //        HediffComp_Breast breastcomp = pawn.GetBreastComp();
    //        this.FailOn(delegate
    //        {
    //            return !(Comp.Fullness > 0.01f);
    //        });
    //        Toil milking = Toils_General.Wait((int)(50 + milkingTime * Comp.Fullness), TargetIndex.None);//duration of
    //
    //        milking.WithProgressBarToilDelay(TargetIndex.A);
    //        milking.tickAction = delegate ()
    //        {
    //            if (breastcomp != null)
    //            {
    //                breastcomp.AdjustAreolaSize(Rand.Range(0.0f,0.0001f * Configurations.NipplePermanentTransitionVariance));
    //                breastcomp.AdjustNippleSize(Rand.Range(0.0f,0.0001f * Configurations.NipplePermanentTransitionVariance));
    //            }
    //
    //        };
    //        yield return milking;
    //        yield return new Toil()
    //        {
    //            initAction = delegate ()
    //            {
    //                Comp.Gathered(pawn);
    //            }
    //        };
    //        //yield return excreting;
    //        yield break;
    //
    //    }
    //
    //
    //    public static HumanCompHasGatherableBodyResource GetMilkComp(Pawn pawn)
    //    {
    //        HumanCompHasGatherableBodyResource result;
    //        if (pawn.health.hediffSet.HasHediff(VariousDefOf.Hediff_Heavy_Lactating_Permanent))
    //        {
    //            result = pawn.TryGetComp<CompHyperMilkableHuman>();
    //        }
    //        else
    //        {
    //            result = pawn.TryGetComp<CompMilkableHuman>();
    //        }
    //        return result;
    //    }
    //
    //
    //}

}


code:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{3591B3C1-EB57-44BF-AB69-A613E097A7F8}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>MilkModule</RootNamespace>
    <AssemblyName>MilkModule</AssemblyName>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>..\..\..\MilkModule\Assemblies\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>..\..\..\MilkModule\Assemblies\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Assembly-CSharp">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Milk">
      <HintPath>..\..\..\..\..\rjw-mc\1.3\Assemblies\Milk.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
    <Reference Include="UnityEngine">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.CoreModule">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.IMGUIModule">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.TextCoreModule">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.TextRenderingModule">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.UI">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.UI.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.UIElementsModule">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="UnityEngine.UIModule">
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.UIModule.dll</HintPath>
      <Private>False</Private>
    </Reference>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="JobDriver_MilkSelf.cs" />
    <Compile Include="Milk_Patch.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\RJW_Menstruation\RJW_Menstruation.csproj">
      <Project>{eed2f3b9-8c20-4194-919e-8d151b29f70b}</Project>
      <Name>RJW_Menstruation</Name>
      <Private>False</Private>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Lib.Harmony">
      <Version>2.1.1</Version>
	  <ExcludeAssets>runtime</ExcludeAssets>
    </PackageReference>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>


code:
using HarmonyLib;
using Milk;
using RJW_Menstruation;
using System.Reflection;
using Verse;

namespace MilkModule
{
    internal static class First
    {
        static First()
        {
            Harmony har = new Harmony("RJW_Menstruation_MilkModule");
            har.PatchAll(Assembly.GetExecutingAssembly());
        }
    }

    [HarmonyPatch(typeof(HumanCompHasGatherableBodyResource), nameof(HumanCompHasGatherableBodyResource.Gathered))]
    public static class Milk_Patch
    {
        public static void Postfix(HumanCompHasGatherableBodyResource __instance)
        {
            if (__instance.parent is Pawn pawn)
                pawn.GetBreastComp()?.AdjustNippleProgress(Rand.Range(0.0f, 0.005f) * Configurations.MaxNippleIncrementFactor);
        }

    }
}


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

// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("MilkModule")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MilkModule")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]

// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("3591b3c1-eb57-44bf-ab69-a613e097a7f8")]

// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
//      주 버전
//      부 버전
//      빌드 번호
//      수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]


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


code:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30907.101
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RJW_Menstruation", "RJW_Menstruation\RJW_Menstruation.csproj", "{EED2F3B9-8C20-4194-919E-8D151B29F70B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MilkModule", "MilkModule\MilkModule.csproj", "{3591B3C1-EB57-44BF-AB69-A613E097A7F8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SexperienceModule", "SexperienceModule\SexperienceModule.csproj", "{7DB664D7-D4B4-4673-9FF1-62EC18305715}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Release|Any CPU.Build.0 = Release|Any CPU
		{3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Release|Any CPU.Build.0 = Release|Any CPU
		{7DB664D7-D4B4-4673-9FF1-62EC18305715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{7DB664D7-D4B4-4673-9FF1-62EC18305715}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{7DB664D7-D4B4-4673-9FF1-62EC18305715}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{7DB664D7-D4B4-4673-9FF1-62EC18305715}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {0E4B1D09-2A81-4440-AC1E-32ACCECBEE0B}
	EndGlobalSection
EndGlobal


code:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
</configuration>


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

namespace RJW_Menstruation
{
    public static class AnimalGeneticsCompatibility
    {
        public static void PreConception(Pawn mother, Pawn father)
        {
            GeneticInformation motherGeneticInformation = mother?.AnimalGenetics();
            GeneticInformation fatherGeneticInformation = father?.AnimalGenetics();

            ParentReferences.Push(new ParentReferences.Record { Mother = motherGeneticInformation, Father = fatherGeneticInformation });
        }

        public static void PostConception()
        {
            ParentReferences.Pop();
        }

        public static void CopyGenes(Pawn baby, Pawn original)
        {
            Dictionary<StatDef, GeneRecord> babyRecords = baby.AnimalGenetics()?.GeneRecords;
            Dictionary<StatDef, GeneRecord> originalRecords = original.AnimalGenetics()?.GeneRecords;

            if (babyRecords == null || originalRecords == null) return;

            foreach(KeyValuePair<StatDef, GeneRecord> record in originalRecords)
            {
                GeneRecord originalRecord = record.Value;
                if (!babyRecords.TryGetValue(record.Key, out GeneRecord babyRecord)) continue;  // Shouldn't fail, but best to be safe

                babyRecord.Parent = originalRecord.Parent;
                babyRecord.Value = originalRecord.Value;
            }
        }
    }
}


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

namespace RJW_Menstruation
{
    public static class HARCompatibility
    {

        public static bool IsHAR(this Pawn pawn)
        {
            if (!Configurations.HARActivated) return false;
            return pawn?.def is ThingDef_AlienRace;
        }

        public static void CopyHARProperties(Pawn baby, Pawn original)
        {
            AlienPartGenerator.AlienComp babyHARComp = baby?.TryGetComp<AlienPartGenerator.AlienComp>();
            AlienPartGenerator.AlienComp originalHARComp = original?.TryGetComp<AlienPartGenerator.AlienComp>();
            if (babyHARComp == null || originalHARComp == null) return;
            babyHARComp.crownType = originalHARComp.crownType;

            foreach(KeyValuePair<string, AlienPartGenerator.ExposableValueTuple<Color, Color>> channel in originalHARComp.ColorChannels)
            {
                babyHARComp.OverwriteColorChannel(channel.Key, channel.Value.first, channel.Value.second);
            }
            babyHARComp.headMaskVariant = originalHARComp.headMaskVariant;
            babyHARComp.bodyMaskVariant = originalHARComp.bodyMaskVariant;
        }

        // HAR doesn't populate variants until the graphics are called for, so this has to happen late
        public static void CopyHARPropertiesPostBirth(Pawn baby, Pawn original)
        {
            AlienPartGenerator.AlienComp babyHARComp = baby?.TryGetComp<AlienPartGenerator.AlienComp>();
            AlienPartGenerator.AlienComp originalHARComp = original?.TryGetComp<AlienPartGenerator.AlienComp>();
            if (babyHARComp == null || originalHARComp == null) return;
            if (originalHARComp.addonVariants != null)  // Testing has shown that the addons are valid by this point, but it's better to be safe
                babyHARComp.addonVariants = new List<int>(originalHARComp.addonVariants);
        }
    }
}


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

namespace RJW_Menstruation
{
    public class Configurations : ModSettings
    {
        public const float ImplantationChanceDefault = 0.65f;
        public const int ImplantationChanceAdjustDefault = 65;
        public const float FertilizeChanceDefault = 0.15f;
        public const int FertilizeChanceAdjustDefault = 150;
        public const float CumDecayRatioDefault = 0.15f;
        public const int CumDecayRatioAdjustDefault = 150;
        public const float CumFertilityDecayRatioDefault = 0.05f;
        public const int CumFertilityDecayRatioAdjustDefault = 50;
        public const int CycleAccelerationDefault = 6;
        public const float EnzygoticTwinsChanceDefault = 0.002f;
        public const int EnzygoticTwinsChanceAdjustDefault = 2;
        public const int MaxEnzygoticTwinsDefault = 9;
        public const int BleedingAmountDefault = 50;
        public const float MaxBreastIncrementFactorDefault = 1.0f;
        public const float MaxBreastIncrementFactorMax = 2.5f;
        public const float MaxNippleIncrementFactorDefault = 1.0f;
        public const float MaxNippleIncrementFactorMax = 2.5f;
        public const float PermanentNippleChangeDefault = 0.1f;
        public const float PermanentNippleChangeMax = 0.25f;
        public const float EggLifespanMultiplierDefault = 1.0f;
        public const float VaginaMorphPowerDefault = 0.2f;

        public static DetailLevel infoDetail = DetailLevel.All;

        public static float ImplantationChance = ImplantationChanceDefault;
        public static int ImplantationChanceAdjust = ImplantationChanceAdjustDefault;
        public static float FertilizeChance = FertilizeChanceDefault;
        public static int FertilizeChanceAdjust = FertilizeChanceAdjustDefault;
        public static float CumDecayRatio = CumDecayRatioDefault;
        public static int CumDecayRatioAdjust = CumDecayRatioAdjustDefault;
        public static float CumFertilityDecayRatio = CumFertilityDecayRatioDefault;
        public static int CumFertilityDecayRatioAdjust = CumFertilityDecayRatioAdjustDefault;
        public static int CycleAcceleration = CycleAccelerationDefault;
        public static bool EnableWombIcon = true;
        public static bool EnableAnimalCycle = false;
        public static bool DrawWombStatus = true;
        public static bool DrawVaginaStatus = true;
        public static bool DrawEggOverlay = true;
        public static bool Debug = false;
        public static bool EnableMenopause = true;
        public static DetailLevel InfoDetail => infoDetail;
        public static bool EstrusOverridesHookupSettings = false;
        public static float EstrusFuckabilityToHookup = RJWHookupSettings.MinimumFuckabilityToHookup;
        public static float EstrusAttractivenessToHookup = RJWHookupSettings.MinimumAttractivenessToHookup;
        public static float EstrusRelationshipToHookup = RJWHookupSettings.MinimumRelationshipToHookup;
        public static bool UseMultiplePregnancy = true;
        public static bool EnableHeteroOvularTwins = true;
        public static bool EnableEnzygoticTwins = true;
        public static float EnzygoticTwinsChance = EnzygoticTwinsChanceDefault;
        public static int EnzygoticTwinsChanceAdjust = EnzygoticTwinsChanceAdjustDefault;
        public static int MaxEnzygoticTwins = MaxEnzygoticTwinsDefault;
        public static int BleedingAmount = BleedingAmountDefault;
        public static bool EnableButtonInHT = false;
        public static bool EnableGatherCumGizmo = true;
        public static PawnFlags ShowFlag = PawnFlags.Colonist | PawnFlags.Prisoner;
        public static bool UseHybridExtention = true;
        public static bool MotherFirst = false;
        public static bool AllowShrinkIcon = false;
        public static float EggLifespanMultiplier = EggLifespanMultiplierDefault;
        public static bool EnableBirthVaginaMorph = false;
        public static float VaginaMorphPower = VaginaMorphPowerDefault;
        public static float MaxBreastIncrementFactor = MaxBreastIncrementFactorDefault;
        public static float MaxNippleIncrementFactor = MaxNippleIncrementFactorDefault;
        public static float PermanentNippleChange = PermanentNippleChangeDefault;
        public static void SettoDefault()
        {
            ImplantationChanceAdjust = ImplantationChanceAdjustDefault;
            FertilizeChanceAdjust = FertilizeChanceAdjustDefault;
            CumDecayRatioAdjust = CumDecayRatioAdjustDefault;
            CumFertilityDecayRatioAdjust = CumFertilityDecayRatioAdjustDefault;
            EnableWombIcon = true;
            EnableGatherCumGizmo = true;
            EnableAnimalCycle = false;
            CycleAcceleration = CycleAccelerationDefault;
            EstrusOverridesHookupSettings = false;
            EstrusFuckabilityToHookup = RJWHookupSettings.MinimumFuckabilityToHookup;
            EstrusAttractivenessToHookup = RJWHookupSettings.MinimumAttractivenessToHookup;
            EstrusRelationshipToHookup = RJWHookupSettings.MinimumRelationshipToHookup;
            EnzygoticTwinsChanceAdjust = EnzygoticTwinsChanceAdjustDefault;
            EnableEnzygoticTwins = true;
            EnableHeteroOvularTwins = true;
            UseMultiplePregnancy = true;
            MaxEnzygoticTwins = MaxEnzygoticTwinsDefault;
            BleedingAmount = BleedingAmountDefault;
            MotherFirst = false;
            MaxBreastIncrementFactor = MaxBreastIncrementFactorDefault;
            MaxNippleIncrementFactor= MaxNippleIncrementFactorDefault;
            PermanentNippleChange = PermanentNippleChangeDefault;
            EggLifespanMultiplier = EggLifespanMultiplierDefault;
            VaginaMorphPower = VaginaMorphPowerDefault;
        }

        public static List<HybridInformations> HybridOverride = new List<HybridInformations>();

        public static bool HARActivated = false;
        public static bool AnimalGeneticsActivated = false;

        public enum DetailLevel
        {
            All,
            OnReveal,
            HideFetusInfo,
            Hide
        }

        public static string LevelString(DetailLevel level)
        {
            switch (level)
            {
                case DetailLevel.All:
                    return "All";
                case DetailLevel.OnReveal:
                    return "On reveal";
                case DetailLevel.HideFetusInfo:
                    return "Hide fetus info";
                case DetailLevel.Hide:
                    return "Hide";
                default:
                    return "";
            }

        }
        public static string HybridString(bool b)
        {
            if (b) return Translations.Option23_Label_1;
            else return Translations.Option23_Label_2;
        }

        public static bool IsOverrideExist(ThingDef def)
        {
            List<HybridInformations> removeList = new List<HybridInformations>();
            if (!HybridOverride.NullOrEmpty())
                foreach (HybridInformations o in HybridOverride)
                {
                    if (o.IsNull) removeList.Add(o);
                    if (o.DefName == def.defName) return true;
                }
            foreach (HybridInformations o in removeList)
            {
                HybridOverride.Remove(o);
            }
            return false;
        }

        [Flags]
        public enum PawnFlags
        {
            None = 0,
            Colonist = 1,
            Prisoner = 2,
            Ally = 4,
            Neutral = 8,
            Hostile = 16
        }

        public override void ExposeData()
        {
            Scribe_Values.Look(ref ImplantationChanceAdjust, "ImplantationChanceAdjust", ImplantationChanceAdjust, true);
            Scribe_Values.Look(ref ImplantationChance, "ImplantationChance", ImplantationChance, true);
            Scribe_Values.Look(ref FertilizeChanceAdjust, "FertilizeChanceAdjust", FertilizeChanceAdjust, true);
            Scribe_Values.Look(ref FertilizeChance, "FertilizeChance", FertilizeChance, true);
            Scribe_Values.Look(ref CumDecayRatioAdjust, "CumDecayRatioAdjust", CumDecayRatioAdjust, true);
            Scribe_Values.Look(ref CumDecayRatio, "CumDecayRatio", CumDecayRatio, true);
            Scribe_Values.Look(ref CumFertilityDecayRatioAdjust, "CumFertilityDecayRatioAdjust", CumFertilityDecayRatioAdjust, true);
            Scribe_Values.Look(ref CumFertilityDecayRatio, "CumFertilityDecayRatio", CumFertilityDecayRatio, true);
            Scribe_Values.Look(ref CycleAcceleration, "CycleAcceleration", CycleAcceleration, true);
            Scribe_Values.Look(ref EnableWombIcon, "EnableWombIcon", EnableWombIcon, true);
            Scribe_Values.Look(ref EnableAnimalCycle, "EnableAnimalCycle", EnableAnimalCycle, true);
            Scribe_Values.Look(ref DrawWombStatus, "DrawWombStatus", DrawWombStatus, true);
            Scribe_Values.Look(ref DrawVaginaStatus, "DrawVaginaStatus", DrawVaginaStatus, true);
            Scribe_Values.Look(ref DrawEggOverlay, "DrawEggOvray", DrawEggOverlay, true);
            Scribe_Values.Look(ref Debug, "Debug", Debug, true);
            Scribe_Values.Look(ref infoDetail, "InfoDetail", infoDetail, true);
            Scribe_Values.Look(ref EnableMenopause, "EnableMenopause", EnableMenopause, true);
            Scribe_Values.Look(ref EstrusOverridesHookupSettings, "EstrusOverridesHookupSettings", EstrusOverridesHookupSettings, true);
            Scribe_Values.Look(ref EstrusFuckabilityToHookup, "EstrusFuckabilityToHookup", EstrusFuckabilityToHookup, true);
            Scribe_Values.Look(ref EstrusAttractivenessToHookup, "EstrusAttractivenessToHookup", EstrusAttractivenessToHookup, true);
            Scribe_Values.Look(ref EstrusRelationshipToHookup, "EstrusRelationshipToHookup", EstrusRelationshipToHookup, true);
            Scribe_Values.Look(ref UseMultiplePregnancy, "UseMultiplePregnancy", UseMultiplePregnancy, true);
            Scribe_Values.Look(ref EnableHeteroOvularTwins, "EnableHeteroOvularTwins", EnableHeteroOvularTwins, true);
            Scribe_Values.Look(ref EnableEnzygoticTwins, "EnableEnzygoticTwins", EnableEnzygoticTwins, true);
            Scribe_Values.Look(ref EnzygoticTwinsChance, "EnzygoticTwinsChance", EnzygoticTwinsChance, true);
            Scribe_Values.Look(ref EnzygoticTwinsChanceAdjust, "EnzygoticTwinsChanceAdjust", EnzygoticTwinsChanceAdjust, true);
            Scribe_Values.Look(ref MaxEnzygoticTwins, "MaxEnzygoticTwins", MaxEnzygoticTwins, true);
            Scribe_Values.Look(ref BleedingAmount, "BleedingAmount", BleedingAmount, true);
            Scribe_Values.Look(ref EnableButtonInHT, "EnableButtonInHT", EnableButtonInHT, true);
            Scribe_Values.Look(ref EnableGatherCumGizmo, "EnableGatherCumGizmo", true, true);
            Scribe_Values.Look(ref ShowFlag, "ShowFlag", ShowFlag, true);
            Scribe_Values.Look(ref UseHybridExtention, "UseHybridExtention", UseHybridExtention, true);
            Scribe_Values.Look(ref MotherFirst, "MotherFirst", MotherFirst, true);
            Scribe_Values.Look(ref MaxBreastIncrementFactor, "MaxBreastIncrementFactor", MaxBreastIncrementFactor, true);
            Scribe_Values.Look(ref MaxNippleIncrementFactor, "MaxNippleIncrementFactor", MaxNippleIncrementFactor, true);
            Scribe_Values.Look(ref PermanentNippleChange, "PermanentNippleChange", PermanentNippleChange, true);
            Scribe_Values.Look(ref AllowShrinkIcon, "AllowShrinkIcon", AllowShrinkIcon, true);
            Scribe_Values.Look(ref EggLifespanMultiplier, "EggLifespanMultiplier", EggLifespanMultiplier, true);
            Scribe_Values.Look(ref EnableBirthVaginaMorph, "EnableBirthVaginaMorph", EnableBirthVaginaMorph, true);
            Scribe_Values.Look(ref VaginaMorphPower, "VaginaMorphPower", VaginaMorphPower, true);
            Scribe_Collections.Look(ref HybridOverride, saveDestroyedThings: true, label: "HybridOverride", lookMode: LookMode.Deep, ctorArgs: new object[0]);
            base.ExposeData();
        }

    }

    public class RJW_Menstruation : Mod
    {

        private static Vector2 scroll;

        public static float EstimatedBleedingAmount
        {
            get
            {
                int days = VariousDefOf.HumanVaginaCompProperties.bleedingIntervalDays;
                return days * 0.03f * Configurations.BleedingAmount * 6;
            }
        }

        public static float EstimatedBleedingAmountPerHour
        {
            get
            {
                return 0.03f * Configurations.BleedingAmount * Configurations.CycleAcceleration;
            }
        }

        public RJW_Menstruation(ModContentPack content) : base(content)
        {
            GetSettings<Configurations>();
            Configurations.HARActivated = ModLister.GetActiveModWithIdentifier("erdelf.HumanoidAlienRaces") != null;
            Configurations.AnimalGeneticsActivated = ModLister.GetActiveModWithIdentifier("Mlie.AnimalGenetics") != null;
        }

        public override string SettingsCategory()
        {
            return Translations.Mod_Title;
        }

        public override void DoSettingsWindowContents(Rect inRect)
        {
            Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
            float mainRectHeight = -3f +
                (Configurations.EnableWombIcon || Configurations.EnableButtonInHT ? 400f : 0f) +
                (Configurations.EstrusOverridesHookupSettings ? 144f : 0f) +
                (Configurations.UseMultiplePregnancy ? (Configurations.EnableEnzygoticTwins ? 175f : 75f) : 0f) +
                (Configurations.EnableBirthVaginaMorph ? 48f : 0f);
            Rect mainRect = new Rect(0f, 0f, inRect.width - 30f, Math.Max(inRect.height + mainRectHeight, 1f));
            int Adjust;
            Listing_Standard listmain = new Listing_Standard
            {
                maxOneColumn = true
            };
            Widgets.BeginScrollView(outRect, ref scroll, mainRect);
            listmain.Begin(mainRect);
            listmain.Gap(20f);
            Rect firstLine = listmain.GetRect(30f);
            firstLine.SplitVertically(firstLine.width / 3, out Rect leftCell, out Rect middleAndRightCells);
            Widgets.CheckboxLabeled(leftCell, Translations.Option1_Label_1, ref Configurations.EnableWombIcon, false, null, null, true);
            Widgets.CheckboxLabeled(middleAndRightCells.LeftHalf(), Translations.Option1_Label_2, ref Configurations.EnableButtonInHT, false, null, null, true);
            Widgets.CheckboxLabeled(middleAndRightCells.RightHalf(), Translations.Option_EnableGatherCumGizmo_Label, ref Configurations.EnableGatherCumGizmo, false, null, null, true);
            if (Configurations.EnableWombIcon || Configurations.EnableButtonInHT)
            {
                Listing_Standard wombsection = listmain.BeginSection(350);
                wombsection.CheckboxLabeled(Translations.Option9_Label, ref Configurations.DrawWombStatus, Translations.Option9_Desc);
                if (Configurations.DrawWombStatus)
                {
                    wombsection.CheckboxLabeled(Translations.Option18_Label, ref Configurations.DrawEggOverlay, Translations.Option18_Desc);
                }

                wombsection.CheckboxLabeled(Translations.Option10_Label, ref Configurations.DrawVaginaStatus, Translations.Option10_Desc);
                wombsection.CheckboxLabeled(Translations.Option29_Label, ref Configurations.AllowShrinkIcon, Translations.Option29_Desc);
                if (wombsection.ButtonText(Translations.Option11_Label + ": " + Configurations.LevelString(Configurations.infoDetail)))
                {
                    if (Configurations.infoDetail == Configurations.DetailLevel.Hide) Configurations.infoDetail = Configurations.DetailLevel.All;
                    else Configurations.infoDetail++;
                }
                switch (Configurations.infoDetail)
                {
                    case Configurations.DetailLevel.All:
                        wombsection.Label(Translations.Option11_Desc_1);
                        break;
                    case Configurations.DetailLevel.OnReveal:
                        wombsection.Label(Translations.Option11_Desc_2);
                        break;
                    case Configurations.DetailLevel.HideFetusInfo:
                        wombsection.Label(Translations.Option11_Desc_3);
                        break;
                    case Configurations.DetailLevel.Hide:
                        wombsection.Label(Translations.Option11_Desc_4);
                        break;
                }
                wombsection.Label(Translations.Option21_Label + " " + Configurations.ShowFlag, -1, Translations.Option21_Desc);
                Rect flagrect = wombsection.GetRect(30f);
                Rect[] flagrects = new Rect[5];
                for (int i = 0; i < 5; i++)
                {
                    flagrects[i] = new Rect(flagrect.x + (flagrect.width / 5) * i, flagrect.y, flagrect.width / 5, flagrect.height);
                }

                if (Widgets.ButtonText(flagrects[0], Translations.Option20_Label_1 + ": " + Configurations.ShowFlag.HasFlag(Configurations.PawnFlags.Colonist)))
                {
                    Configurations.ShowFlag ^= Configurations.PawnFlags.Colonist;
                }
                if (Widgets.ButtonText(flagrects[1], Translations.Option20_Label_2 + ": " + Configurations.ShowFlag.HasFlag(Configurations.PawnFlags.Prisoner)))
                {
                    Configurations.ShowFlag ^= Configurations.PawnFlags.Prisoner;
                }
                if (Widgets.ButtonText(flagrects[2], Translations.Option20_Label_3 + ": " + Configurations.ShowFlag.HasFlag(Configurations.PawnFlags.Ally)))
                {
                    Configurations.ShowFlag ^= Configurations.PawnFlags.Ally;
                }
                if (Widgets.ButtonText(flagrects[3], Translations.Option20_Label_4 + ": " + Configurations.ShowFlag.HasFlag(Configurations.PawnFlags.Neutral)))
                {
                    Configurations.ShowFlag ^= Configurations.PawnFlags.Neutral;
                }
                if (Widgets.ButtonText(flagrects[4], Translations.Option20_Label_5 + ": " + Configurations.ShowFlag.HasFlag(Configurations.PawnFlags.Hostile)))
                {
                    Configurations.ShowFlag ^= Configurations.PawnFlags.Hostile;
                }

                Adjust = (int)(Configurations.MaxBreastIncrementFactor * 1000 / Configurations.MaxBreastIncrementFactorMax);
                wombsection.Label(Translations.Option_MaxBreastIncrementFactor_Label + " " + Configurations.MaxBreastIncrementFactor * 100 + "%", -1, Translations.Option_MaxBreastIncrementFactor_Desc);
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
                Configurations.MaxBreastIncrementFactor = (float)Adjust / (1000 / Configurations.MaxBreastIncrementFactorMax);

                Adjust = (int)(Configurations.MaxNippleIncrementFactor * 1000 / Configurations.MaxNippleIncrementFactorMax);
                wombsection.Label(Translations.Option_MaxNippleIncrementFactor_Label + " " + Configurations.MaxNippleIncrementFactor * 100 + "%", -1, Translations.Option_MaxNippleIncrementFactor_Desc);
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
                Configurations.MaxNippleIncrementFactor = (float)Adjust / (1000 / Configurations.MaxNippleIncrementFactorMax);

                Adjust = (int)(Configurations.PermanentNippleChange * 1000 / Configurations.PermanentNippleChangeMax);
                wombsection.Label(Translations.Option_PermanentNippleChange_Label + " " + Configurations.PermanentNippleChange, -1, Translations.Option_PermanentNippleChange_Desc);
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
                Configurations.PermanentNippleChange = (float)Adjust / (1000 / Configurations.PermanentNippleChangeMax);

                listmain.EndSection(wombsection);
            }

            listmain.CheckboxLabeled(Translations.Option2_Label, ref Configurations.EnableAnimalCycle, Translations.Option2_Desc);

            listmain.CheckboxLabeled(Translations.Option12_Label, ref Configurations.EnableMenopause, Translations.Option12_Desc);

            listmain.Label(Translations.Option3_Label + " " + Configurations.ImplantationChance * 100 + "%", -1, Translations.Option3_Desc);
            Configurations.ImplantationChanceAdjust = (int)listmain.Slider(Configurations.ImplantationChanceAdjust, 0, 1000);
            Configurations.ImplantationChance = (float)Configurations.ImplantationChanceAdjust / 100;

            string tenMl = String.Format("10 ml: {0:0}%", (1.0f - Mathf.Pow(1.0f - Configurations.FertilizeChance, 10)) * 100f);
            listmain.LabelDouble(Translations.Option4_Label + " " + Configurations.FertilizeChance * 100 + "%", tenMl, Translations.Option4_Desc);
            Configurations.FertilizeChanceAdjust = (int)listmain.Slider(Configurations.FertilizeChanceAdjust, 0, 1000);
            Configurations.FertilizeChance = (float)Configurations.FertilizeChanceAdjust / 1000;

            listmain.Label(Translations.Option5_Label + " " + Configurations.CumDecayRatio * 100 + "%", -1, Translations.Option5_Desc);
            Configurations.CumDecayRatioAdjust = (int)listmain.Slider(Configurations.CumDecayRatioAdjust, 0, 1000);
            Configurations.CumDecayRatio = (float)Configurations.CumDecayRatioAdjust / 1000;

            Adjust = (int)(Configurations.EggLifespanMultiplier * 20);
            float lifespan = (24f / Configurations.CycleAcceleration * Configurations.EggLifespanMultiplier);
            listmain.LabelDouble(Translations.Option30_Label + " x" + Configurations.EggLifespanMultiplier, Translations.EstimatedEggLifespan + String.Format(": {0:0}h", (int)lifespan), Translations.Option30_Desc);
            Adjust = (int)listmain.Slider(Adjust, 20, 1000);
            Configurations.EggLifespanMultiplier = (float)Adjust / 20;

            int semenlifespan = (int)(-5 / ((float)Math.Log10((1 - Configurations.CumFertilityDecayRatio) * (1 - Configurations.CumDecayRatio) * 10) - 1)) + 1;
            string estimatedlifespan;
            if (semenlifespan < 0)
            {
                estimatedlifespan = String.Format(": Infinite", semenlifespan);
            }
            else
            {
                estimatedlifespan = String.Format(": {0:0}h", semenlifespan);
            }
            listmain.LabelDouble(Translations.Option6_Label + " " + Configurations.CumFertilityDecayRatio * 100 + "%", Translations.EstimatedCumLifespan + estimatedlifespan, Translations.Option6_Desc);
            Configurations.CumFertilityDecayRatioAdjust = (int)listmain.Slider(Configurations.CumFertilityDecayRatioAdjust, 0, 1000);
            Configurations.CumFertilityDecayRatio = (float)Configurations.CumFertilityDecayRatioAdjust / 1000;

            listmain.Label(Translations.Option7_Label + " x" + Configurations.CycleAcceleration, -1, Translations.Option7_Desc);
            Configurations.CycleAcceleration = (int)listmain.Slider(Configurations.CycleAcceleration, 1, 50);

            float var2 = EstimatedBleedingAmountPerHour;
            float var1 = Math.Max(EstimatedBleedingAmount, var2);
            listmain.LabelDouble(Translations.Option19_Label_1, Translations.Option19_Label_2 + ": " + var1 + "ml, " + var2 + "ml/h", Translations.Option19_Desc);
            Configurations.BleedingAmount = (int)listmain.Slider(Configurations.BleedingAmount, 0, 200);

            listmain.CheckboxLabeled(Translations.Option_EstrusOverride_Label, ref Configurations.EstrusOverridesHookupSettings, Translations.Option_EstrusOverride_Desc);
            if (Configurations.EstrusOverridesHookupSettings)
            {
                listmain.Label(Translations.Option_EstrusFuckability_Label + ": " + (int)(Configurations.EstrusFuckabilityToHookup * 100) + "%");
                Configurations.EstrusFuckabilityToHookup = listmain.Slider(Configurations.EstrusFuckabilityToHookup, 0.1f, 1.0f);
                listmain.Label(Translations.Option_EstrusAttractability_Label + ": " + (int)(Configurations.EstrusAttractivenessToHookup * 100) + "%");
                Configurations.EstrusAttractivenessToHookup = listmain.Slider(Configurations.EstrusAttractivenessToHookup, 0.0f, 1.0f);
                listmain.Label(Translations.Option_EstrusRelationship_Label + ": " + Configurations.EstrusRelationshipToHookup);
                Configurations.EstrusRelationshipToHookup = listmain.Slider((int)Configurations.EstrusRelationshipToHookup, -100f, 100f);
            }

            listmain.CheckboxLabeled(Translations.Option13_Label, ref Configurations.UseMultiplePregnancy, Translations.Option13_Desc);
            if (Configurations.UseMultiplePregnancy)
            {
                float sectionheight = 75f;
                if (Configurations.EnableEnzygoticTwins) sectionheight += 100;
                Listing_Standard twinsection = listmain.BeginSection(sectionheight);
                Rect hybridrect = twinsection.GetRect(25);
                Widgets.CheckboxLabeled(hybridrect.LeftHalf(), Translations.Option22_Label, ref Configurations.UseHybridExtention, false, null, null, true);
                if (Widgets.ButtonText(hybridrect.RightHalf(), Translations.Option28_Label))
                {
                    Dialog_HybridCustom.ToggleWindow();
                    //Configurations.MotherFirst = !Configurations.MotherFirst;
                }
                TooltipHandler.TipRegion(hybridrect, Translations.Option28_Tooltip);

                twinsection.CheckboxLabeled(Translations.Option14_Label, ref Configurations.EnableHeteroOvularTwins, Translations.Option14_Desc);
                twinsection.CheckboxLabeled(Translations.Option15_Label, ref Configurations.EnableEnzygoticTwins, Translations.Option15_Desc);
                if (Configurations.EnableEnzygoticTwins)
                {
                    twinsection.Label(Translations.Option16_Label + " " + Configurations.EnzygoticTwinsChance * 100 + "%", -1, Translations.Option16_Desc);
                    Configurations.EnzygoticTwinsChanceAdjust = (int)twinsection.Slider(Configurations.EnzygoticTwinsChanceAdjust, 0, 1000);
                    Configurations.EnzygoticTwinsChance = (float)Configurations.EnzygoticTwinsChanceAdjust / 1000;

                    twinsection.Label(Translations.Option17_Label + " " + Configurations.MaxEnzygoticTwins, -1, Translations.Option17_Desc);
                    Configurations.MaxEnzygoticTwins = (int)twinsection.Slider(Configurations.MaxEnzygoticTwins, 2, 100);
                }
                listmain.EndSection(twinsection);
            }

            listmain.CheckboxLabeled(Translations.Option31_Label, ref Configurations.EnableBirthVaginaMorph, Translations.Option31_Desc);
            if (Configurations.EnableBirthVaginaMorph)
            {
                float sectionheight = 48f;
                Listing_Standard vmsection = listmain.BeginSection(sectionheight);

                LabelwithTextfield(vmsection.GetRect(24f), Translations.Option32_Label, Translations.Option32_Desc, ref Configurations.VaginaMorphPower, 0, 100f);
                Adjust = (int)(Configurations.VaginaMorphPower * 1000);
                Adjust = (int)vmsection.Slider(Adjust, 0, 1000);
                Configurations.VaginaMorphPower = Adjust / 1000f;

                listmain.EndSection(vmsection);
            }

            Widgets.EndScrollView();

            listmain.CheckboxLabeled(Translations.Option8_Label, ref Configurations.Debug, Translations.Option8_Desc);
            if (listmain.ButtonText(Translations.Button_ResetToDefault))
            {
                Configurations.SettoDefault();

            }

            listmain.End();

        }

        public void LabelwithTextfield(Rect rect, string label, string tooltip, ref float value, float min, float max)
        {
            Rect textfieldRect = new Rect(rect.xMax - 100f, rect.y, 100f, rect.height);
            string valuestr = value.ToString();
            Widgets.Label(rect, label);
            Widgets.TextFieldNumeric(textfieldRect, ref value, ref valuestr, min, max);
            Widgets.DrawHighlightIfMouseover(rect);
            TooltipHandler.TipRegion(rect, tooltip);
        }

    }

}


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

namespace RJW_Menstruation
{
    public class Cum : IExposable
    {
        public Pawn pawn;

        protected float volume; // ml
        public float fertility = 1.0f;
        public bool notcum = false; // for other fluids
        public string notcumLabel = "";
        protected bool useCustomColor = false;
        protected float notcumthickness = 0;
        protected float cumthickness = 1.0f;
        protected Thing internalThing;

        public float Volume
        {
            get
            {
                return volume;
            }
        }

        public float FertVolume
        {
            get
            {
                return volume * fertility;
            }
        }

        public float CumThickness
        {
            get
            {
                return cumthickness;
            }
        }

        public float DecayResist
        {
            get
            {
                if (!notcum) return DNA.cumThickness;
                else return notcumthickness;
            }
            set
            {
                notcumthickness = value;
            }
        }
        protected Color customColor;

        public PawnDNAModExtension DNA
        {
            get
            {
                if (DNAcache != null) return DNAcache;
                try
                {
                    DNAcache = pawn.def.GetModExtension<PawnDNAModExtension>();
                }
                catch (NullReferenceException)
                {
                    DNAcache = ThingDefOf.Human.GetModExtension<PawnDNAModExtension>();
                }
                if (DNAcache == null)
                {
                    DNAcache = ThingDefOf.Human.GetModExtension<PawnDNAModExtension>();
                }
                return DNAcache;
            }
        }
        protected PawnDNAModExtension DNAcache = null;
        public ThingDef FilthDef
        {
            get
            {
                if (filthDef == null) return VariousDefOf.CumFilth;
                else return filthDef;
            }
            set
            {
                filthDef = value;
            }
        }
        protected ThingDef filthDef = null;
        public Color Color
        {
            get
            {
                if (!useCustomColor) return DNA.CumColor;
                else return customColor;
            }

            set
            {
                useCustomColor = true;
                customColor = value;
            }
        }

        public Thing CumThing
        {
            get
            {
                if (internalThing == null)
                {
                    internalThing = ThingMaker.MakeThing(VariousDefOf.CumFilth);
                    internalThing.stackCount = (int)volume;
                }
                internalThing.stackCount = (int)volume;
                return internalThing;
            }
        }

        public Cum() { }

        public Cum(Pawn pawn)
        {
            this.pawn = pawn;
            volume = 1.0f;
            fertility = 1.0f;
        }

        /// <summary>
        /// Not Cum
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="volume"></param>
        /// <param name="notcumlabel"></param>
        /// <param name="decayresist"></param>
        /// <param name="filthDef"></param>
        public Cum(Pawn pawn, float volume, string notcumlabel, float decayresist = 0, ThingDef filthDef = null)
        {
            this.pawn = pawn;
            this.volume = volume;
            this.fertility = 0f;
            this.notcum = true;
            this.notcumLabel = notcumlabel;
            this.notcumthickness = decayresist;
            this.filthDef = filthDef;
        }

        public Cum(Pawn pawn, float volume, float fertility, ThingDef filthDef = null)
        {
            this.pawn = pawn;
            this.volume = volume;
            this.fertility = fertility;
            this.filthDef = filthDef;
        }

        public virtual void ExposeData()
        {
            Scribe_References.Look(ref pawn, "pawn", true);
            Scribe_References.Look(ref internalThing, "internalThing", true);
            Scribe_Values.Look(ref volume, "volume", volume, true);
            Scribe_Values.Look(ref fertility, "fertility", fertility, true);
            Scribe_Values.Look(ref notcumthickness, "notcumthickness", notcumthickness, true);
            Scribe_Values.Look(ref notcum, "notcum", notcum, true);
            Scribe_Values.Look(ref notcumLabel, "notcumLabel", notcumLabel, true);
            Scribe_Values.Look(ref useCustomColor, "useCustomColor", useCustomColor, true);
            Scribe_Values.Look(ref customColor, "customColor", customColor, true);
            Scribe_Defs.Look(ref filthDef, "filthDef");

        }

        public void MakeThinner(int speed)
        {
            cumthickness = cumthickness.LerpMultiple(DecayResist, 0.3f, speed);
        }

        public void MergeWithCum(float volumein, float fertility, ThingDef updatefilthDef = null)
        {
            if (updatefilthDef != null) filthDef = updatefilthDef;
            volume += volumein;
            this.fertility = (this.volume * this.fertility + volumein * fertility) / (this.volume + volumein);
            cumthickness = Mathf.Lerp(cumthickness, 1.0f, volumein / volume);
        }

        public void MergeWithFluid(float volumein, float thickness, ThingDef updatefilthDef = null)
        {
            if (updatefilthDef != null) filthDef = updatefilthDef;
            volume += volumein;
            fertility = volume * fertility / (volume + volumein);
            notcumthickness = Mathf.Lerp(notcumthickness, thickness, volumein / volume);
        }

        public bool ShouldRemove()
        {
            if ((notcum || FertVolume < 0.001f) && volume < 0.01f) return true;
            return false;
        }

        public float DismishNatural(float leakfactor, HediffComp_Menstruation comp, float antisperm = 0.0f)
        {
            // comp is used for Hydrogen's RJW Muscle Injury
            float totalleak = volume;
            volume *= Math.Max(0, (1 - (Configurations.CumDecayRatio * (1 - DecayResist)) * leakfactor));
            fertility *= Math.Max(0, 1 - (Configurations.CumFertilityDecayRatio * (1 - DecayResist) + antisperm));
            CutMinor();
            totalleak -= volume;
            return totalleak;
        }

        public float DismishForce(float portion, float leakfactor = 1.0f)
        {
            float totalleak = volume;
            volume *= Math.Max(0, 1 - (portion * (1 - DecayResist / 10)) * leakfactor);
            CutMinor();
            totalleak -= volume;
            return totalleak;
        }

        public void CumEffects(Pawn pawn)
        {
            if (notcum || DNA?.ingestionOutcomeDoers == null || volume < 1.0f) return;

            foreach (IngestionOutcomeDoer doer in DNA.ingestionOutcomeDoers)
                doer.DoIngestionOutcome(pawn, CumThing);
        }

        protected void CutMinor()
        {
            if (volume < 0.01f) volume = 0f;
        }
    }

    public class CumMixture : Cum
    {
        protected List<string> cums;
        public bool ispurecum = true;
        public List<string> Getingredients => cums;

        public CumMixture()
        {
            notcum = true;
            cums = new List<string>();
        }

        public CumMixture(Pawn pawn, float volume, List<string> cums, Color color, ThingDef mixtureDef, bool pure)
        {
            this.pawn = pawn;
            this.volume = volume;
            this.cums = cums;
            this.customColor = color;
            this.useCustomColor = true;
            ispurecum = pure;
        }

        public override void ExposeData()
        {
            base.ExposeData();
            Scribe_Collections.Look(ref cums, "cumslabel", LookMode.Value, new object[0]);
        }

        public string GetIngredients()
        {
            StringBuilder res = new StringBuilder();

            if (!cums.NullOrEmpty()) for (int i = 0; i < cums.Count; i++)
                {
                    res.Append(cums[i]);
                    if (i < cums.Count - 1) res.Append(", ");
                }
            return res.ToString();
        }
    }
}


code:
using RimWorld;
using Verse;

#pragma warning disable IDE0051 // Remove unused private members
namespace RJW_Menstruation
{
    public static class DebugToolsMenstruation
    {
        [DebugAction("RJW Menstruation", "Set pawn's state to follicular", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void SetFollicular(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.curStage = HediffComp_Menstruation.Stage.Follicular;
            Messages.Message($"{p} is now follicular", p, MessageTypeDefOf.NeutralEvent, false);
        }

        [DebugAction("RJW Menstruation", "Set pawn's state to ovulatory", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void SetOvulatory(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.curStage = HediffComp_Menstruation.Stage.Ovulatory;
            Messages.Message($"{p} is now ovulatory", p, MessageTypeDefOf.NeutralEvent, false);
        }

        [DebugAction("RJW Menstruation", "Set pawn's state to luteal", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void SetLuteal(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.curStage = HediffComp_Menstruation.Stage.Luteal;
            Messages.Message($"{p} is now luteal", p, MessageTypeDefOf.NeutralEvent, false);
        }

        [DebugAction("RJW Menstruation", "Set pawn's state to bleeding", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void SetBleeding(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.curStage = HediffComp_Menstruation.Stage.Bleeding;
            Messages.Message($"{p} is now bleeding", p, MessageTypeDefOf.NeutralEvent, false);
        }
        /*
        [DebugAction("RJW Menstruation", "Set pawn's state to recovering", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void setRecover(Pawn p)
        {
            p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Recover;
        }

        [DebugAction("RJW Menstruation", "Set pawn's state to young", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void setYoung(Pawn p)
        {
            p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Young;
        }
        */
        [DebugAction("RJW Menstruation", "Remove all cum from pawn's womb", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void RemoveCums(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.RemoveAllCums();
            Messages.Message($"All cum removed from {p}'s womb", p, MessageTypeDefOf.NeutralEvent, false);
        }
        [DebugAction("RJW Menstruation", "Add egg to pawn's next ovulation", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void AddEgg(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.eggstack++;
            Messages.Message($"1 egg added to {p}'s next ovulation ({p.GetFirstMenstruationComp().eggstack})", p, MessageTypeDefOf.NeutralEvent, false);
        }

        [DebugAction("RJW Menstruation", "Recalculate pawn's ovary power", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
        private static void RecalculateOvaryPower(Pawn p)
        {
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
                comp.ovarypower = comp.GetOvaryPowerByAge();
            Messages.Message($"{p}'s ovarypower recalculated ({p.GetFirstMenstruationComp().ovarypower})", p, MessageTypeDefOf.NeutralEvent, false);
        }
    }
}
#pragma warning restore IDE0051 // Remove unused private members


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

namespace RJW_Menstruation
{
    public class FertPillOutcomeDoer : IngestionOutcomeDoer
    {
        protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
        {
            foreach (HediffComp_Menstruation comp in pawn.GetMenstruationComps())
                if (comp.curStage.Equals(HediffComp_Menstruation.Stage.Follicular)
                || comp.curStage.Equals(HediffComp_Menstruation.Stage.Luteal)
                || comp.curStage.Equals(HediffComp_Menstruation.Stage.ClimactericFollicular)
                || comp.curStage.Equals(HediffComp_Menstruation.Stage.ClimactericLuteal)
                || comp.curStage.Equals(HediffComp_Menstruation.Stage.Anestrus)
                )
                {
                    comp.SetEstrus();
                    comp.curStage = HediffComp_Menstruation.Stage.Ovulatory;
                    comp.ovarypower--;
                }
        }
    }

    public class InduceOvulationOutcomeDoer : IngestionOutcomeDoer
    {
        protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
        {
            foreach (HediffComp_Menstruation comp in pawn.GetMenstruationComps())
                if (comp.curStage.Equals(HediffComp_Menstruation.Stage.Follicular)
                    || comp.curStage.Equals(HediffComp_Menstruation.Stage.ClimactericFollicular)
                    || comp.curStage.Equals(HediffComp_Menstruation.Stage.Anestrus)
                    )
                {
                    comp.SetEstrus();
                    comp.curStage = HediffComp_Menstruation.Stage.Ovulatory;
                    comp.eggstack += ingested.stackCount - 1;
                }
        }
    }

    public class IngestionOutcomeDoer_AdjustSeverity : IngestionOutcomeDoer
    {
        public HediffDef hediffDef;
        public float severity;

        protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
        {
            Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(hediffDef);
            if (hediff != null) hediff.Severity += severity;
        }

    }

    public class OvaryPillOutcomeDoer : IngestionOutcomeDoer
    {
        public float effectOffset;

        protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
        {
            foreach (HediffComp_Menstruation comp in pawn.GetMenstruationComps())
                if (Configurations.EnableMenopause) comp.RecoverOvary(1 + effectOffset);
        }
    }

    public class SuperOvulationOutcomeDoer : IngestionOutcomeDoer
    {
        protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
        {
            foreach (HediffComp_Menstruation comp in pawn.GetMenstruationComps())
                comp.eggstack += Rand.Range(1, 4);
        }
    }

    public class ContraceptiveOutcomeDoer : IngestionOutcomeDoer
    {
        protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
        {

            List<Thought_Memory> memories = pawn.needs?.mood?.thoughts?.memories?.Memories.FindAll(
                x =>
                x.def == VariousDefOf.CameInsideF
             || x.def == VariousDefOf.CameInsideFFetish
             || x.def == VariousDefOf.HaterCameInsideF);
            if (memories.NullOrEmpty()) return;
            foreach (Thought_Memory m in memories)
            {
                if (m.def == VariousDefOf.HaterCameInsideF) m.moodPowerFactor = 0.5f;
                else m.moodPowerFactor = 0.3f;

            }
            if (pawn.Has(Quirk.Breeder)) pawn.needs.mood.thoughts.memories.TryGainMemoryFast(VariousDefOf.HateTookContraceptivePill);
            else pawn.needs.mood.thoughts.memories.TryGainMemoryFast(VariousDefOf.TookContraceptivePill);
        }
    }
}


code:
using rjw;
using rjw.Modules.Interactions.Contexts;
using rjw.Modules.Interactions.Enums;
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
using rjw.Modules.Shared;
using System.Collections.Generic;
using Verse;

namespace RJW_Menstruation.Interactions
{
    public class EstrusPartKindUsageRule : IPartPreferenceRule
    {
        private const float visible_estrus_multiplier = Multipliers.Doubled;
        private const float concealed_estrus_multiplier = 1.1f;

        private bool WillingAndAble(Pawn fucker, Pawn fucked, bool visible)
        {
            return
                fucked.IsInEstrus(visible)
                &&
                PregnancyHelper.CanImpregnate(fucker, fucked);
        }

        public IEnumerable<Weighted<LewdablePartKind>> ModifiersForDominant(InteractionContext context)
        {
            if (WillingAndAble(context.Internals.Submissive.Pawn, context.Internals.Dominant.Pawn, true))
                yield return new Weighted<LewdablePartKind>(visible_estrus_multiplier, LewdablePartKind.Vagina);
            else if (WillingAndAble(context.Internals.Submissive.Pawn, context.Internals.Dominant.Pawn, false))
                yield return new Weighted<LewdablePartKind>(concealed_estrus_multiplier, LewdablePartKind.Vagina);
        }

        public IEnumerable<Weighted<LewdablePartKind>> ModifiersForSubmissive(InteractionContext context)
        {
            if (WillingAndAble(context.Internals.Dominant.Pawn, context.Internals.Submissive.Pawn, true))
                yield return new Weighted<LewdablePartKind>(visible_estrus_multiplier, LewdablePartKind.Vagina);
            else if (WillingAndAble(context.Internals.Dominant.Pawn, context.Internals.Submissive.Pawn, false))
                yield return new Weighted<LewdablePartKind>(concealed_estrus_multiplier, LewdablePartKind.Vagina);
        }
    }
}


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

namespace RJW_Menstruation
{
    public class FilthMaker_Colored
    {

        public static bool TryMakeFilth(IntVec3 c, Map map, ThingDef filthDef, IEnumerable<string> sources, Color color, bool shouldPropagate, FilthSourceFlags additionalFlags = FilthSourceFlags.None)
        {
            Filth_Colored filth = (Filth_Colored)(from t in c.GetThingList(map)
                                                  where t.def == filthDef
                                                  select t).FirstOrDefault<Thing>();
            if (!c.Walkable(map) || (filth != null && !filth.CanBeThickened))
            {
                if (shouldPropagate)
                {
                    List<IntVec3> list = GenAdj.AdjacentCells8WayRandomized();
                    for (int i = 0; i < 8; i++)
                    {
                        IntVec3 c2 = c + list[i];
                        if (c2.InBounds(map) && TryMakeFilth(c2, map, filthDef, sources, color, false, FilthSourceFlags.None))
                        {
                            return true;
                        }
                    }
                }
                if (filth != null)
                {
                    filth.AddSources(sources);
                }
                return false;
            }
            if (filth != null)
            {
                filth.ThickenFilth();
                filth.AddSources(sources);
            }
            else
            {
                if (!FilthMaker.CanMakeFilth(c, map, filthDef, additionalFlags))
                {
                    return false;
                }
                Filth_Colored filth2 = (Filth_Colored)ThingMaker.MakeThing(filthDef, null);
                filth2.DrawColor = color;
                filth2.AddSources(sources);
                GenSpawn.Spawn(filth2, c, map, WipeMode.Vanish);
            }
            //FilthMonitor.Notify_FilthSpawned();
            return true;
        }

    }
}


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

namespace RJW_Menstruation
{
    public class CompProperties_Breast : HediffCompProperties
    {
        public static readonly ColorInt DefaultBlacknippleColor = new ColorInt(55, 20, 0);
        public string BreastTex = "Breasts/Breast";
        public ColorInt BlacknippleColor = new ColorInt(55, 20, 0);

        public Color BlackNippleColor
        {
            get
            {
                return BlacknippleColor.ToColor;
            }
        }

        public CompProperties_Breast()
        {
            compClass = typeof(HediffComp_Breast);
        }
    }

    public class HediffComp_Breast : HediffComp
    {
        public const int tickInterval = GenDate.TicksPerHour * 3 / 2;
        public const float breastGrowthStart = 1f / 6f;
        public const float breastGrowthEnd = 1f / 3f;
        public static readonly SimpleCurve nippleTransitions = new SimpleCurve()
        {
            new CurvePoint(0f,0f),
            new CurvePoint(0.1f,0f),
            new CurvePoint(0.333f,0.167f),
            new CurvePoint(0.667f,0.833f),
            new CurvePoint(1.0f,1.0f)
        };
        public const float nippleChange = 0.2f;

        public CompProperties_Breast Props;

        protected long ageOfLastBirth = 0;
        protected float maxBreastIncrement = -1f;
        protected float breastSizeIncreased = 0f;
        protected string debugGrowthStatus = "(Growth/shrink not yet calculated; run for 1.5h to update)";
        protected float nippleProgress = 0f;
        protected float baseAlpha = -1f;    // Will grow in response to pregnancy
        protected float baseAreola = -1f;
        protected float baseNipple = -1f;
        protected float cachedAlpha = -1f;  // Calculated dynamically instead of saved
        protected float cachedAreola = -1f; // Actual size = these * breast size
        protected float cachedNipple = -1f;
        protected float babyHalfAge = -1f;

        protected Color cachedColor;
        protected bool loaded = false;

        protected float BabyHalfAge
        {
            get
            {
                if (babyHalfAge > 0f) return babyHalfAge;
                List<LifeStageAge> ages = Pawn.def.race.lifeStageAges;
                if (ages?.Count > 1)
                    babyHalfAge = ages[1].minAge / 2;

                if (babyHalfAge <= 0) babyHalfAge = 1.2f / 2; // Default to human

                if (RJWPregnancySettings.phantasy_pregnancy)
                    babyHalfAge /= GenDate.DaysPerYear;

                return babyHalfAge;
            }
        }

        protected void ShrinkBreasts()
        {
            // The natural rate will take them from full to empty during the second half of their child's babyhood
            float shrinkRate = tickInterval * MaxBreastIncrement / (BabyHalfAge * GenDate.TicksPerYear);
            float shrinkAmount = Mathf.Min(shrinkRate, breastSizeIncreased);
            breastSizeIncreased -= shrinkAmount;
            parent.Severity -= shrinkAmount;
        }

        protected float MaxBreastIncrement
        {
            get
            {
                return maxBreastIncrement * Configurations.MaxBreastIncrementFactor;
            }
        }

        public Color NippleColor
        {
            get
            {
                return cachedColor;
            }
        }
        public float Alpha
        {
            get
            {
                return cachedAlpha;
            }
        }
        public float NippleSize
        {
            get
            {
                return cachedNipple * parent.Severity;
            }
        }
        public float AreolaSize
        {
            get
            {
                return cachedAreola * parent.Severity;
            }
        }

        public float BreastSizeIncreased
        {
            get
            {
                return breastSizeIncreased;
            }
        }

        public override void CompExposeData()
        {
            base.CompExposeData();

            if (Scribe.mode == LoadSaveMode.LoadingVars)
            {   // For compatibility
                Scribe_Values.Look(ref baseAlpha, "alphaPermanent", baseAlpha / 2, false);
                Scribe_Values.Look(ref baseAreola, "areolaSizePermanent", baseAreola / 2, false);
                Scribe_Values.Look(ref baseNipple, "nippleSizePermanent", baseNipple / 2, false);
                baseAlpha *= 2;
                baseAreola *= 2;
                baseNipple *= 2;
            }
            Scribe_Values.Look(ref ageOfLastBirth, "ageOfLastBirth", ageOfLastBirth, true);
            Scribe_Values.Look(ref maxBreastIncrement, "maxBreastIncrement", maxBreastIncrement, true);
            Scribe_Values.Look(ref breastSizeIncreased, "breastSizeIncreased", breastSizeIncreased, true);
            Scribe_Values.Look(ref nippleProgress, "nippleProgress", nippleProgress, true);
            Scribe_Values.Look(ref baseAlpha, "baseAlpha", baseAlpha, true);
            Scribe_Values.Look(ref baseAreola, "baseAreola", baseAreola, true);
            Scribe_Values.Look(ref baseNipple, "baseNipple", baseNipple, true);
        }

        public bool ShouldSimulate()
        {
            if (!Configurations.EnableAnimalCycle && Pawn.IsAnimal()) return false;
            if (Pawn.Spawned || Pawn.IsCaravanMember() || PawnUtility.IsTravelingInTransportPodWorldObject(Pawn)) return true;

            return false;
        }

        public override void CompPostTick(ref float severityAdjustment)
        {
            base.CompPostTick(ref severityAdjustment);
            // If an exception makes it out, RW will remove the hediff, so catch it here
            try
            {
                if (
                    !Pawn.IsHashIntervalTick(tickInterval) ||
                    !ShouldSimulate()
                    )
                {
                    return;
                }
                CalculateBreastSize();
                CalculateNipples();
                UpdateNipples();
            }
            catch (Exception ex)
            {
                Log.Error($"Error processing breasts of {Pawn}: {ex}");
            }

        }

        public override void CompPostPostAdd(DamageInfo? dinfo)
        {
            if (!loaded) Initialize();
            if (ageOfLastBirth > Pawn.ageTracker.AgeChronologicalTicks) ageOfLastBirth = CalculateLastBirth();   // catch transplant issues
        }

        public override void CompPostPostRemoved()
        {
            if (Pawn.health.hediffSet.hediffs.Contains(parent))
            {
                Log.Warning($"Attempted to remove breast comp from wrong pawn ({Pawn}).");
                return;
            }
            base.CompPostPostRemoved();
        }

        protected long CalculateLastBirth()
        {
            long youngestAge = (long)(BabyHalfAge * GenDate.TicksPerYear) * -2; // So a newborn isn't considered a new mother, either

            if ((Pawn.relations == null)) return youngestAge;

            bool hasChild = Pawn.relations.Children.
                Where(child => !Pawn.health.hediffSet.GetHediffs<Hediff_BasePregnancy>().Any(preg => preg.babies.Contains(child))). // no fetuses
                Where(child => child.GetMother() == Pawn).  // not Dad
                TryMinBy(child => child.ageTracker.AgeBiologicalTicks, out Pawn youngest);

            if (hasChild) youngestAge = Pawn.ageTracker.AgeBiologicalTicks - youngest.ageTracker.AgeBiologicalTicks;

            return youngestAge;
        }

        public void Initialize()
        {
            Props = (CompProperties_Breast)props;

            if (maxBreastIncrement <= 0f)
            {
                maxBreastIncrement = Utility.RandGaussianLike(0.088f, 0.202f);
            }
            if (ageOfLastBirth == 0)
            {
                ageOfLastBirth = CalculateLastBirth();
            }
            if (baseAlpha <= 0f)
            {
                baseAlpha = Utility.RandGaussianLike(0.0f, 0.3f) + Rand.Range(0.0f, 0.5f);
            }
            if (baseAreola <= 0f)
            {
                baseAreola = Utility.RandGaussianLike(0.0f, 1.0f);
            }
            if (baseNipple <= 0f)
            {
                baseNipple = Utility.RandGaussianLike(0.0f, 1.0f);
            }
            UpdateNipples();
            loaded = true;
        }

        protected void CalculateBreastSize()
        {
            // Scenario A: the youngest child is less than halfway into babyhood: Full size
            if (ageOfLastBirth + BabyHalfAge * GenDate.TicksPerYear > Pawn.ageTracker.AgeBiologicalTicks)
            {
                debugGrowthStatus = "Full size due to young child";
                if (breastSizeIncreased < MaxBreastIncrement)
                {
                    parent.Severity += (MaxBreastIncrement - breastSizeIncreased);
                    breastSizeIncreased = MaxBreastIncrement;
                }
            }
            // Scenario B: Pregnant, grow in the second half of first trimester
            else if (Pawn.IsRJWPregnant())
            {
                float pregnancySize = Mathf.InverseLerp(breastGrowthStart, breastGrowthEnd, Pawn.GetFarthestPregnancyProgress()) * MaxBreastIncrement;
                if (breastSizeIncreased > pregnancySize)
                {
                    debugGrowthStatus = "Shrinking due to being oversize for pregnancy";
                    // Breasts still large from the last kid
                    ShrinkBreasts();
                }
                else if (breastSizeIncreased < MaxBreastIncrement)
                {
                    // Time to grow
                    float growAmount = pregnancySize - breastSizeIncreased;
                    if (growAmount != 0)
                        debugGrowthStatus = "Growing due to pregnancy";
                    else
                        debugGrowthStatus = "Pregnant, but not time to grow";
                    breastSizeIncreased += growAmount;
                    parent.Severity += growAmount;
                }
                else debugGrowthStatus = "Pregnant and full size";
            }
            // Scenario C: Not (or very early) pregnant and youngest child nonexistent or more than halfway into babyhood, time to shrink
            else if (breastSizeIncreased > 0)
            {
                debugGrowthStatus = "Shrinking due to no pregnancy nor young child";
                ShrinkBreasts();
            }
            else debugGrowthStatus = "Base size";
        }

        protected void CalculateNipples()
        {
            float newNippleProgress;
            if (ageOfLastBirth + BabyHalfAge * GenDate.TicksPerYear > Pawn.ageTracker.AgeBiologicalTicks)
                newNippleProgress = 1f;
            else if (Pawn.IsRJWPregnant())
                newNippleProgress = nippleTransitions.Evaluate(Pawn.GetFarthestPregnancyProgress());
            else
                newNippleProgress = 0f;

            if (newNippleProgress < 0) newNippleProgress = 0;

            if (newNippleProgress == nippleProgress) return;    // Nothing to change
            else if (newNippleProgress > nippleProgress)
            {
                float progressDifference = newNippleProgress - nippleProgress;
                // All nipple growth has a slight effect on the base
                // Not mathematically precise in hitting the goal at the end of the term, but close enough
                baseAlpha *= 1.0f + progressDifference * Configurations.PermanentNippleChange;
                if (baseAlpha > 1.0f) baseAlpha = 1.0f;
                baseAreola *= 1.0f + progressDifference * Configurations.PermanentNippleChange;
                if (baseAreola > 1.0f) baseAreola = 1.0f;
                baseNipple *= 1.0f + progressDifference * Configurations.PermanentNippleChange;
                if (baseNipple > 1.0f) baseNipple = 1.0f;
                nippleProgress = newNippleProgress;
            }
            else
            {
                nippleProgress -= tickInterval / (BabyHalfAge * GenDate.TicksPerYear);
                if (nippleProgress < newNippleProgress) nippleProgress = newNippleProgress;
            }
        }

        public void GaveBirth()
        {
            ageOfLastBirth = Pawn.ageTracker.AgeBiologicalTicks;
        }

        public void AdjustNippleProgress(float amount)
        {
            nippleProgress = Mathf.Clamp01(nippleProgress + amount);
            UpdateNipples();
        }

        public void AdjustNippleSizeImmediately(float amount)
        {
            baseNipple = Mathf.Clamp01(baseNipple + amount);
            UpdateNipples();
        }

        public void AdjustNippleColorImmediately(float amount)
        {
            baseAlpha = Mathf.Clamp01(baseAlpha + amount);
            UpdateNipples();
        }

        public void AdjustAreolaSizeImmediately(float amount)
        {
            baseAreola = Mathf.Clamp01(baseAreola + amount);
            UpdateNipples();
        }

        public void UpdateNipples()
        {
            cachedAlpha = baseAlpha + nippleProgress * nippleChange;
            cachedAreola = baseAreola + nippleProgress * nippleChange;
            cachedNipple = baseNipple + nippleProgress * nippleChange;

            // For some reason, Props can go null when RJW relocates the chest (e.g. some animals), so catch that
            cachedColor = Colors.CMYKLerp(Pawn.story?.SkinColor ?? Color.white, (Props?.BlackNippleColor ?? CompProperties_Breast.DefaultBlacknippleColor.ToColor), Alpha);
        }

        public void CopyBreastProperties(HediffComp_Breast original)
        {
            maxBreastIncrement = original.maxBreastIncrement;
            baseAlpha = original.baseAlpha;
            baseAreola = original.baseAreola;
            baseNipple = original.baseNipple;
            UpdateNipples();
        }

        public string DebugInfo()
        {
            return "Size: " + parent.Severity +
                "\nIncrease: " + breastSizeIncreased +
                "\n" + debugGrowthStatus +
                "\nNipple progress: " + nippleProgress +
                "\nBase alpha: " + baseAlpha +
                "\nAlpha: " + cachedAlpha +
                "\nBase areola: " + baseAreola +
                "\nAreola: " + cachedAreola +
                "\nDisplayed areola: " + AreolaSize +
                "\nBase nipple: " + baseNipple +
                "\nNipple: " + cachedNipple +
                "\nDisplayed nipple: " + NippleSize;
        }
    }
}


code:
using RimWorld;
using UnityEngine;
using Verse;

namespace RJW_Menstruation
{
    public class CompProperties_InducedOvulator : CompProperties_Menstruation
    {
        public CompProperties_InducedOvulator()
        {
            compClass = typeof(HediffComp_InducedOvulator);
        }

    }

    public class HediffComp_InducedOvulator : HediffComp_Menstruation
    {
        public override string GetCurStageDesc
        {
            get
            {
                switch (CurrentVisibleStage)
                {
                    case Stage.Follicular:
                        return Translations.Stage_Follicular_Induced_Desc + (EggHealth < 1f ? Translations.Stage_Climacteric_Desc : "");
                    case Stage.ClimactericFollicular:
                        return Translations.Stage_Follicular_Induced_Desc + " " + Translations.Stage_Climacteric_Desc;
                    default:
                        return base.GetCurStageDesc;
                }
            }
        }

        // In an induced ovulator, about 65% of eggs ovulated will become pregnancies, so the expected lifetime supply
        // is the number of pregnancies they could have, with some extra to be sure.
        // An IUD or a poor fertility mate could run this down quicker. Oh well.
        protected override float RaceCyclesPerYear()
        {
            // Don't bother with breeding season, since so much time is planned to be spent pregnant.
            float pregnanciesPerYear = GenDate.DaysPerYear / Mathf.Max(1, Pawn.def.race.gestationPeriodDays);

            return 2 * pregnanciesPerYear / Configurations.ImplantationChanceDefault;
        }

        // There's really no good way to estimate the number of times it's been induced, so this is all we can do
        protected override int PawnEggsUsed(float pawnCyclesElapsed, float avglittersize)
        {
            return Mathf.CeilToInt((Pawn.relations?.ChildrenCount ?? 0) / Configurations.ImplantationChanceDefault);
        }

        protected override void GoOvulatoryStage()
        {
            estrusflag = false;
            GoNextStage(Stage.Luteal);
        }

        protected override void AfterCumIn(Pawn cummer)
        {
            base.AfterCumIn(cummer);
            switch (curStage)
            {
                case Stage.Follicular:
                case Stage.ClimactericFollicular:
                    GoNextStage(Stage.Ovulatory);
                    break;
            }
        }

        public override bool IsDangerDay
        {
            get
            {
                if (Pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) return false;

                switch (curStage)
                {
                    case Stage.Follicular:
                    case Stage.ClimactericFollicular:
                    case Stage.Ovulatory:
                        return true;
                    case Stage.Luteal:
                    case Stage.ClimactericLuteal:
                        return IsEggExist && curStageHrs < Props.eggLifespanDays * 24;
                    default:
                        return false;
                }
            }
        }

        protected override bool ShouldBeInEstrus()
        {
            if (!loaded)
                Initialize();
            switch (curStage)
            {
                case Stage.Follicular:
                case Stage.ClimactericFollicular:
                    return curStageHrs > currentIntervalHours - Props.estrusDaysBeforeOvulation * 24;
                case Stage.Ovulatory:
                    return true;
                case Stage.Luteal:
                case Stage.ClimactericLuteal:
                    return IsEggExist && curStageHrs < Props.eggLifespanDays * 24;
                default:
                    return false;
            }
        }
    }
}