diff --git a/1.3/Assemblies/RJW_Menstruation.dll b/1.3/Assemblies/RJW_Menstruation.dll index b340755..7cef547 100644 Binary files a/1.3/Assemblies/RJW_Menstruation.dll and b/1.3/Assemblies/RJW_Menstruation.dll differ diff --git a/1.3/Defs/TaleDefs/Tales_Cum.xml b/1.3/Defs/TaleDefs/Tales_Cum.xml new file mode 100644 index 0000000..b5a37c7 --- /dev/null +++ b/1.3/Defs/TaleDefs/Tales_Cum.xml @@ -0,0 +1,31 @@ + + + CameInside + + Tale_DoublePawn + Volatile + FUCKER + FUCKED + 1.5 + + +
  • tale_noun->[FUCKER_nameDef] coming inside of [FUCKED_nameDef]
  • +
  • image->[FUCKER_nameFull]'s penis deep inside of [FUCKED_nameFull]'s vagina [circumstance_group]
  • +
  • image->[FUCKER_nameFull]'s penis vanishing into [FUCKED_nameFull]'s vagina [circumstance_group]
  • +
  • image->[FUCKED_nameFull]'s vagina being filled by [FUCKER_nameFull]'s penis [circumstance_group]
  • +
  • image->[FUCKED_nameFull]'s vagina gripping [FUCKER_nameFull]'s penis tight [cirsumstance_group]
  • +
  • circumstance_phrase->while [FUCKER_nameDef] grits [FUCKER_possessive] teeth
  • +
  • circumstance_phrase->while [FUCKER_nameDef] wears a triumphant smirk
  • +
  • circumstance_phrase->as [FUCKED_nameDef] shudders in ecstasy
  • +
  • circumstance_phrase->as [FUCKER_nameDef] shoots [FUCKER_possessive] load into [FUCKED_nameDef]
  • +
  • circumstance_phrase->while [FUCKED_nameDef] looks into [FUCKER_nameDef]'s eyes with a smile
  • +
  • desc_sentence->[FUCKER_nameDef]'s cum oozes out of [FUCKED_nameDef]'s vagina and drips onto the floor.
  • +
  • desc_sentence->[FUCKER_nameDef]'s sperm races into [FUCKED_nameDef]'s womb and enters [FUCKED_possessive] egg.
  • +
  • desc_sentence->[FUCKER_nameDef]'s cum shoots into [FUCKED_nameDef]'s womb.
  • +
  • desc_sentence->[FUCKED_nameDef]'s womb is filled with cum.
  • +
  • desc_sentence->Sweat runs down [FUCKER_nameDef]'s face.
  • +
  • desc_sentence->[FUCKED_nameDef] is panting heavily.
  • +
    +
    +
    +
    \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/Keyed/RJW_Menstruation.xml b/1.3/Languages/ChineseSimplified/Keyed/RJW_Menstruation.xml index 32aa104..d10b3fe 100644 --- a/1.3/Languages/ChineseSimplified/Keyed/RJW_Menstruation.xml +++ b/1.3/Languages/ChineseSimplified/Keyed/RJW_Menstruation.xml @@ -8,7 +8,6 @@ 排卵 黄体期 月经来潮 - 已受精 怀孕 产后恢复 diff --git a/1.3/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml b/1.3/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml index eb4314f..3ce1dfe 100644 --- a/1.3/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml +++ b/1.3/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml @@ -8,7 +8,6 @@ 排卵 黃體期 月經來潮 - 已受精 懷孕 從出生中恢復 diff --git a/1.3/Languages/English/Keyed/RJW_Menstruation.xml b/1.3/Languages/English/Keyed/RJW_Menstruation.xml index 2f84c88..bdb4a6f 100644 --- a/1.3/Languages/English/Keyed/RJW_Menstruation.xml +++ b/1.3/Languages/English/Keyed/RJW_Menstruation.xml @@ -8,7 +8,6 @@ Ovulation Luteal In period - Luteal Pregnant Recovering from birth None diff --git a/1.3/Languages/Korean/Keyed/RJW_Menstruation.xml b/1.3/Languages/Korean/Keyed/RJW_Menstruation.xml index 6370588..829fcf5 100644 --- a/1.3/Languages/Korean/Keyed/RJW_Menstruation.xml +++ b/1.3/Languages/Korean/Keyed/RJW_Menstruation.xml @@ -8,7 +8,6 @@ 배란 황체기 생리중 - 황체기 임신 회복기 없음 diff --git a/1.3/Languages/Spanish/Keyed/RJW_Menstruation.xml b/1.3/Languages/Spanish/Keyed/RJW_Menstruation.xml index 7e28a7a..e428b7d 100644 --- a/1.3/Languages/Spanish/Keyed/RJW_Menstruation.xml +++ b/1.3/Languages/Spanish/Keyed/RJW_Menstruation.xml @@ -8,7 +8,6 @@ Ovulación Luteal En periodo - Luteal Embarazada Recuperándose del nacimiento Ninguna diff --git a/1.3/MilkModule/Assemblies/MilkModule.dll b/1.3/MilkModule/Assemblies/MilkModule.dll index 9b9615a..778684a 100644 Binary files a/1.3/MilkModule/Assemblies/MilkModule.dll and b/1.3/MilkModule/Assemblies/MilkModule.dll differ diff --git a/1.3/Patches/Hediffs_PrivateParts.xml b/1.3/Patches/Hediffs_PrivateParts.xml index 9dce268..662def7 100644 --- a/1.3/Patches/Hediffs_PrivateParts.xml +++ b/1.3/Patches/Hediffs_PrivateParts.xml @@ -1,8 +1,8 @@ - - - + + + @@ -16,15 +16,13 @@ 10 1.0 1.0 - 0.05 - 14 + 14 14 6 30 1 Womb/Womb Genitals/Vagina - 420 true @@ -40,8 +38,7 @@ 10 1.0 1.0 - 0.05 - 14 + 14 14 0 30 @@ -89,8 +86,7 @@ 10 2.0 2.0 - 0.05 - 14 + 14 14 0 0 diff --git a/1.3/Patches/Hediffs_PrivateParts_Animal.xml b/1.3/Patches/Hediffs_PrivateParts_Animal.xml index adfb808..8ffacb0 100644 --- a/1.3/Patches/Hediffs_PrivateParts_Animal.xml +++ b/1.3/Patches/Hediffs_PrivateParts_Animal.xml @@ -1,8 +1,8 @@ - - - + + + @@ -18,8 +18,7 @@ 8 1.0 1.0 - 0.05 - 14 + 14 166 8 15 @@ -40,8 +39,7 @@ 6 1.0 2.0 - 0.05 - 9 + 9 10 0 15 @@ -63,8 +61,7 @@ 25 1.0 1.0 - 0.05 - 7 + 7 14 0 30 @@ -87,8 +84,7 @@ 50 0.5 0.2 - 0.05 - 270 + 270 30 0 300 @@ -109,8 +105,7 @@ 10 1.0 1.0 - 0.05 - 5 + 5 16 0 15 @@ -131,8 +126,7 @@ 5 1.0 2.0 - 0.05 - 6 + 6 9 0 3 @@ -153,8 +147,7 @@ 5 2.0 2.0 - 0.05 - 12 + 12 9 0 3 @@ -175,8 +168,7 @@ 10 2.0 2.0 - 0.05 - 14 + 14 14 0 3 diff --git a/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Animal_RaceSupport.xml b/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Animal_RaceSupport.xml index 7628c4d..556660e 100644 --- a/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Animal_RaceSupport.xml +++ b/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Animal_RaceSupport.xml @@ -1,8 +1,8 @@ - - - + + + @@ -18,8 +18,7 @@ 18 1.0 1.0 - 0.05 - 10 + 10 10 4 30 @@ -40,8 +39,7 @@ 8 1.0 1.0 - 0.05 - 8 + 8 12 0 0 @@ -62,8 +60,7 @@ 15 1.0 1.0 - 0.05 - 10 + 10 12 0 30 @@ -84,8 +81,7 @@ 8 1.0 1.0 - 0.05 - 6 + 6 12 0 30 @@ -106,8 +102,7 @@ 12 1.0 1.0 - 0.05 - 14 + 14 20 0 30 @@ -128,8 +123,7 @@ 2 0.1 0.1 - 0.05 - 14 + 14 14 0 0 @@ -150,8 +144,7 @@ 10 0.1 0.1 - 0.05 - 14 + 14 14 0 0 diff --git a/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Humanlike_RaceSupport.xml b/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Humanlike_RaceSupport.xml index 59505fa..e0d0729 100644 --- a/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Humanlike_RaceSupport.xml +++ b/1.3/RJW Menstruation Race Support/Patches/Hediffs_PrivateParts_Humanlike_RaceSupport.xml @@ -1,8 +1,8 @@ - - - + + + @@ -16,15 +16,13 @@ 10 1.0 1.0 - 0.05 - 1800 + 1800 1800 6 30 1 Womb/Womb Genitals/Vagina - 620 true @@ -50,15 +48,13 @@ 10 1.0 1.0 - 0.05 - 7 + 7 10 0 10 1 Womb/Womb Genitals/Vagina - 620 true @@ -86,15 +82,13 @@ 10 0.2 0.2 - 0.05 - 14 + 14 14 0 10 1 Womb/Womb Genitals/Vagina - 420 true diff --git a/1.3/SexperienceModule/Assemblies/SexperienceModule.dll b/1.3/SexperienceModule/Assemblies/SexperienceModule.dll index 55382de..79ed7a6 100644 Binary files a/1.3/SexperienceModule/Assemblies/SexperienceModule.dll and b/1.3/SexperienceModule/Assemblies/SexperienceModule.dll differ diff --git a/1.3/source/RJW_Menstruation/MilkModule/JobDriver_MilkSelf.cs b/1.3/source/RJW_Menstruation/MilkModule/JobDriver_MilkSelf.cs index e331d6b..b35b0a6 100644 --- a/1.3/source/RJW_Menstruation/MilkModule/JobDriver_MilkSelf.cs +++ b/1.3/source/RJW_Menstruation/MilkModule/JobDriver_MilkSelf.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Verse; -using Verse.AI; -using RimWorld; -using Milk; +using Milk; using RJW_Menstruation; +using Verse; namespace MilkModule { @@ -51,7 +44,7 @@ namespace MilkModule if (pawn.health.hediffSet.HasHediff(VariousDefOf.Hediff_Heavy_Lactating_Permanent)) { result = pawn.TryGetComp(); - + } else { @@ -125,6 +118,6 @@ namespace MilkModule // // //} - + } diff --git a/1.3/source/RJW_Menstruation/MilkModule/Milk_Patch.cs b/1.3/source/RJW_Menstruation/MilkModule/Milk_Patch.cs index 8fbcb96..2de9e87 100644 --- a/1.3/source/RJW_Menstruation/MilkModule/Milk_Patch.cs +++ b/1.3/source/RJW_Menstruation/MilkModule/Milk_Patch.cs @@ -1,14 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Reflection; -using HarmonyLib; -using Verse; -using RimWorld; +using HarmonyLib; using Milk; using RJW_Menstruation; +using System.Reflection; +using Verse; namespace MilkModule { @@ -16,7 +10,7 @@ namespace MilkModule { static First() { - var har = new Harmony("RJW_Menstruation_MilkModule"); + Harmony har = new Harmony("RJW_Menstruation_MilkModule"); har.PatchAll(Assembly.GetExecutingAssembly()); } } diff --git a/1.3/source/RJW_Menstruation/MilkModule/Properties/AssemblyInfo.cs b/1.3/source/RJW_Menstruation/MilkModule/Properties/AssemblyInfo.cs index 019d075..c526740 100644 --- a/1.3/source/RJW_Menstruation/MilkModule/Properties/AssemblyInfo.cs +++ b/1.3/source/RJW_Menstruation/MilkModule/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs index 739e645..2ef752e 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs @@ -10,12 +10,12 @@ namespace RJW_Menstruation { public const float ImplantationChanceDefault = 0.65f; public const int ImplantationChanceAdjustDefault = 65; - public const float FertilizeChanceDefault = 0.10f; - public const int FertilizeChanceAdjustDefault = 100; - public const float CumDecayRatioDefault = 0.30f; - public const int CumDecayRatioAdjustDefault = 300; - public const float CumFertilityDecayRatioDefault = 0.2f; - public const int CumFertilityDecayRatioAdjustDefault = 200; + 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; @@ -79,7 +79,7 @@ namespace RJW_Menstruation return NippleTransitionVariance * NippleTransitionSpeed; } } - + public static void SettoDefault() { ImplantationChanceAdjust = ImplantationChanceAdjustDefault; @@ -152,14 +152,14 @@ namespace RJW_Menstruation { List removeList = new List(); if (!HybridOverride.NullOrEmpty()) - foreach(HybridInformations o in HybridOverride) + foreach (HybridInformations o in HybridOverride) { if (o.IsNull) removeList.Add(o); if (o.DefName == def.defName) return true; } if (!removeList.NullOrEmpty()) { - foreach(HybridInformations o in removeList) + foreach (HybridInformations o in removeList) { HybridOverride.Remove(o); } @@ -226,7 +226,7 @@ namespace RJW_Menstruation base.ExposeData(); } - + } @@ -242,7 +242,7 @@ namespace RJW_Menstruation { get { - int days = VariousDefOf.VaginaCompProperties.bleedingIntervalDays; + int days = VariousDefOf.HumanVaginaCompProperties.bleedingIntervalDays; return days * 0.03f * Configurations.BleedingAmount * 6; } } @@ -300,7 +300,7 @@ namespace RJW_Menstruation { 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))) @@ -353,17 +353,17 @@ namespace RJW_Menstruation } Adjust = (int)(Configurations.NippleTransitionVariance * 1000); - wombsection.Label(Translations.Option24_Label + " " + Configurations.NippleTransitionVariance* 100 + " / 100", -1,Translations.Option24_Desc); - Adjust = (int)wombsection.Slider(Adjust,0,1000); + wombsection.Label(Translations.Option24_Label + " " + Configurations.NippleTransitionVariance * 100 + " / 100", -1, Translations.Option24_Desc); + Adjust = (int)wombsection.Slider(Adjust, 0, 1000); Configurations.NippleTransitionVariance = (float)Adjust / 1000; Adjust = (int)(Configurations.NipplePermanentTransitionVariance * 1000); - wombsection.Label(Translations.Option25_Label + " " + Configurations.NipplePermanentTransitionVariance*100 + " / 100", -1, Translations.Option25_Desc); + wombsection.Label(Translations.Option25_Label + " " + Configurations.NipplePermanentTransitionVariance * 100 + " / 100", -1, Translations.Option25_Desc); Adjust = (int)wombsection.Slider(Adjust, 0, 1000); Configurations.NipplePermanentTransitionVariance = (float)Adjust / 1000; Adjust = (int)(Configurations.NippleMaximumTransition * 1000); - wombsection.Label(Translations.Option26_Label + " " + Configurations.NippleMaximumTransition* 100 + " / 100", -1, Translations.Option26_Desc); + wombsection.Label(Translations.Option26_Label + " " + Configurations.NippleMaximumTransition * 100 + " / 100", -1, Translations.Option26_Desc); Adjust = (int)wombsection.Slider(Adjust, 0, 1000); Configurations.NippleMaximumTransition = (float)Adjust / 1000; @@ -383,7 +383,8 @@ namespace RJW_Menstruation Configurations.ImplantationChanceAdjust = (int)listmain.Slider(Configurations.ImplantationChanceAdjust, 0, 1000); Configurations.ImplantationChance = (float)Configurations.ImplantationChanceAdjust / 100; - listmain.Label(Translations.Option4_Label + " " + Configurations.FertilizeChance * 100 + "%", -1, Translations.Option4_Desc); + 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; @@ -399,7 +400,7 @@ namespace RJW_Menstruation Configurations.EggLifespanMultiplier = (float)Adjust / 20; - int semenlifespan = (int)(-5 / ((float)Math.Log10((1 - Configurations.CumFertilityDecayRatio)*10) - 1)) + 1; + int semenlifespan = (int)(-5 / ((float)Math.Log10((1 - Configurations.CumFertilityDecayRatio) * (1 - Configurations.CumDecayRatio) * 10) - 1)) + 1; string estimatedlifespan; if (semenlifespan < 0) { diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Cum.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Cum.cs index 2976f05..d969e18 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Cum.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Cum.cs @@ -11,8 +11,7 @@ namespace RJW_Menstruation public Pawn pawn; protected float volume; // ml - protected float fertvolume; - public float fertFactor = 1.0f; + public float fertility = 1.0f; public bool notcum = false; // for other fluids public string notcumLabel = ""; protected bool useCustomColor = false; @@ -32,7 +31,7 @@ namespace RJW_Menstruation { get { - return fertvolume; + return volume * fertility; } } @@ -62,23 +61,20 @@ namespace RJW_Menstruation { get { + if (DNAcache != null) return DNAcache; + try + { + DNAcache = pawn.def.GetModExtension(); + } + catch (NullReferenceException) + { + DNAcache = ThingDefOf.Human.GetModExtension(); + } if (DNAcache == null) { - try - { - DNAcache = pawn.def.GetModExtension(); - } - catch (NullReferenceException) - { - DNAcache = ThingDefOf.Human.GetModExtension(); - } - if (DNAcache == null) - { - DNAcache = ThingDefOf.Human.GetModExtension(); - } - return DNAcache; + DNAcache = ThingDefOf.Human.GetModExtension(); } - else return DNAcache; + return DNAcache; } } protected PawnDNAModExtension DNAcache = null; @@ -130,7 +126,7 @@ namespace RJW_Menstruation { this.pawn = pawn; volume = 1.0f; - fertvolume = 1.0f; + fertility = 1.0f; } /// @@ -145,7 +141,7 @@ namespace RJW_Menstruation { this.pawn = pawn; this.volume = volume; - this.fertvolume = volume; + this.fertility = 0f; this.notcum = true; this.notcumLabel = notcumlabel; this.notcumthickness = decayresist; @@ -156,7 +152,7 @@ namespace RJW_Menstruation { this.pawn = pawn; this.volume = volume; - this.fertvolume = volume * fertility; + this.fertility = fertility; this.filthDef = filthDef; } @@ -167,9 +163,8 @@ namespace RJW_Menstruation 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 fertvolume, "fertvolume", fertvolume, true); + Scribe_Values.Look(ref fertility, "fertility", fertility, true); Scribe_Values.Look(ref notcumthickness, "notcumthickness", notcumthickness, true); - Scribe_Values.Look(ref fertFactor, "fertFactor", fertFactor, 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); @@ -183,11 +178,11 @@ namespace RJW_Menstruation cumthickness = cumthickness.LerpMultiple(DecayResist, 0.3f, speed); } - public void MergeWithCum(float volumein, float fertility, ThingDef updatefilthDef = null) + public void MergeWithCum(float volumein, float fertility, ThingDef updatefilthDef = null) { if (updatefilthDef != null) filthDef = updatefilthDef; volume += volumein; - fertvolume += volumein*fertility; + this.fertility = (this.volume * this.fertility + volumein * fertility) / (this.volume + volumein); cumthickness = Mathf.Lerp(cumthickness, 1.0f, volumein / volume); } @@ -195,12 +190,13 @@ namespace RJW_Menstruation { 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; + if ((notcum || FertVolume < 0.001f) && volume < 0.01f) return true; return false; } @@ -209,17 +205,16 @@ namespace RJW_Menstruation { float totalleak = volume; volume *= Math.Max(0, (1 - (Configurations.CumDecayRatio * (1 - DecayResist)) * leakfactor)); - fertvolume *= Math.Max(0, 1 - (Configurations.CumFertilityDecayRatio * (1 - DecayResist) + antisperm)); + 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); - fertvolume *= Math.Max(0, 1 - (portion * (1 - DecayResist)) * leakfactor); + volume *= Math.Max(0, 1 - (portion * (1 - DecayResist / 10)) * leakfactor); CutMinor(); totalleak -= volume; return totalleak; @@ -227,24 +222,20 @@ namespace RJW_Menstruation public void CumEffects(Pawn pawn) { - if (!notcum && DNA != null && volume >= 1.0f) - { - List doers = DNA.ingestionOutcomeDoers; - - if (!doers.NullOrEmpty()) for (int i = 0; i < doers.Count; i++) - { - doers[i].DoIngestionOutcome(pawn, CumThing); - } - } + if (notcum || DNA == null || volume < 1.0f) return; + + List doers = DNA.ingestionOutcomeDoers; + + if (!doers.NullOrEmpty()) for (int i = 0; i < doers.Count; i++) + { + doers[i].DoIngestionOutcome(pawn, CumThing); + } } protected void CutMinor() { if (volume < 0.01f) volume = 0f; - if (fertvolume < 0.001f) fertvolume = 0f; } - - } public class CumMixture : Cum, IDisposable @@ -259,7 +250,7 @@ namespace RJW_Menstruation cums = new List(); } - public CumMixture(Pawn pawn, float volume, List cums, Color color, ThingDef mixtureDef, bool pure) + public CumMixture(Pawn pawn, float volume, List cums, Color color, ThingDef mixtureDef, bool pure) { this.pawn = pawn; this.volume = volume; @@ -272,7 +263,7 @@ namespace RJW_Menstruation public void Dispose() { cums.Clear(); - + } public override void ExposeData() @@ -284,17 +275,12 @@ namespace RJW_Menstruation public string GetIngredients() { string res = ""; - if (!cums.NullOrEmpty()) for(int i=0; i memories = pawn.needs?.mood?.thoughts?.memories?.Memories.FindAll( - x => + x => x.def == VariousDefOf.CameInsideF || x.def == VariousDefOf.CameInsideFFetish || x.def == VariousDefOf.HaterCameInsideF); - if (!memories.NullOrEmpty()) + if (memories.NullOrEmpty()) return; + foreach (Thought_Memory m in memories) { - 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); + 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); } - } - - - } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/EstrusPartKindUsageRule.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/EstrusPartKindUsageRule.cs index bb507f3..3062feb 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/EstrusPartKindUsageRule.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/EstrusPartKindUsageRule.cs @@ -1,10 +1,10 @@ -using Verse; -using rjw; +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 { diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs index 72b5d38..4a38f7a 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs @@ -1,21 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Verse; +using HugsLib; using RimWorld; -using UnityEngine; -using HugsLib; using rjw; +using System; +using System.Collections.Generic; +using UnityEngine; +using Verse; namespace RJW_Menstruation { public class CompProperties_Breast : HediffCompProperties { public string BreastTex = "Breasts/Breast"; - public ColorInt BlacknippleColor = new ColorInt(55,20,0); - + public ColorInt BlacknippleColor = new ColorInt(55, 20, 0); + public Color BlackNippleColor { @@ -24,7 +21,7 @@ namespace RJW_Menstruation return BlacknippleColor.ToColor; } } - + public CompProperties_Breast() { @@ -174,7 +171,7 @@ namespace RJW_Menstruation Scribe_Values.Look(ref originareola, "originareola", originareola, true); Scribe_Values.Look(ref originnipple, "originnipple", originnipple, true); Scribe_Values.Look(ref pregnant, "pregnant", pregnant, true); - + } public override void CompPostTick(ref float severityAdjustment) { } @@ -187,17 +184,14 @@ namespace RJW_Menstruation public override void CompPostPostRemoved() { - - if (parent?.pawn?.GetBreastComp() == this) + if (parent.pawn.health.hediffSet.hediffs.Contains(parent)) { - Log.Warning("Something tried to remove hediff with wrong way."); - } - else - { - HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(action); - Log.Message(parent.pawn.Label + "breast tick scheduler removed"); - base.CompPostPostRemoved(); + Log.Warning($"Attempted to remove breast comp from wrong pawn ({parent.pawn})."); + return; } + HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(action); + if (Configurations.Debug) Log.Message(parent.pawn.Label + " breast tick scheduler removed"); + base.CompPostPostRemoved(); } protected long CalculateLastBirth() @@ -207,13 +201,16 @@ namespace RJW_Menstruation { foreach (Pawn child in parent.pawn.relations.Children) { - - bool isFetus; - if (PregnancyHelper.GetPregnancy(parent.pawn) is Hediff_BasePregnancy preg) + bool isFetus = false; + foreach (Hediff_BasePregnancy preg in parent.pawn.health.hediffSet.GetHediffs()) { - isFetus = preg.babies.Contains(child); + if (preg.babies.Contains(child)) + { + isFetus = true; + break; + } } - else isFetus = false; + if ( parent.pawn.ageTracker.BirthAbsTicks - child.ageTracker.BirthAbsTicks > ageOfLastBirth && !isFetus && @@ -221,7 +218,7 @@ namespace RJW_Menstruation ) youngestAge = parent.pawn.ageTracker.BirthAbsTicks - child.ageTracker.BirthAbsTicks; } - } + } return youngestAge; } @@ -234,10 +231,10 @@ namespace RJW_Menstruation { ageOfLastBirth = CalculateLastBirth(); } - + if (alphaPermanent < 0f) { - alphaPermanent = (Utility.RandGaussianLike(0.0f, 0.3f) + Rand.Range(0.0f,0.5f))/2; + alphaPermanent = (Utility.RandGaussianLike(0.0f, 0.3f) + Rand.Range(0.0f, 0.5f)) / 2; originalpha = alphaPermanent; alpha = alphaPermanent; alphaCurrent = alphaPermanent; @@ -261,7 +258,7 @@ namespace RJW_Menstruation HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(action, TICKINTERVAL, parent.pawn); } - + public void Transition() { @@ -284,7 +281,7 @@ namespace RJW_Menstruation // Scenario B: Pregnant, grow in the second half of first trimester else if (parent.pawn.IsPregnant()) { - float pregnancySize = Mathf.InverseLerp(BREAST_GROWTH_START, BREAST_GROWTH_END, parent.pawn.GetPregnancyProgress()) * MAX_BREAST_INCREMENT; + float pregnancySize = Mathf.InverseLerp(BREAST_GROWTH_START, BREAST_GROWTH_END, parent.pawn.GetFarthestPregnancyProgress()) * MAX_BREAST_INCREMENT; if (breastSizeIncreased > pregnancySize) { debugGrowthStatus = "Shrinking due to being oversize for pregnancy"; @@ -396,9 +393,9 @@ namespace RJW_Menstruation { return "Increase: " + breastSizeIncreased + "\n" + debugGrowthStatus + - "\nAlpha: " + alpha + - "\nNippleSize: " + nippleSize + - "\nAreolaSize: " + areolaSize + + "\nAlpha: " + alpha + + "\nNippleSize: " + nippleSize + + "\nAreolaSize: " + areolaSize + "\nAlphaCurrent: " + alphaCurrent + "\nNippleSizeCurrent: " + nippleSizeCurrent + "\nAreolaSizeCurrent: " + areolaSizeCurrent + @@ -408,7 +405,7 @@ namespace RJW_Menstruation "\nAlphaMax: " + MaxAlpha + "\nNippleSizeMax: " + MaxNipple + "\nAreolaSizeMax: " + MaxAreola + - "\nPermanentAlpha:" + alphaPermanent + + "\nPermanentAlpha:" + alphaPermanent + "\nPermanentNipple:" + nippleSizePermanent + "\nPermanentAreola:" + areolaSizePermanent; } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs index b457176..91be3e1 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs @@ -1,10 +1,4 @@ -using HugsLib; -using RimWorld; -using rjw; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; +using RimWorld; using Verse; namespace RJW_Menstruation @@ -36,60 +30,33 @@ namespace RJW_Menstruation } } - protected override void FollicularAction() + // The maximum theoretical rate of ovulation is inducing the moment it goes follicular and no pregnancies + // There will be far more eggs than will ever actually be produced, but it fits the induced ovulator philosophy + protected override float RaceCyclesPerYear() { - if (!IsBreedingSeason()) - { - GoNextStage(Stage.Anestrus); - return; - } - if (curStageHrs >= FollicularIntervalHours) - { - estrusflag = false; - lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor); - GoNextStage(Stage.Luteal); - } + int breedingSeasons = 0; + if (Props.breedingSeason == SeasonalBreed.Always) breedingSeasons = 4; else { - curStageHrs += Configurations.CycleAcceleration; - if (!estrusflag && curStageHrs > FollicularIntervalHours - Props.estrusDaysBeforeOvulation * 24) - { - estrusflag = true; - SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation); - } - StayCurrentStage(); + if ((Props.breedingSeason & SeasonalBreed.Spring) != 0) breedingSeasons++; + if ((Props.breedingSeason & SeasonalBreed.Summer) != 0) breedingSeasons++; + if ((Props.breedingSeason & SeasonalBreed.Fall) != 0) breedingSeasons++; + if ((Props.breedingSeason & SeasonalBreed.Winter) != 0) breedingSeasons++; } + float breedingRatio = breedingSeasons / 4.0f; + return breedingRatio * GenDate.DaysPerYear / ((float)(Props.lutealIntervalDays + Props.bleedingIntervalDays) / Configurations.CycleAccelerationDefault); } - protected override void ClimactericFollicularAction() + // 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) { - if (!Configurations.EnableMenopause) - { - RemoveClimactericEffect(); - StayCurrentStage(); - } - else if (curStageHrs >= (follicularIntervalhours - bleedingIntervalhours) * CycleFactor) - { - estrusflag = false; - lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor); - GoNextStage(Stage.ClimactericLuteal); - } - else if (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.2f) // Might randomly skip to luteal early) - { - estrusflag = false; - lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor * 6); - GoNextStage(Stage.ClimactericLuteal); - } - else - { - curStageHrs += Configurations.CycleAcceleration; - if (!estrusflag && curStageHrs > FollicularIntervalHours - Props.estrusDaysBeforeOvulation * 24) - { - estrusflag = true; - SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation); - } - StayCurrentStage(); - } + return 0; + } + + protected override void GoOvulatoryStage(bool climacteric) + { + estrusflag = false; + GoNextStage(climacteric ? Stage.ClimactericLuteal : Stage.Luteal); } protected override void AfterCumIn(Pawn cummer) @@ -99,7 +66,7 @@ namespace RJW_Menstruation { case Stage.Follicular: case Stage.ClimactericFollicular: - curStage = Stage.Ovulatory; + GoNextStage(Stage.Ovulatory); break; } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs index 9fb5bfb..a4e75af 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs @@ -27,8 +27,7 @@ namespace RJW_Menstruation public float maxCumCapacity; // ml public float baseImplantationChanceFactor; public float basefertilizationChanceFactor; - public float deviationFactor; - public int folicularIntervalDays = 14; //before ovulation including beginning of bleeding + public int follicularIntervalDays = 14; //before ovulation including beginning of bleeding public int lutealIntervalDays = 14; //after ovulation until bleeding public int bleedingIntervalDays = 6; //must be less than folicularIntervalDays public int recoveryIntervalDays = 10; //additional infertile days after gave birth @@ -36,7 +35,6 @@ namespace RJW_Menstruation public string wombTex = "Womb/Womb"; //fertiledays = ovaluationday - spermlifespan ~ ovaluationday + egglifespanday public string vagTex = "Genitals/Vagina"; //fertiledays = ovaluationday - spermlifespan ~ ovaluationday + egglifespanday public bool infertile = false; - public int ovaryPower = 600000000; // default: almost unlimited ovulation public bool concealedEstrus = false; public SeasonalBreed breedingSeason = SeasonalBreed.Always; public int estrusDaysBeforeOvulation = 3; @@ -65,7 +63,10 @@ namespace RJW_Menstruation const float minmakefilthvalue = 1.0f; //const int ovarypowerthreshold = 72; - public const int tickInterval = GenDate.TicksPerHour; + const int tickInterval = GenDate.TicksPerHour; + const int maxImplantDelayHours = 30 * 24; + const int minImplantAgeHours = 3 * 24; + public CompProperties_Menstruation Props; public Stage curStage = Stage.Follicular; public int curStageHrs = 0; @@ -81,7 +82,6 @@ namespace RJW_Menstruation Ovulatory, Luteal, Bleeding, - Fertilized, //Obsoleted Pregnant, Recover, None, @@ -107,11 +107,9 @@ namespace RJW_Menstruation protected List cums; protected List eggs; - protected int follicularIntervalhours = -1; - protected int lutealIntervalhours = -1; - protected int bleedingIntervalhours = -1; - protected int recoveryIntervalhours = -1; - protected int currentIntervalhours = -1; + protected float cycleSpeed = -1; + protected float cycleVariability = -1; + protected int currentIntervalHours = -1; protected float crampPain = -1; protected Need sexNeed = null; protected string customwombtex = null; @@ -121,6 +119,21 @@ namespace RJW_Menstruation protected HediffComp_Breast breastcache = null; protected float antisperm = 0.0f; protected float? originvagsize = null; + protected Hediff_BasePregnancy pregnancy = null; + + public Hediff_BasePregnancy Pregnancy { + get + { + if (pregnancy == null) return null; + else if (!parent.pawn.health.hediffSet.hediffs.Contains(pregnancy)) + { + pregnancy = null; + return null; + } + else return pregnancy; + } + set => pregnancy = value; + } public int OvaryPowerThreshold { @@ -131,51 +144,28 @@ namespace RJW_Menstruation } } - public int FollicularIntervalHours - { - get - { - return (int)((follicularIntervalhours - bleedingIntervalhours) * CycleFactor); - } - } - public float TotalCum { get { - float res = 0; if (cums.NullOrEmpty()) return 0; - foreach (Cum cum in cums) - { - res += cum.Volume; - } - return res; + return cums.Sum(cum => cum.Volume); } } public float TotalFertCum { get { - float res = 0; if (cums.NullOrEmpty()) return 0; - foreach (Cum cum in cums) - { - if (!cum.notcum) res += cum.FertVolume; - } - return res; + return cums.Sum(cum => cum.FertVolume); } } public float TotalCumPercent { get { - float res = 0; if (cums.NullOrEmpty()) return 0; - foreach (Cum cum in cums) - { - res += cum.Volume; - } - return res / Props.maxCumCapacity; + return cums.Sum(cum => cum.Volume) / Props.maxCumCapacity; } } public float CumCapacity @@ -183,16 +173,7 @@ namespace RJW_Menstruation get { float res = Props.maxCumCapacity * parent.pawn.BodySize; - if (curStage != Stage.Pregnant || (parent.pawn.GetRJWPregnancy()?.Severity ?? 0f) < 0.175f) res *= 500f; - return res; - } - } - public float CumInFactor - { - get - { - float res = 1.0f; - if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) res = 0.01f; + if (curStage != Stage.Pregnant || (pregnancy?.Severity ?? 0f) < 0.175f) res *= 500f; return res; } } @@ -220,12 +201,12 @@ namespace RJW_Menstruation { get { - if (!cums.NullOrEmpty()) foreach (Cum cum in cums) + if (cums.NullOrEmpty()) yield return Translations.Info_noCum; + else foreach (Cum cum in cums) { if (!cum.notcum) yield return String.Format(cum.pawn?.Label + ": {0:0.##}ml", cum.Volume); else yield return String.Format(cum.notcumLabel + ": {0:0.##}ml", cum.Volume); } - else yield return Translations.Info_noCum; } } public Color GetCumMixtureColor @@ -234,16 +215,15 @@ namespace RJW_Menstruation { Color mixedcolor = Color.white; - if (!cums.NullOrEmpty()) + if (cums.NullOrEmpty()) return mixedcolor; + + float mixedsofar = 0; + foreach (Cum cum in cums) { - float mixedsofar = 0; - foreach (Cum cum in cums) + if (cum.Volume > 0) { - if (cum.Volume > 0) - { - mixedcolor = Colors.CMYKLerp(mixedcolor, cum.Color, cum.Volume / (mixedsofar + cum.Volume)); - mixedsofar += cum.Volume; - } + mixedcolor = Colors.CMYKLerp(mixedcolor, cum.Color, cum.Volume / (mixedsofar + cum.Volume)); + mixedsofar += cum.Volume; } } return mixedcolor; @@ -256,7 +236,7 @@ namespace RJW_Menstruation { if (curStage == Stage.Pregnant) { - if (Configurations.InfoDetail == Configurations.DetailLevel.All || (PregnancyHelper.GetPregnancy(parent.pawn)?.Visible ?? false)) + if (Configurations.InfoDetail == Configurations.DetailLevel.All || (pregnancy?.Visible ?? false)) return Stage.Pregnant; else return Stage.Luteal; @@ -279,8 +259,6 @@ namespace RJW_Menstruation return Translations.Stage_Luteal; case Stage.Bleeding: return Translations.Stage_Bleeding; - case Stage.Fertilized: - return Translations.Stage_Fertilized; case Stage.Pregnant: return Translations.Stage_Pregnant; case Stage.Recover: @@ -304,7 +282,7 @@ namespace RJW_Menstruation } public virtual string GetCurStageDesc { - get + get { switch (CurrentVisibleStage) { @@ -316,14 +294,12 @@ namespace RJW_Menstruation return Translations.Stage_Luteal_Desc; case Stage.Bleeding: return Translations.Stage_Bleeding_Desc; - case Stage.Fertilized: - return Translations.Stage_Luteal_Desc; case Stage.Pregnant: return Translations.Stage_Pregnant_Desc; case Stage.Recover: return Translations.Stage_Recover_Desc; case Stage.None: - case Stage.Young: + case Stage.Young: return Translations.Stage_None_Desc; case Stage.ClimactericFollicular: return Translations.Stage_Follicular_Desc + " " + Translations.Stage_Climacteric_Desc; @@ -367,24 +343,23 @@ namespace RJW_Menstruation { get { + if (eggs.NullOrEmpty()) return ""; + string res = ""; - if (!eggs.NullOrEmpty()) + int fertilized = 0; + foreach (Egg egg in eggs) { - int fertilized = 0; - foreach (Egg egg in eggs) - { - if (egg.fertilized) fertilized++; - } - if (fertilized != 0) res += fertilized + " " + Translations.Dialog_WombInfo05; - if (fertilized != 0 && eggs.Count - fertilized != 0) res += ", "; - if (cums.NullOrEmpty() || TotalFertCum == 0) - { - if (eggs.Count - fertilized != 0) res += eggs.Count - fertilized + " " + Translations.Dialog_WombInfo07; - } - else - { - if (eggs.Count - fertilized != 0) res += eggs.Count - fertilized + " " + Translations.Dialog_WombInfo06; - } + if (egg.fertilized) fertilized++; + } + if (fertilized != 0) res += fertilized + " " + Translations.Dialog_WombInfo05; + if (fertilized != 0 && eggs.Count - fertilized != 0) res += ", "; + if (cums.NullOrEmpty() || TotalFertCum == 0) + { + if (eggs.Count - fertilized != 0) res += eggs.Count - fertilized + " " + Translations.Dialog_WombInfo07; + } + else + { + if (eggs.Count - fertilized != 0) res += eggs.Count - fertilized + " " + Translations.Dialog_WombInfo06; } return res; } @@ -393,16 +368,8 @@ namespace RJW_Menstruation { get { - if (!eggs.NullOrEmpty()) - { - if (!cums.NullOrEmpty()) foreach (Cum cum in cums) - { - if (cum.FertVolume > 0) return true; - } - return false; - - } - else return false; + if (eggs.NullOrEmpty() || cums.NullOrEmpty()) return false; + return cums.Any(cum => cum.FertVolume > 0); } } /// @@ -445,7 +412,7 @@ namespace RJW_Menstruation { case Stage.Follicular: case Stage.ClimactericFollicular: - return curStageHrs > 0.7f * (follicularIntervalhours - bleedingIntervalhours); + return curStageHrs > 0.7f * currentIntervalHours; case Stage.Ovulatory: return true; case Stage.Luteal: @@ -512,24 +479,7 @@ namespace RJW_Menstruation { get { - switch (curStage) - { - case Stage.Follicular: - case Stage.ClimactericFollicular: - return FollicularIntervalHours; - case Stage.Luteal: - case Stage.ClimactericLuteal: - return lutealIntervalhours; - case Stage.Bleeding: - case Stage.ClimactericBleeding: - return bleedingIntervalhours; - case Stage.Recover: - return recoveryIntervalhours; - case Stage.Pregnant: - return currentIntervalhours; - default: - return float.PositiveInfinity; - } + return currentIntervalHours; } } @@ -557,17 +507,16 @@ namespace RJW_Menstruation Scribe_Collections.Look(ref eggs, saveDestroyedThings: true, label: "eggs", lookMode: LookMode.Deep, ctorArgs: new object[0]); Scribe_Values.Look(ref curStage, "curStage", curStage, true); Scribe_Values.Look(ref curStageHrs, "curStageHrs", curStageHrs, true); - Scribe_Values.Look(ref follicularIntervalhours, "follicularIntervalhours", follicularIntervalhours, true); - Scribe_Values.Look(ref lutealIntervalhours, "lutealIntervalhours", lutealIntervalhours, true); - Scribe_Values.Look(ref bleedingIntervalhours, "bleedingIntervalhours", bleedingIntervalhours, true); - Scribe_Values.Look(ref recoveryIntervalhours, "recoveryIntervalhours", recoveryIntervalhours, true); - Scribe_Values.Look(ref currentIntervalhours, "currentIntervalhours", currentIntervalhours, true); + Scribe_Values.Look(ref cycleSpeed, "cycleSpeed", cycleSpeed, true); + Scribe_Values.Look(ref cycleVariability, "cycleVariability", cycleVariability, true); + Scribe_Values.Look(ref currentIntervalHours, "currentIntervalHours", currentIntervalHours, true); Scribe_Values.Look(ref crampPain, "crampPain", crampPain, true); Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true); Scribe_Values.Look(ref eggstack, "eggstack", eggstack, true); Scribe_Values.Look(ref estrusflag, "estrusflag", estrusflag, true); Scribe_Values.Look(ref originvagsize, "originvagsize", originvagsize, true); Scribe_Values.Look(ref DoCleanWomb, "DoCleanWomb", DoCleanWomb, true); + Scribe_References.Look(ref pregnancy, "pregnancy"); } @@ -590,22 +539,19 @@ namespace RJW_Menstruation public override void CompPostPostRemoved() { - if (parent?.pawn?.GetMenstruationComp() == this) + // If a hediff is removed from a pawn that does not have it, CompPostPostRemoved is still called on the pawn that does. + // If it was a legitimate removal, then it won't be in this pawn's hediff list anymore, as that removal occurs first + if (parent.pawn.health.hediffSet.hediffs.Contains(parent)) { - Log.Warning("Something tried to remove hediff with wrong way."); - } - else - { - HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(actionref); - Log.Message(parent.pawn.Label + "tick scheduler removed"); - base.CompPostPostRemoved(); + Log.Warning($"Attempted to remove menstruation comp from wrong pawn ({parent.pawn})."); + return; } + HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(actionref); + if (Configurations.Debug) Log.Message(parent.pawn.Label + " menstruation tick scheduler removed"); + pregnancy?.Miscarry(); + base.CompPostPostRemoved(); } - - - - /// /// Get fluid in womb that not a cum /// @@ -627,24 +573,21 @@ namespace RJW_Menstruation /// public Cum GetCum(Pawn pawn) { - if (!cums.NullOrEmpty()) foreach (Cum cum in cums) - { - if (!cum.notcum && cum.pawn.Equals(pawn)) return cum; - } - return null; + if (cums.NullOrEmpty()) return null; + return cums.Find(cum => !cum.notcum && cum.pawn == pawn); } /// /// Inject pawn's cum into womb /// /// - /// + /// /// /// - public void CumIn(Pawn pawn, float injectedvolume, float fertility = 1.0f, ThingDef filthdef = null) + public void CumIn(Pawn pawn, float volume, float fertility = 1.0f, ThingDef filthdef = null) { - float volume = injectedvolume * CumInFactor; if (volume <= 0) return; + if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) fertility /= 100f; float cumd = TotalCumPercent; float tmp = TotalCum + volume; if (tmp > CumCapacity) @@ -678,7 +621,7 @@ namespace RJW_Menstruation } cumd = TotalCumPercent - cumd; - parent.pawn.records.AddTo(VariousDefOf.AmountofCreampied, injectedvolume); + parent.pawn.records.AddTo(VariousDefOf.AmountofCreampied, volume); AfterCumIn(pawn); AfterFluidIn(cumd); } @@ -733,7 +676,7 @@ namespace RJW_Menstruation protected virtual void AfterCumIn(Pawn cummer) { ThoughtCumInside(cummer); - + TaleCumInside(cummer); } protected virtual void AfterNotCumIn() @@ -868,7 +811,7 @@ namespace RJW_Menstruation /// /// /// - public CumMixture MixtureOut(ThingDef mixtureDef ,float portion = 0.1f) + public CumMixture MixtureOut(ThingDef mixtureDef, float portion = 0.1f) { if (cums.NullOrEmpty()) return null; Color color = GetCumMixtureColor; @@ -902,121 +845,135 @@ namespace RJW_Menstruation cums.Clear(); } - + /// /// Fertilize eggs and return the result /// /// - protected bool FertilizationCheck() + protected void FertilizationCheck() { - if (!eggs.NullOrEmpty()) + if (eggs.NullOrEmpty()) return; + foreach (Egg egg in eggs) { - bool onefertilized = false; - foreach (Egg egg in eggs) + if (!egg.fertilized) egg.fertilizer = Fertilize(); + if (egg.fertilizer != null) { - if (!egg.fertilized) egg.fertilizer = Fertilize(); - if (egg.fertilizer != null) - { - egg.fertilized = true; - egg.lifespanhrs += 240; - onefertilized = true; - } + egg.fertilized = true; } - return onefertilized; } - else return false; } public void Initialize() { Props = (CompProperties_Menstruation)props; - if (!Props.infertile) - { - if (follicularIntervalhours < 0) - { - follicularIntervalhours = PeriodRandomizer(Props.folicularIntervalDays * 24, Props.deviationFactor); - if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young; - else if (!IsBreedingSeason()) curStage = Stage.Anestrus; - else curStage = RandomStage(); - } - - if (lutealIntervalhours < 0) lutealIntervalhours = PeriodRandomizer(Props.lutealIntervalDays * 24, Props.deviationFactor); - if (bleedingIntervalhours < 0) bleedingIntervalhours = PeriodRandomizer(Props.bleedingIntervalDays * 24, Props.deviationFactor); - if (recoveryIntervalhours < 0) recoveryIntervalhours = PeriodRandomizer(Props.recoveryIntervalDays * 24, Props.deviationFactor); - if (crampPain < 0) crampPain = PainRandomizer(); - if (cums == null) cums = new List(); - if (eggs == null) eggs = new List(); - - - InitOvary(); - - Hediff_BasePregnancy pregnancy = parent.pawn.GetRJWPregnancy(); - if (pregnancy != null) - { - Hediff hediff = PregnancyHelper.GetPregnancy(parent.pawn); - if (hediff != null) - { - if (hediff is Hediff_BasePregnancy preg) - { - currentIntervalhours = (int)(preg.GestationHours()); - curStage = Stage.Pregnant; - } - } - } - - if (parent.pawn.IsAnimal()) - { - if (Configurations.EnableAnimalCycle) - { - HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false); - } - } - else - { - if (pregnancy == null && parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Young), GetNextUpdate(), parent.pawn, false); - else HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false); - } - } - else + if (Props.infertile) { if (cums == null) cums = new List(); curStage = Stage.None; HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false); + loaded = true; + return; + } + + if (cycleSpeed < 0f) cycleSpeed = Utility.RandGaussianLike(0.8f, 1.2f); + if (cycleVariability < 0f) cycleVariability = MenstruationUtility.RandomVariabilityPercent(); + if (currentIntervalHours < 0) + { + if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young; + else if (!IsBreedingSeason()) curStage = Stage.Anestrus; + else curStage = RandomStage(); + if (curStage == Stage.Follicular) + currentIntervalHours = PeriodRandomizer(Stage.Follicular) - PeriodRandomizer(Stage.Bleeding); + else + currentIntervalHours = PeriodRandomizer(curStage); + if (currentIntervalHours <= 0) currentIntervalHours = 1; + else if (currentIntervalHours < curStageHrs) curStageHrs = currentIntervalHours; + } + if (crampPain < 0) crampPain = PainRandomizer(); + if (cums == null) cums = new List(); + if (eggs == null) eggs = new List(); + + + InitOvary(); + + if (pregnancy == null) + { + // If this womb isn't marked pregnant, search for pregnancies that have no womb and claim one + foreach (Hediff_BasePregnancy preg in parent.pawn.health.hediffSet.GetHediffs()) + { + if (preg.GetMenstruationComp() == null) + { + currentIntervalHours = (int)preg.GestationHours(); + curStage = Stage.Pregnant; + pregnancy = preg; + break; + } + } + } + + if (parent.pawn.IsAnimal()) + { + if (Configurations.EnableAnimalCycle) + { + HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false); + } + } + else + { + if (pregnancy == null && parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Young), GetNextUpdate(), parent.pawn, false); + else HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false); } //Log.Message(parent.pawn.Label + " - Initialized menstruation comp"); loaded = true; } - public int GetOvaryPowerByAge(Pawn pawn) + protected virtual float RaceCyclesPerYear() { - int power; + int breedingSeasons = 0; + if (Props.breedingSeason == SeasonalBreed.Always) breedingSeasons = 4; + else + { + if ((Props.breedingSeason & SeasonalBreed.Spring) != 0) breedingSeasons++; + if ((Props.breedingSeason & SeasonalBreed.Summer) != 0) breedingSeasons++; + if ((Props.breedingSeason & SeasonalBreed.Fall) != 0) breedingSeasons++; + if ((Props.breedingSeason & SeasonalBreed.Winter) != 0) breedingSeasons++; + } + float breedingRatio = breedingSeasons / 4.0f; + return breedingRatio * GenDate.DaysPerYear / ((float)(Props.follicularIntervalDays + Props.lutealIntervalDays) / Configurations.CycleAccelerationDefault); + } + + protected virtual int PawnEggsUsed(float pawnCyclesElapsed, float avglittersize) + { + return (int)(pawnCyclesElapsed * avglittersize); + } + + public int GetOvaryPowerByAge() + { + Pawn pawn = parent.pawn; float avglittersize; try { - if (pawn.def.race.litterSizeCurve.Points.Count < 3) avglittersize = 1; // Account for busted littersizecurves - else avglittersize = Rand.ByCurveAverage(pawn.def.race.litterSizeCurve); + avglittersize = Mathf.Max(Rand.ByCurveAverage(pawn.def.race.litterSizeCurve), 1.0f); } catch (NullReferenceException) { - avglittersize = 1; + avglittersize = 1.0f; } - //Old one. Sex minimum age based. - //ovarypower = (int)(((Props.ovaryPower * Utility.RandGaussianLike(0.70f, 1.30f) * parent.pawn.def.race.lifeExpectancy / ThingDefOf.Human.race.lifeExpectancy) - // - (Math.Max(0, ageYear - RJWSettings.sex_minimum_age * parent.pawn.def.race.lifeExpectancy / ThingDefOf.Human.race.lifeExpectancy)) - // * (60 / (Props.folicularIntervalDays + Props.lutealIntervalDays) * Configurations.CycleAcceleration)) * avglittersize); + float fertStartAge = pawn.RaceProps.lifeStageAges?.Find(stage => stage.def.reproductive)?.minAge ?? 0.0f; + float fertEndAge = pawn.RaceProps.lifeExpectancy * (pawn.IsAnimal() ? RJWPregnancySettings.fertility_endage_female_animal : RJWPregnancySettings.fertility_endage_female_humanlike); + if (fertEndAge < fertStartAge) fertEndAge = fertStartAge; - //New one. - float fertendage, lifenormalized; - if (pawn.IsAnimal()) fertendage = RJWPregnancySettings.fertility_endage_female_animal * 100f; - else fertendage = RJWPregnancySettings.fertility_endage_female_humanlike * 80f; - lifenormalized = pawn.def.race.lifeExpectancy / ThingDefOf.Human.race.lifeExpectancy; - fertendage *= lifenormalized; - power = (int)((fertendage - pawn.ageTracker.AgeBiologicalYearsFloat) * (60f / (Props.folicularIntervalDays + Props.lutealIntervalDays) * Configurations.CycleAcceleration) * avglittersize); - power = (int)Mathf.Max(0, Mathf.Min(Props.ovaryPower * Utility.RandGaussianLike(0.70f, 1.30f, 5) * lifenormalized, power)); + float raceCyclesPerYear = RaceCyclesPerYear(); + int lifetimeCycles = (int)(raceCyclesPerYear * (fertEndAge - fertStartAge)); + int lifetimeEggs = (int)(lifetimeCycles * avglittersize * Utility.RandGaussianLike(0.70f, 1.30f, 5)); - return power; + float pawnCyclesPerYear = raceCyclesPerYear * cycleSpeed; + float pawnCyclesElapsed = Mathf.Max((pawn.ageTracker.AgeBiologicalYearsFloat - fertStartAge) * pawnCyclesPerYear, 0.0f); + int pawnEggsUsed = PawnEggsUsed(pawnCyclesElapsed, avglittersize); + + return Math.Max(lifetimeEggs - pawnEggsUsed, 0); } protected void InitOvary() @@ -1027,24 +984,19 @@ namespace RJW_Menstruation } else if (ovarypower < -50000) { - if (Props.ovaryPower > 10000000) ovarypower = Props.ovaryPower; - else + ovarypower = GetOvaryPowerByAge(); + if (ovarypower < 1) { - ovarypower = GetOvaryPowerByAge(parent.pawn); - if (ovarypower < 1) - { - Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Menopause, parent.pawn); - hediff.Severity = 0.2f; - parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); - curStage = Stage.Young; - } - else if (ovarypower < OvaryPowerThreshold) - { - Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn); - hediff.Severity = 0.008f * (OvaryPowerThreshold - ovarypower); - parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); - } - + Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Menopause, parent.pawn); + hediff.Severity = 0.2f; + parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); + curStage = Stage.Young; + } + else if (ovarypower < OvaryPowerThreshold) + { + Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn); + hediff.Severity = 0.008f * (OvaryPowerThreshold - ovarypower); + parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); } } } @@ -1074,14 +1026,25 @@ namespace RJW_Menstruation public void SetEstrus(int days) { HediffDef estrusdef = Props.concealedEstrus ? VariousDefOf.Hediff_Estrus_Concealed : VariousDefOf.Hediff_Estrus; - HediffWithComps hediff = (HediffWithComps)parent.pawn.health.hediffSet.GetFirstHediffOfDef(estrusdef); + Hediff hediff = parent.pawn.health.hediffSet.GetFirstHediffOfDef(estrusdef); + + if (Props.concealedEstrus) + { + if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.Hediff_Estrus)) return; + } + else + { + Hediff concealedHediff = parent.pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_Estrus_Concealed); + if (concealedHediff != null) parent.pawn.health.RemoveHediff(concealedHediff); + } + if (hediff != null) { hediff.Severity = (float)days / Configurations.CycleAcceleration + 0.2f; } else { - hediff = (HediffWithComps)HediffMaker.MakeHediff(estrusdef, parent.pawn); + hediff = HediffMaker.MakeHediff(estrusdef, parent.pawn); hediff.Severity = (float)days / Configurations.CycleAcceleration + 0.2f; parent.pawn.health.AddHediff(hediff); } @@ -1091,8 +1054,8 @@ namespace RJW_Menstruation { if (Props.breedingSeason == SeasonalBreed.Always) return true; Map map = parent.pawn.Map; - if (map is null) map = Find.AnyPlayerHomeMap; - if (map is null) return true; + if (map == null) map = Find.AnyPlayerHomeMap; + if (map == null) return true; switch (GenLocalDate.Season(map)) { case Season.Spring: @@ -1116,11 +1079,9 @@ namespace RJW_Menstruation List eligibleCum = cums.FindAll(cum => !cum.notcum && cum.FertVolume > 0 && cum.pawn != null && (RJWPregnancySettings.bestial_pregnancy_enabled || xxx.is_animal(parent.pawn) == xxx.is_animal(cum.pawn))); if (eligibleCum.Count == 0) return null; - float totalFertPower = 0; - foreach (Cum cum in eligibleCum) - totalFertPower += cum.FertVolume; - - if (Rand.Range(0.0f, 1.0f) > totalFertPower * Configurations.FertilizeChance * Props.basefertilizationChanceFactor) + float totalFertPower = eligibleCum.Sum(cum => cum.FertVolume); + + if (Rand.Range(0.0f, 1.0f) > 1.0f - Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor)) return null; parent.pawn.records.AddTo(VariousDefOf.AmountofFertilizedEggs, 1); @@ -1133,101 +1094,90 @@ namespace RJW_Menstruation } // We shouldn't reach here, but floating point errors exist, so just to be sure, select whomever came the most - - float mostCum = 0; - Pawn mostCummer = null; - - foreach (Cum cum in eligibleCum) - { - if(cum.FertVolume > mostCum) - { - mostCum = cum.FertVolume; - mostCummer = cum.pawn; - } - } - - return mostCummer; + return eligibleCum.MaxBy(cum => cum.FertVolume).pawn; } - + protected bool Implant() { - if (!eggs.NullOrEmpty()) + if (eggs.NullOrEmpty()) return false; + + List deadeggs = new List(); + bool pregnant = false; + foreach (Egg egg in eggs) { - List deadeggs = new List(); - bool pregnant = false; - foreach (Egg egg in eggs) + if (!egg.fertilized || + egg.fertstage < minImplantAgeHours || + egg.position < Math.Min(Props.lutealIntervalDays * 24 / 2, maxImplantDelayHours)) + continue; + else if (egg.fertilizer == null) { - if (!egg.fertilized || egg.fertstage < 168) continue; - else if (egg.fertilizer is null) + deadeggs.Add(egg); + continue; + } + else if (parent.pawn.health.hediffSet.GetHediffs().Any() || pregnancy is Hediff_MechanoidPregnancy) + { + deadeggs.Add(egg); + continue; + } + else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * ImplantFactor * InterspeciesImplantFactor(egg.fertilizer)) + { + if (pregnancy != null) { - deadeggs.Add(egg); - continue; - } - else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * ImplantFactor * InterspeciesImplantFactor(egg.fertilizer)) - { - Hediff_BasePregnancy pregnancy = parent.pawn.GetRJWPregnancy(); - if (pregnancy != null) + if (Configurations.UseMultiplePregnancy && Configurations.EnableHeteroOvularTwins) { - if (Configurations.UseMultiplePregnancy && Configurations.EnableHeteroOvularTwins) + if (pregnancy is Hediff_MultiplePregnancy h) { - if (pregnancy is Hediff_MultiplePregnancy h) - { - h.AddNewBaby(parent.pawn, egg.fertilizer); - } - pregnant = true; - deadeggs.Add(egg); + h.AddNewBaby(parent.pawn, egg.fertilizer); } - else - { - pregnant = true; - break; - } - - + pregnant = true; + deadeggs.Add(egg); } else { - if (!Configurations.UseMultiplePregnancy) - { - PregnancyHelper.PregnancyDecider(parent.pawn, egg.fertilizer); - Hediff_BasePregnancy hediff = (Hediff_BasePregnancy)PregnancyHelper.GetPregnancy(parent.pawn); - currentIntervalhours = (int)hediff?.GestationHours(); - pregnant = true; - break; - } - else - { - Hediff_BasePregnancy.Create(parent.pawn, egg.fertilizer); - Hediff_BasePregnancy hediff = (Hediff_BasePregnancy)PregnancyHelper.GetPregnancy(parent.pawn); - currentIntervalhours = (int)hediff?.GestationHours(); - - pregnant = true; - deadeggs.Add(egg); - } + pregnant = true; + break; } - } - else deadeggs.Add(egg); - } - - if (pregnant && (!Configurations.UseMultiplePregnancy || !Configurations.EnableHeteroOvularTwins)) - { - eggs.Clear(); - deadeggs.Clear(); - return true; - } - else if (!deadeggs.NullOrEmpty()) - { - foreach (Egg egg in deadeggs) + else { - eggs.Remove(egg); + if (!Configurations.UseMultiplePregnancy) + { + PregnancyHelper.PregnancyDecider(parent.pawn, egg.fertilizer); + // I hate having to do this, but it gets the newest pregnancy + pregnancy = parent.pawn.health.hediffSet.GetHediffs().MaxBy(hediff => hediff.loadID); + currentIntervalHours = (int)pregnancy?.GestationHours(); + pregnant = true; + break; + } + else + { + pregnancy = Hediff_BasePregnancy.Create(parent.pawn, egg.fertilizer); + currentIntervalHours = (int)pregnancy?.GestationHours(); + pregnant = true; + deadeggs.Add(egg); + } } - deadeggs.Clear(); + } - if (pregnant) return true; + else deadeggs.Add(egg); } - return false; + + if (pregnant && (!Configurations.UseMultiplePregnancy || !Configurations.EnableHeteroOvularTwins)) + { + eggs.Clear(); + deadeggs.Clear(); + return true; + } + else if (!deadeggs.NullOrEmpty()) + { + foreach (Egg egg in deadeggs) + { + eggs.Remove(egg); + } + deadeggs.Clear(); + } + return pregnant; } protected void BleedOut() @@ -1258,32 +1208,26 @@ namespace RJW_Menstruation protected float AbsorbCum(float amount, Absorber absorber) { - if (absorber != null) - { - float absorbable = absorber.GetStatValue(VariousDefOf.MaxAbsorbable); - absorber.SetColor(Colors.CMYKLerp(GetCumMixtureColor, absorber.DrawColor, 1f - amount / absorbable)); - if (!absorber.dirty) - { - absorber.absorbedfluids += amount; - if (absorber.absorbedfluids > absorbable && !parent.pawn.apparel.IsLocked(absorber)) - { - absorber.def = absorber.DirtyDef; - //absorber.fluidColor = GetCumMixtureColor; - absorber.dirty = true; - } - } - else - { - - //if (absorber.LeakAfterDirty) FilthMaker.TryMakeFilth(parent.pawn.Position, parent.pawn.Map, cum.FilthDef, cum.pawn.LabelShort); - return amount; - } - } - else + if (absorber == null) { //if (amount >= minmakefilthvalue) FilthMaker.TryMakeFilth(parent.pawn.Position, parent.pawn.Map, cum.FilthDef, cum.pawn.LabelShort); return amount; } + + float absorbable = absorber.GetStatValue(VariousDefOf.MaxAbsorbable); + absorber.SetColor(Colors.CMYKLerp(GetCumMixtureColor, absorber.DrawColor, 1f - amount / absorbable)); + if (absorber.dirty) + { + //if (absorber.LeakAfterDirty) FilthMaker.TryMakeFilth(parent.pawn.Position, parent.pawn.Map, cum.FilthDef, cum.pawn.LabelShort); + return amount; + } + absorber.absorbedfluids += amount; + if (absorber.absorbedfluids > absorbable && !parent.pawn.apparel.IsLocked(absorber)) + { + absorber.def = absorber.DirtyDef; + //absorber.fluidColor = GetCumMixtureColor; + absorber.dirty = true; + } return 0; } @@ -1305,10 +1249,13 @@ namespace RJW_Menstruation List deadeggs = new List(); foreach (Egg egg in eggs) { - egg.lifespanhrs -= Configurations.CycleAcceleration; egg.position += Configurations.CycleAcceleration; - if (egg.lifespanhrs < 0) deadeggs.Add(egg); if (egg.fertilized) egg.fertstage += Configurations.CycleAcceleration; + else + { + egg.lifespanhrs -= Configurations.CycleAcceleration; + if (egg.lifespanhrs < 0) deadeggs.Add(egg); + } } if (!deadeggs.NullOrEmpty()) { @@ -1325,25 +1272,36 @@ namespace RJW_Menstruation Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_MenstrualCramp, parent.pawn); hediff.Severity = crampPain * Rand.Range(0.9f, 1.1f); HediffCompProperties_SeverityPerDay Prop = (HediffCompProperties_SeverityPerDay)hediff.TryGetComp().props; - Prop.severityPerDay = -hediff.Severity / (bleedingIntervalhours / 24) * Configurations.CycleAcceleration; + Prop.severityPerDay = -hediff.Severity / (currentIntervalHours / 24) * Configurations.CycleAcceleration; parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); } - protected virtual void FollicularAction() + protected virtual void FollicularAction(bool climacteric) { - if (!IsBreedingSeason()) + if (climacteric && !Configurations.EnableMenopause) { + RemoveClimactericEffect(); + StayCurrentStage(); + } + else if (!IsBreedingSeason()) + { + estrusflag = false; GoNextStage(Stage.Anestrus); return; } - if (curStageHrs >= FollicularIntervalHours) + else if (curStageHrs >= currentIntervalHours) { - GoNextStage(Stage.Ovulatory); + GoOvulatoryStage(climacteric); + } + else if (climacteric && ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.2f) //skips ovulatory + { + estrusflag = false; + GoNextStage(Stage.ClimactericLuteal); } else { curStageHrs += Configurations.CycleAcceleration; - if (!estrusflag && curStageHrs > FollicularIntervalHours - Props.estrusDaysBeforeOvulation * 24) + if (!estrusflag && curStageHrs > currentIntervalHours - Props.estrusDaysBeforeOvulation * 24) { estrusflag = true; SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation); @@ -1359,17 +1317,18 @@ namespace RJW_Menstruation float eggnum; try { - eggnum = Rand.ByCurve(parent.pawn.RaceProps.litterSizeCurve) + eggstack; + eggnum = Rand.ByCurve(parent.pawn.RaceProps.litterSizeCurve); } - catch(NullReferenceException) + catch (NullReferenceException) { - eggnum = 1 + eggstack; + eggnum = 1; } - catch(ArgumentException e) + catch (ArgumentException e) { Log.Warning($"Invalid litterSizeCurve for {parent.pawn.RaceProps}: {e}"); - eggnum = 1 + eggstack; + eggnum = 1; } + eggnum += eggstack; do { @@ -1394,19 +1353,42 @@ namespace RJW_Menstruation Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn); hediff.Severity = 0.008f * i; parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); - lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor * 6); GoNextStage(Stage.ClimactericLuteal); } else { - lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor); GoNextStage(Stage.Luteal); } } - protected virtual void LutealAction() + protected virtual void LutealAction(bool climacteric) { - if (!eggs.NullOrEmpty()) + if (climacteric && !Configurations.EnableMenopause) + { + RemoveClimactericEffect(); + StayCurrentStage(); + } + else if (curStageHrs > currentIntervalHours) + { + eggs.Clear(); + if (Props.bleedingIntervalDays == 0) + { + GoNextStage(climacteric ? Stage.ClimactericFollicular : Stage.Follicular); + } + else if (climacteric && (ovarypower < OvaryPowerThreshold / 4 || (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.3f))) //skips bleeding + { + GoNextStage(Stage.ClimactericFollicular); + } + else + { + if (crampPain >= 0.05f) + { + AddCrampPain(); + } + GoNextStage(climacteric ? Stage.ClimactericBleeding : Stage.Bleeding); + } + } + else if (!eggs.NullOrEmpty()) { FertilizationCheck(); EggDecay(); @@ -1424,43 +1406,37 @@ namespace RJW_Menstruation StayCurrentStage(); } } - else if (curStageHrs <= lutealIntervalhours) + else { curStageHrs += Configurations.CycleAcceleration; StayCurrentStage(); } - else - { - eggs.Clear(); - if (Props.bleedingIntervalDays == 0) - { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor); - GoNextStage(Stage.Follicular); - } - else - { - bleedingIntervalhours = PeriodRandomizer(bleedingIntervalhours, Props.deviationFactor); - if (crampPain >= 0.05f) - { - AddCrampPain(); - } - GoNextStage(Stage.Bleeding); - } - } + } - protected virtual void BleedingAction() + protected virtual void BleedingAction(bool climacteric) { - if (curStageHrs >= bleedingIntervalhours) + if (climacteric && !Configurations.EnableMenopause) + { + RemoveClimactericEffect(); + StayCurrentStage(); + } + else if (curStageHrs >= currentIntervalHours) { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor); Hediff hediff = parent.pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp); if (hediff != null) parent.pawn.health.RemoveHediff(hediff); - GoNextStage(Stage.Follicular); + int totalFollicularHours = PeriodRandomizer(climacteric ? Stage.ClimactericFollicular : Stage.Follicular, climacteric ? 6.0f : 1.0f); // The total amount of time for both bleeding and follicular + if (totalFollicularHours <= currentIntervalHours) // We've bled for so long that we completely missed the follicular phase + GoOvulatoryStage(climacteric); + else + { + currentIntervalHours = totalFollicularHours - currentIntervalHours; // I.e., the remaining follicular hours equals the total minus the bleeding hours elapsed + GoNextStage(climacteric ? Stage.ClimactericFollicular : Stage.Follicular, false); + } } else { - if (curStageHrs < bleedingIntervalhours / 4) for (int i = 0; i < Configurations.CycleAcceleration; i++) BleedOut(); + if (curStageHrs < currentIntervalHours / 4) for (int i = 0; i < Configurations.CycleAcceleration; i++) BleedOut(); curStageHrs += Configurations.CycleAcceleration; StayCurrentStage(); } @@ -1475,24 +1451,25 @@ namespace RJW_Menstruation Implant(); } - if (parent.pawn.GetRJWPregnancy() != null) + if (parent.pawn.health.hediffSet.hediffs.Contains(pregnancy)) { curStageHrs += 1; StayCurrentStageConst(Stage.Pregnant); } else { + if (pregnancy != null) pregnancy = null; if (Breast != null) { Breast.BirthTransition(); } GoNextStage(Stage.Recover); - } + } } protected virtual void RecoverAction() { - if (curStageHrs >= recoveryIntervalhours) + if (curStageHrs >= currentIntervalHours) { if (Configurations.EnableMenopause && ovarypower < OvaryPowerThreshold) { @@ -1504,7 +1481,6 @@ namespace RJW_Menstruation } else { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor); GoNextStage(Stage.Follicular); } } @@ -1525,97 +1501,10 @@ namespace RJW_Menstruation { StayCurrentStageConst(Stage.Young); } - else GoNextStage(IsBreedingSeason() ? Stage.Follicular : Stage.Anestrus); - } - - protected virtual void ClimactericFollicularAction() - { - if (!Configurations.EnableMenopause) - { - RemoveClimactericEffect(); - StayCurrentStage(); - } - else if (curStageHrs >= (follicularIntervalhours - bleedingIntervalhours) * CycleFactor) - { - GoNextStage(Stage.Ovulatory); - } - else if (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.2f) //skips ovulatory - { - lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor * 6); - GoNextStage(Stage.ClimactericLuteal); - } else { - curStageHrs += Configurations.CycleAcceleration; - StayCurrentStage(); - } - } - - protected virtual void ClimactericLutealAction() - { - if (!Configurations.EnableMenopause) - { - RemoveClimactericEffect(); - StayCurrentStage(); - } - else if (!eggs.NullOrEmpty()) - { - FertilizationCheck(); - EggDecay(); - if (Implant()) GoNextStage(Stage.Pregnant); - else - { - curStageHrs += Configurations.CycleAcceleration; - StayCurrentStage(); - } - } - else if (curStageHrs <= lutealIntervalhours) - { - curStageHrs += Configurations.CycleAcceleration; - StayCurrentStage(); - } - else - { - eggs.Clear(); - if (Props.bleedingIntervalDays == 0) - { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor * 6); - GoNextStage(Stage.ClimactericFollicular); - } - else if (ovarypower < OvaryPowerThreshold / 4 || (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.3f)) //skips bleeding - { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor * 6); - GoNextStage(Stage.ClimactericFollicular); - } - else - { - bleedingIntervalhours = PeriodRandomizer(bleedingIntervalhours, Props.deviationFactor); - if (crampPain >= 0.05f) - { - AddCrampPain(); - } - GoNextStage(Stage.ClimactericBleeding); - } - } - } - - protected virtual void ClimactericBleedingAction() - { - if (!Configurations.EnableMenopause) - { - RemoveClimactericEffect(); - StayCurrentStage(); - } - else if (curStageHrs >= bleedingIntervalhours) - { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor * 6); - GoNextStage(Stage.ClimactericFollicular); - } - else - { - if (curStageHrs < bleedingIntervalhours / 6) for (int i = 0; i < Configurations.CycleAcceleration; i++) BleedOut(); - curStageHrs += Configurations.CycleAcceleration; - StayCurrentStage(); + bool breedingSeason = IsBreedingSeason(); + GoNextStage(breedingSeason ? Stage.Follicular : Stage.Anestrus, breedingSeason); } } @@ -1633,60 +1522,67 @@ namespace RJW_Menstruation protected virtual void ThoughtCumInside(Pawn cummer) { - if (xxx.is_human(parent.pawn) && xxx.is_human(cummer)) - { - if ((cummer.Has(Quirk.Teratophile) != (parent.pawn.GetStatValue(StatDefOf.PawnBeauty) >= 0)) || - cummer.Has(Quirk.ImpregnationFetish) || - cummer.Has(Quirk.Breeder)) - { - if (cummer.relations.OpinionOf(parent.pawn) <= -25) - { - cummer.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideM, parent.pawn); - } - else - { - cummer.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideM, parent.pawn); - } - } + if (!xxx.is_human(parent.pawn) || !xxx.is_human(cummer)) return; - if (IsDangerDay) + if ((cummer.Has(Quirk.Teratophile) != (parent.pawn.GetStatValue(StatDefOf.PawnBeauty) >= 0)) || + cummer.Has(Quirk.ImpregnationFetish) || + cummer.Has(Quirk.Breeder)) + { + if (cummer.relations.OpinionOf(parent.pawn) <= -25) { - if (parent.pawn.Has(Quirk.Breeder) || parent.pawn.Has(Quirk.ImpregnationFetish)) - { - parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideFFetish, cummer); - } - else if (parent.pawn.relations.OpinionOf(cummer) <= -5) - { - parent.pawn.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(VariousDefOf.CameInsideF, cummer); - parent.pawn.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(VariousDefOf.HaterCameInsideFEstrus, cummer); - parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideF, cummer); - } - else if (parent.pawn.IsInEstrus() && parent.pawn.relations.OpinionOf(cummer) < RJWHookupSettings.MinimumRelationshipToHookup) - { - parent.pawn.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(VariousDefOf.CameInsideF, cummer); - parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideFEstrus, cummer); - } - else if (!parent.pawn.relations.DirectRelationExists(PawnRelationDefOf.Spouse, cummer) && !parent.pawn.relations.DirectRelationExists(PawnRelationDefOf.Fiance, cummer)) - { - if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) < 0.50f) parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideFLowFert, cummer); - else parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideF, cummer); - } + cummer.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideM, parent.pawn); } else { - if (parent.pawn.Has(Quirk.Breeder) || parent.pawn.Has(Quirk.ImpregnationFetish)) - { - parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideFFetishSafe, cummer); - } - else if (parent.pawn.relations.OpinionOf(cummer) <= -5) - { - parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideFSafe, cummer); - } + cummer.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideM, parent.pawn); + } + } + + if (IsDangerDay) + { + if (parent.pawn.Has(Quirk.Breeder) || parent.pawn.Has(Quirk.ImpregnationFetish)) + { + parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideFFetish, cummer); + } + else if (parent.pawn.relations.OpinionOf(cummer) <= -5) + { + parent.pawn.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(VariousDefOf.CameInsideF, cummer); + parent.pawn.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(VariousDefOf.HaterCameInsideFEstrus, cummer); + parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideF, cummer); + } + else if (parent.pawn.IsInEstrus() && parent.pawn.relations.OpinionOf(cummer) < RJWHookupSettings.MinimumRelationshipToHookup) + { + parent.pawn.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(VariousDefOf.CameInsideF, cummer); + parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideFEstrus, cummer); + } + else if (!parent.pawn.relations.DirectRelationExists(PawnRelationDefOf.Spouse, cummer) && !parent.pawn.relations.DirectRelationExists(PawnRelationDefOf.Fiance, cummer)) + { + if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) < 0.50f) parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideFLowFert, cummer); + else parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideF, cummer); + } + } + else + { + if (parent.pawn.Has(Quirk.Breeder) || parent.pawn.Has(Quirk.ImpregnationFetish)) + { + parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.CameInsideFFetishSafe, cummer); + } + else if (parent.pawn.relations.OpinionOf(cummer) <= -5) + { + parent.pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.HaterCameInsideFSafe, cummer); } } } - + protected virtual void TaleCumInside(Pawn cummer) + { + // Only make the tale for human-on-human, consentual sex. Otherwise the art just gets too hard to phrase properly + if (!xxx.is_human(parent.pawn) || !xxx.is_human(cummer) || parent.pawn == cummer) return; + if (parent.pawn.CurJobDef != xxx.casual_sex && parent.pawn.CurJobDef != xxx.gettin_loved) return; + if (!(parent.pawn.IsColonist || parent.pawn.IsPrisonerOfColony) && !(cummer.IsColonist || cummer.IsPrisonerOfColony)) return; + if (!IsDangerDay) return; + TaleRecorder.RecordTale(VariousDefOf.TaleCameInside, new object[] { cummer, parent.pawn }); + } private Action PeriodSimulator(Stage targetstage) { @@ -1694,22 +1590,24 @@ namespace RJW_Menstruation switch (targetstage) { case Stage.Follicular: - action = FollicularAction; + action = delegate + { + FollicularAction(false); + }; break; case Stage.Ovulatory: action = OvulatoryAction; break; case Stage.Luteal: - action = LutealAction; - break; - case Stage.Bleeding: - action = BleedingAction; - break; - case Stage.Fertilized: //Obsoleted stage. merged in luteal stage action = delegate { - ModLog.Message("Obsoleted stage. skipping..."); - GoNextStage(Stage.Luteal); + LutealAction(false); + }; + break; + case Stage.Bleeding: + action = delegate + { + BleedingAction(false); }; break; case Stage.Pregnant: @@ -1728,13 +1626,22 @@ namespace RJW_Menstruation action = YoungAction; break; case Stage.ClimactericFollicular: - action = ClimactericFollicularAction; + action = delegate + { + FollicularAction(true); + }; break; case Stage.ClimactericLuteal: - action = ClimactericLutealAction; + action = delegate + { + LutealAction(true); + }; break; case Stage.ClimactericBleeding: - action = ClimactericBleedingAction; + action = delegate + { + BleedingAction(true); + }; break; case Stage.Anestrus: action = AnestrusAction; @@ -1742,7 +1649,7 @@ namespace RJW_Menstruation default: curStage = Stage.Follicular; curStageHrs = 0; - if (follicularIntervalhours < 0) follicularIntervalhours = PeriodRandomizer(Props.folicularIntervalDays * 24, Props.deviationFactor); + if (currentIntervalHours < 0) currentIntervalHours = PeriodRandomizer(curStage); HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Follicular), GetNextUpdate(), parent.pawn, false); break; } @@ -1757,7 +1664,7 @@ namespace RJW_Menstruation actionref = action; return actionref; - + } @@ -1772,19 +1679,18 @@ namespace RJW_Menstruation return ((nextOffset - currentOffset + tickInterval - 1) % tickInterval) + 1; } - protected void GoNextStage(Stage nextstage) + protected void GoNextStage(Stage nextstage, bool calculateHours = true) { curStageHrs = 0; + float variabilityFactor = nextstage == Stage.ClimactericFollicular || nextstage == Stage.ClimactericLuteal || nextstage == Stage.ClimactericBleeding ? 6.0f : 1.0f; + if (calculateHours) currentIntervalHours = PeriodRandomizer(nextstage, variabilityFactor); curStage = nextstage; HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(nextstage), GetNextUpdate(), parent.pawn, false); } - - protected void GoNextStageSetHour(Stage nextstage, int hour) + protected virtual void GoOvulatoryStage(bool climacteric) { - curStageHrs = hour; - curStage = nextstage; - HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(nextstage), GetNextUpdate(), parent.pawn, false); + GoNextStage(Stage.Ovulatory); } //stage can be interrupted in other reasons @@ -1801,15 +1707,14 @@ namespace RJW_Menstruation protected void GoFollicularOrBleeding() { + bool climacteric = Configurations.EnableMenopause && ovarypower < OvaryPowerThreshold; if (Props.bleedingIntervalDays == 0) { - follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor); - GoNextStage(Stage.Follicular); + GoNextStage(climacteric ? Stage.ClimactericFollicular : Stage.Follicular); } else { - bleedingIntervalhours = PeriodRandomizer(bleedingIntervalhours, Props.deviationFactor); - GoNextStage(Stage.Bleeding); + GoNextStage(climacteric ? Stage.ClimactericBleeding : Stage.Bleeding); } } @@ -1824,9 +1729,25 @@ namespace RJW_Menstruation else if (curStage == Stage.ClimactericLuteal) curStage = Stage.Luteal; } - protected int PeriodRandomizer(int intervalhours, float deviation) + protected int PeriodRandomizer(Stage stage, float variabilityFactor = 1.0f) { - return intervalhours + (int)(intervalhours * Rand.Range(-deviation, deviation)); + // Most cycle lengthening or shortening occurs in the follicular phase, so weight towards that + switch (stage) + { + case Stage.Follicular: + case Stage.ClimactericFollicular: + return (int)(Props.follicularIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 1.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 1.5f)); + case Stage.Luteal: + case Stage.ClimactericLuteal: + return (int)(Props.lutealIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f)); + case Stage.Bleeding: + case Stage.ClimactericBleeding: + return (int)(Props.bleedingIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f)); + case Stage.Recover: + return (int)(Props.recoveryIntervalDays * 24 * Rand.Range(-0.05f, 0.05f)); + default: // Often unused + return 1; + } } protected float InterspeciesImplantFactor(Pawn fertilizer) @@ -1851,29 +1772,26 @@ namespace RJW_Menstruation protected Stage RandomStage() { - int rand = Rand.Range(0, 2); + int rand = Rand.ElementByWeight( + 0, Props.follicularIntervalDays - Props.bleedingIntervalDays, + 1, Props.lutealIntervalDays, + 2, Props.bleedingIntervalDays); switch (rand) { case 0: - curStageHrs = Rand.Range(0, (Props.folicularIntervalDays - Props.bleedingIntervalDays) * 24); + curStageHrs = Rand.Range(0, (Props.follicularIntervalDays - Props.bleedingIntervalDays) * 24); return Stage.Follicular; case 1: - curStageHrs = Rand.Range(0, Props.eggLifespanDays * 24); + curStageHrs = Rand.Range(0, Props.lutealIntervalDays * 24); return Stage.Luteal; case 2: curStageHrs = Rand.Range(0, Props.bleedingIntervalDays * 24); return Stage.Bleeding; default: return Stage.Follicular; } - - } - - - - public class Egg : IExposable { public bool fertilized; @@ -1937,12 +1855,4 @@ namespace RJW_Menstruation { } } - - - - - - - - } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs index c988cfc..7f76ffa 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs @@ -1,47 +1,65 @@ -using System; +using RimWorld; +using rjw; +using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; -using Verse; -using rjw; using UnityEngine; +using Verse; namespace RJW_Menstruation { public static class MenstruationUtility { - - + [Obsolete("This method is obsolete. Use GetMenstruationComps or a related function instead", false)] public static HediffComp_Menstruation GetMenstruationComp(this Pawn pawn) { - var hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll((Hediff h) => h.def.defName.ToLower().Contains("vagina")); - HediffComp_Menstruation result; - if (hedifflist.NullOrEmpty()) return null; - else + return pawn.GetFirstMenstruationComp(); + } + + public static IEnumerable GetMenstruationComps(this Pawn pawn) + { + List hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll(h => VariousDefOf.AllVaginas.Contains(h.def)); + if (hedifflist == null) yield break; + foreach (Hediff hediff in hedifflist) { - foreach (Hediff h in hedifflist) - { - result = h.TryGetComp(); - if (result != null) return result; - } + HediffComp_Menstruation result = hediff.TryGetComp(); + if (result != null) yield return result; + } + } + + public static HediffComp_Menstruation GetFirstMenstruationComp(this Pawn pawn) + { + return pawn.GetMenstruationComps().FirstOrDefault(); + } + + public static HediffComp_Menstruation GetRandomMenstruationComp(this Pawn pawn) + { + return pawn.GetMenstruationComps().RandomElementWithFallback(); + } + + public static HediffComp_Menstruation GetFertileMenstruationComp(this Pawn pawn) + { + List comps = pawn.GetMenstruationComps().ToList(); + return comps.Where(c => c.IsDangerDay).RandomElementWithFallback() ?? comps.RandomElementWithFallback(); + } + + public static HediffComp_Menstruation GetMenstruationComp(this Hediff vagina) + { + if (vagina is Hediff_PartBaseNatural || vagina is Hediff_PartBaseArtifical) + { + return vagina.TryGetComp(); } return null; } - public static HediffComp_Menstruation GetMenstruationComp(this Hediff hediff) + public static HediffComp_Menstruation GetMenstruationComp(this Hediff_BasePregnancy pregnancy) { - if (hediff is Hediff_PartBaseNatural || hediff is Hediff_PartBaseArtifical) - { - return hediff.TryGetComp(); - } - return null; + return pregnancy?.pawn.GetMenstruationComps().FirstOrDefault(comp => comp.Pregnancy == pregnancy); } public static HediffComp_Anus GetAnusComp(this Pawn pawn) { - var hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll((Hediff h) => h.def.defName.ToLower().Contains("anus")); + List hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll((Hediff h) => h.def.defName.ToLower().Contains("anus")); HediffComp_Anus result; if (!hedifflist.NullOrEmpty()) { @@ -63,18 +81,11 @@ namespace RJW_Menstruation return null; } - public static float GetFertilityChance(this HediffComp_Menstruation comp) { - return comp.TotalFertCum * Configurations.FertilizeChance * comp.Props.basefertilizationChanceFactor; + return 1.0f - Mathf.Pow(1.0f - Configurations.FertilizeChance, comp.TotalFertCum * comp.Props.basefertilizationChanceFactor); } - public static HediffComp_Menstruation.Stage GetCurStage(this Pawn pawn) - { - return GetMenstruationComp(pawn)?.curStage ?? HediffComp_Menstruation.Stage.Bleeding; - } - - public static Texture2D GetPregnancyIcon(this HediffComp_Menstruation comp, Hediff hediff) { string icon = ""; @@ -157,19 +168,19 @@ namespace RJW_Menstruation } public static Texture2D GetEggIcon(this HediffComp_Menstruation comp, bool includeOvary) { - if (comp.parent.pawn.IsPregnant(Configurations.InfoDetail != Configurations.DetailLevel.All) && !(PregnancyHelper.GetPregnancy(comp.parent.pawn) is Hediff_MechanoidPregnancy)) - { - if (comp.parent.pawn.GetPregnancyProgress() < 0.2f) return ContentFinder.Get("Eggs/Egg_Implanted00", true); + if (comp.Pregnancy != null && !(comp.Pregnancy is Hediff_MechanoidPregnancy)) + { + if (comp.GetPregnancyProgress() < 0.2f) return ContentFinder.Get("Eggs/Egg_Implanted00", true); else return ContentFinder.Get("Womb/Empty", true); } - switch(comp.curStage) + switch (comp.curStage) { case HediffComp_Menstruation.Stage.Follicular: case HediffComp_Menstruation.Stage.ClimactericFollicular: if (!includeOvary) break; if (comp is HediffComp_InducedOvulator) break; - if (comp.curStageHrs > comp.FollicularIntervalHours - 30) // Approximate time for ovulation to occur + if (comp.curStageHrs > comp.CurStageIntervalHours - 30) // Approximate time for ovulation to occur return ContentFinder.Get("Ovaries/Ovary_01", true); else break; case HediffComp_Menstruation.Stage.Ovulatory: @@ -209,7 +220,7 @@ namespace RJW_Menstruation public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp, bool drawOrigin = false) { - var hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.Find((Hediff h) => h.def.defName.ToLower().Contains("vagina")); + Hediff hediff = comp?.parent; if (hediff == null) return ContentFinder.Get("Genitals/Vagina00", true); //HediffComp_Menstruation comp = hediff.GetMenstruationComp(); string icon; @@ -237,37 +248,32 @@ namespace RJW_Menstruation public static Texture2D GetAnalIcon(this Pawn pawn, bool drawOrigin = false) { - var hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("anus")); - if (hediff != null) - { - string icon; - float severity; - HediffComp_Anus comp = hediff.GetAnusComp(); - if (comp != null) - { - CompProperties_Anus Props = (CompProperties_Anus)comp.props; - icon = Props.analTex ?? "Genitals/Anal"; - if (drawOrigin) severity = comp.OriginAnusSize; - else severity = hediff.Severity; - } - else - { - icon = "Genitals/Anal"; - severity = hediff.Severity; - } - if (severity < 0.20f) icon += "00"; //micro - else if (severity < 0.40f) icon += "01"; //tight - else if (severity < 0.60f) icon += "02"; //average - else if (severity < 0.80f) icon += "03"; //accomodating - else if (severity < 1.01f) icon += "04"; //cavernous - else icon += "05"; //abyssal + Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("anus")); + if (hediff == null) return ContentFinder.Get(("Genitals/Anal00"), true); - return ContentFinder.Get((icon), true); + string icon; + float severity; + HediffComp_Anus comp = hediff.GetAnusComp(); + if (comp != null) + { + CompProperties_Anus Props = (CompProperties_Anus)comp.props; + icon = Props.analTex ?? "Genitals/Anal"; + if (drawOrigin) severity = comp.OriginAnusSize; + else severity = hediff.Severity; } else { - return ContentFinder.Get(("Genitals/Anal00"), true); + icon = "Genitals/Anal"; + severity = hediff.Severity; } + if (severity < 0.20f) icon += "00"; //micro + else if (severity < 0.40f) icon += "01"; //tight + else if (severity < 0.60f) icon += "02"; //average + else if (severity < 0.80f) icon += "03"; //accomodating + else if (severity < 1.01f) icon += "04"; //cavernous + else icon += "05"; //abyssal + + return ContentFinder.Get((icon), true); } public static float GestationHours(this Hediff_BasePregnancy hediff) @@ -280,6 +286,21 @@ namespace RJW_Menstruation else return (hediff.p_end_tick - hediff.p_start_tick) / GenDate.TicksPerHour; } + public static float RandomVariabilityPercent(int recursion = 0) + { + // Humans, in days + const float mean = 1.635f; + const float stddev = 0.9138f; + const float lambda = 0.234f; + if (recursion >= 10) return mean / (28 * 2); + + float variability = Rand.Gaussian(mean, stddev) - Mathf.Log(Rand.Value) / lambda; + variability /= 28 * 2; // Convert to percentage + + if (variability < 0 || variability > 0.35f) return RandomVariabilityPercent(recursion + 1); // ~2% chance, about the limit on how far variability can go before things start to break + else return variability; + } + public static bool IsInEstrus(this Pawn pawn, bool visible = true) { if (pawn.Dead) return false; diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs index 73521e2..56eff5c 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs @@ -17,21 +17,26 @@ namespace RJW_Menstruation protected void PregnancyThought() { - if (!is_discovered && xxx.is_human(pawn)) + if (is_discovered || + !xxx.is_human(pawn) || + pawn.Has(Quirk.Breeder) || + (pawn.relations?.DirectRelations?.Find(x => x.def.Equals(PawnRelationDefOf.Spouse) || + x.def.Equals(PawnRelationDefOf.Fiance))) != null) + return; + if (pawn.Has(Quirk.ImpregnationFetish) || pawn.relations?.DirectRelations?.Find(x => x.def.Equals(PawnRelationDefOf.Lover)) != null) { - if (!pawn.Has(Quirk.Breeder) && pawn.relations?.DirectRelations?.Find(x => x.def.Equals(PawnRelationDefOf.Spouse) || x.def.Equals(PawnRelationDefOf.Fiance)) == null) - { - if (pawn.Has(Quirk.ImpregnationFetish) || pawn.relations?.DirectRelations?.Find(x => x.def.Equals(PawnRelationDefOf.Lover)) != null) - { - pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.UnwantedPregnancyMild); - } - else - { - pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.UnwantedPregnancy); - } - } - + pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.UnwantedPregnancyMild); } + else + { + pawn.needs.mood.thoughts.memories.TryGainMemory(VariousDefOf.UnwantedPregnancy); + } + } + + public override void Miscarry() + { + this.GetMenstruationComp().Pregnancy = null; + base.Miscarry(); } public override void GiveBirth() @@ -47,42 +52,43 @@ namespace RJW_Menstruation Initialize(pawn, father); } - List siblings = new List(); foreach (Pawn baby in babies) { if (xxx.is_animal(baby)) { - BestialBirth(baby, siblings); + BestialBirth(baby); } else { - HumanlikeBirth(baby, siblings); + HumanlikeBirth(baby); } baby.ageTracker.AgeChronologicalTicks = 0; } pawn.health.RemoveHediff(this); + HediffComp_Menstruation comp = this.GetMenstruationComp(); + if(comp != null) comp.Pregnancy = null; } public string GetBabyInfo() { + if (babies.NullOrEmpty()) + return "Null"; + string res = ""; - if (!babies.NullOrEmpty()) + + IEnumerable babiesdistinct = babies.Distinct(new RaceComparer()); + int iteration = 0; + foreach (Pawn baby in babiesdistinct) { - var babiesdistinct = babies.Distinct(new RaceComparer()); - int iteration = 0; - foreach (Pawn baby in babiesdistinct) - { - int num = babies.Where(x => x.def.Equals(baby.def)).Count(); - if (iteration > 0) res += ", "; - res += num + " " + baby.def.label; - iteration++; - } - res += " " + Translations.Dialog_WombInfo02; - return res; + int num = babies.Where(x => x.def.Equals(baby.def)).Count(); + if (iteration > 0) res += ", "; + res += num + " " + baby.def.label; + iteration++; } - return "Null"; + res += " " + Translations.Dialog_WombInfo02; + return res; } public string GetFatherInfo() @@ -95,7 +101,7 @@ namespace RJW_Menstruation if (!is_parent_known && Configurations.InfoDetail != Configurations.DetailLevel.All) return res + Translations.Dialog_FatherUnknown; - var babiesdistinct = babies.Distinct(new FatherComparer(pawn)); + IEnumerable babiesdistinct = babies.Distinct(new FatherComparer(pawn)); int iteration = 0; foreach (Pawn baby in babiesdistinct) { @@ -106,7 +112,7 @@ namespace RJW_Menstruation return res; } - private void HumanlikeBirth(Pawn baby, List siblings) + private void HumanlikeBirth(Pawn baby) { Pawn mother = pawn; Pawn father = Utility.GetFather(baby, pawn); //backup melanin, LastName for when baby reset by other mod on spawn/backstorychange @@ -115,7 +121,7 @@ namespace RJW_Menstruation PawnUtility.TrySpawnHatchedOrBornPawn(baby, mother); - var sex_need = mother.needs?.TryGetNeed(); + Need_Sex sex_need = mother.needs?.TryGetNeed(); if (mother.Faction != null && !(mother.Faction?.IsPlayer ?? false) && sex_need != null) { sex_need.CurLevel = 1.0f; @@ -144,17 +150,13 @@ namespace RJW_Menstruation baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Prisoner); } - foreach (Pawn sibling in siblings) - { - baby.relations.AddDirectRelation(PawnRelationDefOf.Sibling, sibling); - } - siblings.Add(baby); - + if (xxx.is_human(mother)) TaleRecorder.RecordTale(TaleDefOf.GaveBirth, new object[] { mother, baby }); + PostBirth(mother, father, baby); } - private void BestialBirth(Pawn baby, List siblings) + private void BestialBirth(Pawn baby) { Pawn mother = pawn; Pawn father = Utility.GetFather(baby, pawn); //backup melanin, LastName for when baby reset by other mod on spawn/backstorychange @@ -174,14 +176,6 @@ namespace RJW_Menstruation baby.SetFaction(mother.Faction); } - if (!RJWSettings.Disable_bestiality_pregnancy_relations) - { - foreach (Pawn sibling in siblings) - { - baby.relations.AddDirectRelation(PawnRelationDefOf.Sibling, sibling); - } - siblings.Add(baby); - } Train(baby, mother); PostBirth(mother, father, baby); @@ -198,7 +192,6 @@ namespace RJW_Menstruation List momtraits = new List(); List poptraits = new List(); List traits_to_inherit = new List(); - System.Random rd = new System.Random(); float max_num_momtraits_inherited = RJWPregnancySettings.max_num_momtraits_inherited; float max_num_poptraits_inherited = RJWPregnancySettings.max_num_poptraits_inherited; float max_num_traits_inherited = max_num_momtraits_inherited + max_num_poptraits_inherited; @@ -226,7 +219,7 @@ namespace RJW_Menstruation i = 1; while (momtraits.Count > 0 && i <= max_num_momtraits_inherited) { - rand_trait_index = rd.Next(0, momtraits.Count); + rand_trait_index = Rand.Range(0, momtraits.Count); traits_to_inherit.Add(momtraits[rand_trait_index]); momtraits.RemoveAt(rand_trait_index); } @@ -236,7 +229,7 @@ namespace RJW_Menstruation j = 1; while (poptraits.Count > 0 && j <= max_num_poptraits_inherited) { - rand_trait_index = rd.Next(0, poptraits.Count); + rand_trait_index = Rand.Range(0, poptraits.Count); traits_to_inherit.Add(poptraits[rand_trait_index]); poptraits.RemoveAt(rand_trait_index); } @@ -257,7 +250,7 @@ namespace RJW_Menstruation { while (poptraits != null && momtraits.Count() > 0 && i <= max_num_momtraits_inherited) { - rand_trait_index = rd.Next(0, momtraits.Count); + rand_trait_index = Rand.Range(0, momtraits.Count); if (!traits_to_inherit.Contains(momtraits[rand_trait_index])) { traits_to_inherit.Add(momtraits[rand_trait_index]); @@ -269,7 +262,7 @@ namespace RJW_Menstruation { while (poptraits.Count > 0 && i < max_num_poptraits_inherited) { - rand_trait_index = rd.Next(0, poptraits.Count); + rand_trait_index = Rand.Range(0, poptraits.Count); if (!traits_to_inherit.Contains(poptraits[rand_trait_index])) { traits_to_inherit.Add(poptraits[rand_trait_index]); @@ -295,16 +288,15 @@ namespace RJW_Menstruation protected void Train(Pawn baby, Pawn mother) { - if (!xxx.is_human(baby) && baby.Faction == Faction.OfPlayer) + if (xxx.is_human(baby) || baby.Faction != Faction.OfPlayer) return; + + if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Obedience, out _).Accepted) { - if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Obedience, out _).Accepted) - { - baby.training.Train(TrainableDefOf.Obedience, mother); - } - if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Tameness, out _).Accepted) - { - baby.training.Train(TrainableDefOf.Tameness, mother); - } + baby.training.Train(TrainableDefOf.Obedience, mother); + } + if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Tameness, out _).Accepted) + { + baby.training.Train(TrainableDefOf.Tameness, mother); } } @@ -352,7 +344,7 @@ namespace RJW_Menstruation kind: BabyPawnKindDecider(mother, father), //fixedIdeo: mother.Ideo, //forbidAnyTitle: true, - forceNoBackstory:true + forceNoBackstory: true ); int division = 1; @@ -363,7 +355,7 @@ namespace RJW_Menstruation string firstheadpath = null; string firstHARcrown = null; int traitSeed = Rand.Int; - List parentTraits = GetInheritableTraits(mother, father); + List parentTraits = GetInheritableTraits(mother, father); while (Rand.Chance(Configurations.EnzygoticTwinsChance) && division < Configurations.MaxEnzygoticTwins) division++; for (int i = 0; i < division; i++) { @@ -421,30 +413,28 @@ namespace RJW_Menstruation public Pawn GenerateBaby(PawnGenerationRequest request, Pawn mother, Pawn father, List parentTraits, int traitSeed) { Pawn baby = PawnGenerator.GeneratePawn(request); - if (baby != null) + if (baby == null) { - if (xxx.is_human(baby) || (baby.relations != null && !RJWSettings.Disable_bestiality_pregnancy_relations)) + Log.Error("Baby not generated. Request: " + request.ToString()); + return null; + } + if (xxx.is_human(baby) || (baby.relations != null && !RJWSettings.Disable_bestiality_pregnancy_relations)) + { + baby.SetMother(mother); + if (mother != father) { - baby.SetMother(mother); - if (mother != father) - { - if (father.gender != Gender.Female) baby.SetFather(father); - else - { - baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, father); - } - } - } - if (xxx.is_human(baby)) - { - // Ensure the same inherited traits are chosen each run - // Has to happen right here so GeneratePawn up there still gets unique results - Rand.PushState(traitSeed); // With a seed just to make sure that fraternal twins *don't* get trait-duped - UpdateTraits(baby, parentTraits); - Rand.PopState(); + if (father.gender != Gender.Female) baby.SetFather(father); + else baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, father); } } - else Log.Error("Baby not generated. Request: " + request.ToString()); + if (xxx.is_human(baby)) + { + // Ensure the same inherited traits are chosen each run + // Has to happen right here so GeneratePawn up there still gets unique results + Rand.PushState(traitSeed); // With a seed just to make sure that fraternal twins *don't* get trait-duped + UpdateTraits(baby, parentTraits); + Rand.PopState(); + } return baby; } @@ -457,7 +447,10 @@ namespace RJW_Menstruation /// public PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father) { - PawnKindDef spawn_kind_def = mother.kindDef; + PawnKindDef motherKindDef = Utility.GetRacesPawnKind(mother); + PawnKindDef fatherKindDef = Utility.GetRacesPawnKind(father); + + PawnKindDef spawn_kind_def = motherKindDef; int flag = 0; if (xxx.is_human(mother)) flag += 2; @@ -471,18 +464,18 @@ namespace RJW_Menstruation switch (flag) { case 3: - if (!Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother)) spawn_kind_def = father.kindDef; + if (!Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother)) spawn_kind_def = fatherKindDef; break; case 2: - if (RJWPregnancySettings.bestiality_DNA_inheritance == 0f) spawn_kind_def = father.kindDef; - else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = father.kindDef; + if (RJWPregnancySettings.bestiality_DNA_inheritance == 0f) spawn_kind_def = fatherKindDef; + else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef; break; case 1: - if (RJWPregnancySettings.bestiality_DNA_inheritance == 1f) spawn_kind_def = father.kindDef; - else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = father.kindDef; + if (RJWPregnancySettings.bestiality_DNA_inheritance == 1f) spawn_kind_def = fatherKindDef; + else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef; break; case 0: - if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = father.kindDef; + if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef; break; } @@ -490,19 +483,19 @@ namespace RJW_Menstruation bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father); if (IsAndroidmother && !IsAndroidfather) { - spawn_kind_def = father.kindDef; + spawn_kind_def = fatherKindDef; } else if (!IsAndroidmother && IsAndroidfather) { - spawn_kind_def = mother.kindDef; + spawn_kind_def = motherKindDef; } string MotherRaceName = ""; string FatherRaceName = ""; - MotherRaceName = mother.kindDef?.race?.defName; + MotherRaceName = motherKindDef?.race?.defName; PawnKindDef non_hybrid_kind_def = spawn_kind_def; if (father != null) - FatherRaceName = father.kindDef?.race?.defName; + FatherRaceName = fatherKindDef?.race?.defName; if (FatherRaceName != "" && Configurations.UseHybridExtention) @@ -516,24 +509,24 @@ namespace RJW_Menstruation if (!Configurations.UseHybridExtention || spawn_kind_def == null) { spawn_kind_def = non_hybrid_kind_def; - var groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty())); + IEnumerable groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty())); //ModLog.Message(" found custom RaceGroupDefs " + groups.Count()); - foreach (var t in groups) + foreach (RaceGroupDef t in groups) { if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName)) || (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName)))) { //ModLog.Message(" has hybridRaceParents"); if (t.hybridChildKindDef.Contains("MotherKindDef")) - spawn_kind_def = mother.kindDef; + spawn_kind_def = motherKindDef; else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null) - spawn_kind_def = father.kindDef; + spawn_kind_def = fatherKindDef; else { //ModLog.Message(" trying hybridChildKindDef " + t.defName); - var child_kind_def_list = new List(); + List child_kind_def_list = new List(); child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName))); //ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count); @@ -547,20 +540,20 @@ namespace RJW_Menstruation } else if (!Configurations.UseHybridExtention || spawn_kind_def == null) { - spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? mother.kindDef; + spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? motherKindDef; } if (spawn_kind_def.defName.Contains("Nymph")) { //child is nymph, try to find other PawnKindDef - var spawn_kind_def_list = new List(); + List spawn_kind_def_list = new List(); spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph"))); //no other PawnKindDef found try mother if (spawn_kind_def_list.NullOrEmpty()) - spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == mother.kindDef.race && !x.defName.Contains("Nymph"))); + spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == motherKindDef.race && !x.defName.Contains("Nymph"))); //no other PawnKindDef found try father if (spawn_kind_def_list.NullOrEmpty() && father != null) - spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == father.kindDef.race && !x.defName.Contains("Nymph"))); + spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == fatherKindDef.race && !x.defName.Contains("Nymph"))); //no other PawnKindDef found fallback to generic colonist if (spawn_kind_def_list.NullOrEmpty()) spawn_kind_def = PawnKindDefOf.Colonist; @@ -568,9 +561,6 @@ namespace RJW_Menstruation if (!spawn_kind_def_list.NullOrEmpty()) spawn_kind_def = spawn_kind_def_list.RandomElement(); } - - - return spawn_kind_def; } @@ -638,17 +628,17 @@ namespace RJW_Menstruation parentTraitPool.RemoveAll(x => x.ScenForced); int numberInherited; if (parentTraitPool != null) - numberInherited = System.Math.Min(parentTraitPool.Count(), Rand.RangeInclusive(0,2)); // Not 3; give a better chance for a natural trait to appear + numberInherited = System.Math.Min(parentTraitPool.Count(), Rand.RangeInclusive(0, 2)); // Not 3; give a better chance for a natural trait to appear else numberInherited = 0; //Game suggested traits. - var forcedTraits = personalTraitPool + IEnumerable forcedTraits = personalTraitPool .Where(x => x.ScenForced) .Distinct(new TraitComparer(ignoreDegree: true)); // result can be a mess, because game allows this mess to be created in scenario editor List selectedTraits = new List(); - var comparer = new TraitComparer(); // trait comparision implementation, because without game compares traits *by reference*, makeing them all unique. + TraitComparer comparer = new TraitComparer(); // trait comparision implementation, because without game compares traits *by reference*, makeing them all unique. selectedTraits.AddRange(forcedTraits); // enforcing scenario forced traits for (int i = 0; i < numberInherited; i++) // add parent traits first { @@ -663,13 +653,13 @@ namespace RJW_Menstruation while (selectedTraits.Count < traitLimit && personalTraitPool.Count > 0) { int index = Rand.Range(0, personalTraitPool.Count); // getting trait and removing from the pull - var trait = personalTraitPool[index]; + Trait trait = personalTraitPool[index]; personalTraitPool.RemoveAt(index); if (!selectedTraits.Any(x => comparer.Equals(x, trait) || // skipping traits conflicting with already added x.def.ConflictsWith(trait))) selectedTraits.Add(new Trait(trait.def, trait.Degree, false)); - + } pawn.story.traits.allTraits = selectedTraits; diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/IngestionOutcomeDoers.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/IngestionOutcomeDoers.cs index 6ca0713..0ebf299 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/IngestionOutcomeDoers.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/IngestionOutcomeDoers.cs @@ -1,24 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; +using RimWorld; using Verse; -using rjw; namespace RJW_Menstruation { public class IngestionOutcomeDoer_GiveHediff_StackCount : IngestionOutcomeDoer_GiveHediff - { - protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested) - { - Hediff hediff = HediffMaker.MakeHediff(hediffDef, pawn); - float effect = ((!(severity > 0f)) ? hediffDef.initialSeverity : severity) * ingested.stackCount; - AddictionUtility.ModifyChemicalEffectForToleranceAndBodySize(pawn, toleranceChemical, ref effect); - hediff.Severity = effect; - pawn.health.AddHediff(hediff); - } + { + protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested) + { + Hediff hediff = HediffMaker.MakeHediff(hediffDef, pawn); + float effect = ((!(severity > 0f)) ? hediffDef.initialSeverity : severity) * ingested.stackCount; + AddictionUtility.ModifyChemicalEffectForToleranceAndBodySize(pawn, toleranceChemical, ref effect); + hediff.Severity = effect; + pawn.health.AddHediff(hediff); + } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/JobDrivers.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/JobDrivers.cs index 0dcd459..99cae05 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/JobDrivers.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/JobDrivers.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using RimWorld; +using RimWorld; +using System.Collections.Generic; +using System.Linq; using Verse; using Verse.AI; @@ -16,11 +17,10 @@ namespace RJW_Menstruation protected override IEnumerable MakeNewToils() { - - HediffComp_Menstruation Comp = pawn.GetMenstruationComp(); + List comps = pawn.GetMenstruationComps().ToList(); this.FailOn(delegate { - return !(Comp.TotalCumPercent > 0.001); + return comps.All(comp => comp.TotalCumPercent < 0.001); }); Toil excreting = Toils_General.Wait(excretingTime, TargetIndex.None);//duration of @@ -30,8 +30,9 @@ namespace RJW_Menstruation { initAction = delegate () { - Comp.CumOut(null, 0.5f); - if (Comp.TotalCumPercent > 0.001) JumpToToil(excreting); + foreach (HediffComp_Menstruation comp in comps) + comp.CumOut(null, 0.5f); + if (comps.Any(comp => comp.TotalCumPercent > 0.001)) JumpToToil(excreting); } }; //yield return excreting; @@ -107,7 +108,7 @@ namespace RJW_Menstruation protected virtual void Finish() { - if(pawn.CurJobDef == JobDefOf.Wait_MaintainPosture) + if (pawn.CurJobDef == JobDefOf.Wait_MaintainPosture) { pawn.jobs.EndCurrentJob(JobCondition.InterruptForced); } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GC_Patch.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GC_Patch.cs index 82a2bf0..79e7be5 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GC_Patch.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GC_Patch.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; -using System.Linq; -using HarmonyLib; -using Verse; +using HarmonyLib; using RimWorld; using RimWorld.Planet; +using System.Collections.Generic; +using System.Linq; +using Verse; namespace RJW_Menstruation.Patch { @@ -26,12 +26,11 @@ namespace RJW_Menstruation.Patch public static void Prefix() { GetCriticalPawnReason_Patch.cummedPawns.Clear(); -// foreach(Pawn p in PawnsFinder.All_AliveOrDead) - foreach(Pawn p in PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_OfPlayerFaction.Union(PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_PrisonersOfColony)) + // foreach(Pawn p in PawnsFinder.All_AliveOrDead) + foreach (Pawn p in PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_OfPlayerFaction.Union(PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_PrisonersOfColony)) { - HediffComp_Menstruation comp = p.GetMenstruationComp(); - if (comp is null) continue; - GetCriticalPawnReason_Patch.cummedPawns.UnionWith(comp.GetCummersAndFertilizers()); + foreach (HediffComp_Menstruation comp in p.GetMenstruationComps()) + GetCriticalPawnReason_Patch.cummedPawns.UnionWith(comp.GetCummersAndFertilizers()); } } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GetGizmos.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GetGizmos.cs index fe22153..22bf735 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GetGizmos.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/GetGizmos.cs @@ -28,11 +28,9 @@ namespace RJW_Menstruation foreach (Gizmo gizmo in gizmos) yield return gizmo; - HediffComp_Menstruation comp = __instance.GetMenstruationComp(); - if (comp == null) yield break; - - foreach (Gizmo gizmo in GetMenstruationGizmos(__instance, comp)) - yield return gizmo; + foreach (HediffComp_Menstruation comp in __instance.GetMenstruationComps()) + foreach (Gizmo gizmo in GetMenstruationGizmos(__instance, comp)) + yield return gizmo; } public static List GetMenstruationGizmos(Pawn pawn, HediffComp_Menstruation comp) @@ -49,8 +47,8 @@ namespace RJW_Menstruation else description += comp.GetCurStageLabel + "\n"; if (pawn.IsPregnant()) { - Hediff hediff = PregnancyHelper.GetPregnancy(pawn); - if (Utility.ShowFetusImage((Hediff_BasePregnancy)hediff)) + Hediff_BasePregnancy hediff = comp.Pregnancy; + if (Utility.ShowFetusImage(hediff)) { icon = comp.GetPregnancyIcon(hediff); if (hediff is Hediff_BasePregnancy h) @@ -100,7 +98,7 @@ namespace RJW_Menstruation Dialog_WombStatus.ToggleWindow(pawn, comp); } }; - + return gizmo; } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs index be30dc8..d701d49 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs @@ -14,14 +14,14 @@ namespace RJW_Menstruation { static First() { - var har = new Harmony("RJW_Menstruation"); + Harmony har = new Harmony("RJW_Menstruation"); har.PatchAll(Assembly.GetExecutingAssembly()); InjectIntoRjwInteractionServices(); } private static void InjectIntoRjwInteractionServices() { - var log = LogManager.GetLogger("StaticConstructorOnStartup"); + ILog log = LogManager.GetLogger("StaticConstructorOnStartup"); List partKindUsageRules = Unprivater.GetProtectedValue>("_partKindUsageRules", typeof(PartPreferenceDetectorService)); partKindUsageRules.Add(new Interactions.EstrusPartKindUsageRule()); diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs index 260937c..2265058 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs @@ -2,10 +2,8 @@ using HugsLib; using RimWorld; using System.Collections.Generic; -using System.Linq; using UnityEngine; using Verse; -using rjw; namespace RJW_Menstruation { @@ -16,20 +14,18 @@ namespace RJW_Menstruation public static void Postfix(Pawn __instance) { //Log.Message("Initialize on spawnsetup"); - HediffComp_Menstruation comp = __instance.GetMenstruationComp(); - if (comp != null) + foreach (HediffComp_Menstruation comp in __instance.GetMenstruationComps()) { HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(comp.actionref); comp.Initialize(); } + HediffComp_Breast bcomp = __instance.GetBreastComp(); if (bcomp != null) { HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(bcomp.action); bcomp.Initialize(); } - - } } @@ -38,7 +34,7 @@ namespace RJW_Menstruation { public static void Postfix(Vector3 clickPos, Pawn pawn, List opts) { - var selftargets = GenUI.TargetsAt(clickPos, TargetingParameters.ForSelf(pawn)); + IEnumerable selftargets = GenUI.TargetsAt(clickPos, TargetingParameters.ForSelf(pawn)); foreach (LocalTargetInfo t in selftargets) { diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs index 887f6b8..f4445f9 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs @@ -2,12 +2,12 @@ using rjw; using rjw.Modules.Interactions.Enums; using rjw.Modules.Interactions.Objects; -using Verse; -using UnityEngine; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; +using UnityEngine; +using Verse; namespace RJW_Menstruation { @@ -15,22 +15,28 @@ namespace RJW_Menstruation [HarmonyPatch(typeof(PregnancyHelper), nameof(PregnancyHelper.impregnate))] public static class Impregnate_Patch { - public static bool Prefix(SexProps props) + public static bool Prefix(SexProps props, out HediffComp_Menstruation __state) { xxx.rjwSextype sextype = props.sexType; Pawn pawn = props.pawn; Pawn partner = props.partner; + if (PregnancyHelper.GetPregnancy(partner) is Hediff_BasePregnancy oldestPregnancy) __state = oldestPregnancy.GetMenstruationComp(); + else __state = null; + if (sextype != xxx.rjwSextype.Vaginal && sextype != xxx.rjwSextype.DoublePenetration) return true; if (partner.IsAnimal() && !Configurations.EnableAnimalCycle) return true; if (!InteractionCanCausePregnancy(props)) return false; - var pawnparts = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)); + List pawnparts = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)); - HediffComp_Menstruation comp = partner.GetMenstruationComp(); - if (comp is null) return true; + HediffComp_Menstruation comp; + if (pawn.Has(Quirk.ImpregnationFetish) || partner.Has(Quirk.ImpregnationFetish) || partner.IsInEstrus()) + comp = partner.GetFertileMenstruationComp(); + else comp = partner.GetRandomMenstruationComp(); + if (comp == null) return true; if (Genital_Helper.has_penis_fertile(pawn, pawnparts) && PregnancyHelper.CanImpregnate(pawn, partner, sextype)) { @@ -44,8 +50,18 @@ namespace RJW_Menstruation else comp.CumIn(pawn, pawn.GetCumVolume(pawnparts), 0); return true; + } + public static void Postfix(SexProps props, HediffComp_Menstruation __state) + { + if (__state == null || __state.Pregnancy != null) return; + // It was pregnant, but not anymore. This probably means the pregnancy was destroyed by e.g. a mech implant + Pawn pawn = props.partner; + Hediff_BasePregnancy newestPregnancy = pawn.health.hediffSet.GetHediffs().MaxBy(hediff => hediff.loadID); + if (newestPregnancy == null) return; + if (pawn.GetMenstruationComps().Any(comp => comp.Pregnancy == newestPregnancy)) return; // One of the wombs did get it + else __state.Pregnancy = newestPregnancy; } /// @@ -85,31 +101,59 @@ namespace RJW_Menstruation public static bool Prefix(Pawn pawn, Pawn partner) // partner has vagina { if (partner.IsAnimal() && !Configurations.EnableAnimalCycle) return true; - HediffComp_Menstruation comp = partner.GetMenstruationComp(); - if (comp != null) + HediffComp_Menstruation comp; + if (pawn.Has(Quirk.ImpregnationFetish) || partner.Has(Quirk.ImpregnationFetish) || partner.IsInEstrus()) + comp = partner.GetFertileMenstruationComp(); + else comp = partner.GetRandomMenstruationComp(); + if (comp == null) { - if (AndroidsCompatibility.IsAndroid(pawn) && !AndroidsCompatibility.AndroidPenisFertility(pawn)) - { - comp.CumIn(pawn, pawn.GetCumVolume(), 0); - return false; - } - else comp.CumIn(pawn, pawn.GetCumVolume(), pawn.health.capacities.GetLevel(xxx.reproduction)); + if (Configurations.Debug) ModLog.Message("used original rjw method: Comp missing"); + return true; + } + else if (AndroidsCompatibility.IsAndroid(pawn) && !AndroidsCompatibility.AndroidPenisFertility(pawn)) + { + comp.CumIn(pawn, pawn.GetCumVolume(), 0); return false; } - ModLog.Message("used original rjw method: Comp missing"); - return true; + else comp.CumIn(pawn, pawn.GetCumVolume(), pawn.health.capacities.GetLevel(xxx.reproduction)); + return false; + } + } + + [HarmonyPatch(typeof(PregnancyHelper), nameof(PregnancyHelper.CanImpregnate))] + public static class CanImpregnate_Patch + { + private static bool PregnancyBlocksImpregnation(this Pawn pawn, bool _) + { + if (!Configurations.EnableAnimalCycle && pawn.IsAnimal()) return pawn.IsPregnant(); + else if (pawn.GetMenstruationComps().Any()) return false; + else return pawn.IsPregnant(); + } + private static readonly MethodInfo IsPregnant = AccessTools.Method(typeof(PawnExtensions), nameof(PawnExtensions.IsPregnant), new System.Type[] {typeof(Pawn), typeof(bool)}); + public static IEnumerable Transpiler(IEnumerable instructions) + { + if (IsPregnant == null) throw new System.InvalidOperationException("IsPregnant not found"); + foreach(CodeInstruction instruction in instructions) + { + if (instruction.Calls(IsPregnant)) + yield return CodeInstruction.Call(typeof(CanImpregnate_Patch), nameof(PregnancyBlocksImpregnation)); + else yield return instruction; + } } } [HarmonyPatch(typeof(Hediff_BasePregnancy), nameof(Hediff_BasePregnancy.PostBirth))] public static class RJW_Patch_PostBirth { - public static void Postfix(Pawn mother, Pawn baby) + public static void Postfix(Hediff_BasePregnancy __instance, Pawn mother, Pawn baby) { if (Configurations.EnableBirthVaginaMorph) { - Hediff vagina = mother.health.hediffSet.hediffs.FirstOrFallback(x => x.def.defName.ToLower().Contains("vagina")); - float morph = Mathf.Max(baby.BodySize - Mathf.Pow(vagina.Severity * mother.BodySize,2), 0f); + // The comp still has the pregnancy attached at this point in the process + Hediff vagina = __instance.GetMenstruationComp()?.parent; + if (vagina == null) vagina = mother.health.hediffSet.hediffs.FirstOrFallback(x => VariousDefOf.AllVaginas.Contains(x.def)); + if (vagina == null) return; + float morph = Mathf.Max(baby.BodySize - Mathf.Pow(vagina.Severity * mother.BodySize, 2), 0f); vagina.Severity += morph * Configurations.VaginaMorphPower; } } @@ -123,9 +167,9 @@ namespace RJW_Menstruation // This is stricter than can_impregnate, so quickly filter out scenarios that are negative anyways. if (__result == false || __instance != Quirk.ImpregnationFetish) return; __result = - ((PregnancyHelper.CanImpregnate(pawn, partner) && (partner.GetMenstruationComp()?.IsDangerDay ?? true)) + (PregnancyHelper.CanImpregnate(pawn, partner) && (partner.GetMenstruationComps()?.Any(comp => comp.IsDangerDay) ?? true)) || - (PregnancyHelper.CanImpregnate(partner, pawn) && (pawn.GetMenstruationComp()?.IsDangerDay ?? true))); + (PregnancyHelper.CanImpregnate(partner, pawn) && (pawn.GetMenstruationComps()?.Any(comp => comp.IsDangerDay) ?? true)); } } @@ -144,9 +188,9 @@ namespace RJW_Menstruation else __result--; if ( - (PregnancyHelper.CanImpregnate(pawn, partner, props.sexType) && (partner.GetMenstruationComp()?.IsDangerDay ?? true)) + (PregnancyHelper.CanImpregnate(pawn, partner, props.sexType) && (partner.GetMenstruationComps()?.Any(comp => comp.IsDangerDay) ?? true)) || - (PregnancyHelper.CanImpregnate(partner, pawn, props.sexType) && (pawn.GetMenstruationComp()?.IsDangerDay ?? true))) + (PregnancyHelper.CanImpregnate(partner, pawn, props.sexType) && (pawn.GetMenstruationComps()?.Any(comp => comp.IsDangerDay) ?? true))) __result++; } } @@ -176,7 +220,7 @@ namespace RJW_Menstruation { __result *= (1f + GetNetFertility(fucker, fucked) / 40); } - else if(xxx.is_animal(fucker) && fucked.IsInEstrus(true) && PregnancyHelper.CanImpregnate(fucker, fucked)) + else if (xxx.is_animal(fucker) && fucked.IsInEstrus(true) && PregnancyHelper.CanImpregnate(fucker, fucked)) { __result *= 1.25f; } @@ -195,10 +239,11 @@ namespace RJW_Menstruation private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup)); public static IEnumerable Transpiler(IEnumerable instructions) { + if (MinimumFuckabilityToHookup == null) throw new System.InvalidOperationException("MinimumFuckabilityToHookup not found"); bool first_fuckability = true; - foreach(CodeInstruction instruction in instructions) + foreach (CodeInstruction instruction in instructions) { - if(instruction.LoadsField(MinimumFuckabilityToHookup)) + if (instruction.LoadsField(MinimumFuckabilityToHookup)) { // The first load will be for the estrus-haver considering a partner, the second for a pawn considering the estrus-haver yield return new CodeInstruction(first_fuckability ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1); @@ -230,14 +275,16 @@ namespace RJW_Menstruation private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup)); public static IEnumerable Transpiler(IEnumerable instructions) { + if (MinimumAttractivenessToHookup == null) throw new System.InvalidOperationException("MinimumAttractivenessToHookup not found"); + if (MinimumRelationshipToHookup == null) throw new System.InvalidOperationException("MinimumRelationshipToHookup not found"); LocalBuilder pawn_index = null; // Like in the last one, we switch the arguments around for the second load bool first_attractiveness = true; bool first_relationship = true; - foreach(CodeInstruction instruction in instructions) + foreach (CodeInstruction instruction in instructions) { // Get where the compiler decided to index the pawn at - if (pawn_index is null && instruction.opcode == OpCodes.Stloc_S) // the first stloc.s in the IL is the pawn being loaded out of the list + if (pawn_index == null && instruction.opcode == OpCodes.Stloc_S) // the first stloc.s in the IL is the pawn being loaded out of the list { // a future RJW or compiler update might change this, or maybe another mod's patch pawn_index = (LocalBuilder)instruction.operand; yield return instruction; @@ -252,7 +299,7 @@ namespace RJW_Menstruation yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(AttractivenessThreshold)); first_attractiveness = false; - } + } else if (instruction.LoadsField(MinimumRelationshipToHookup)) { if (pawn_index?.LocalType != typeof(Pawn)) @@ -269,6 +316,21 @@ namespace RJW_Menstruation } } + [HarmonyPatch(typeof(JobDriver_Sex), nameof(JobDriver_Sex.PlayCumSound))] + public static class Orgasm_Patch + { + public static void Postfix(JobDriver_Sex __instance) + { +#if false + Pawn pawn = __instance.pawn; + foreach (HediffComp_Menstruation comp in pawn.GetMenstruationComps()) + { + comp.CumIn(pawn, (comp.parent.Severity / 10) * Rand.Range(0.75f, 1.25f), pawn.Label, -5.0f, VariousDefOf.GirlCumFilth); + } +#endif + } + } + [HarmonyPatch(typeof(CompHediffBodyPart), nameof(CompHediffBodyPart.updatesize))] public static class Updatesize_Patch { diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj b/1.3/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj index 7efb672..198c10f 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj @@ -101,6 +101,7 @@ ..\..\..\..\..\rjw\1.3\Assemblies\RJW.dll False + ..\..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll @@ -158,7 +159,7 @@ 2.1.1 - runtime + runtime diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Recipe_Surgery.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Recipe_Surgery.cs index 89ed888..6a1f8b8 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Recipe_Surgery.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Recipe_Surgery.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; -using Verse; +using RimWorld; using rjw; +using System.Collections.Generic; +using Verse; namespace RJW_Menstruation @@ -23,7 +19,7 @@ namespace RJW_Menstruation BodyPartRecord part = Genital_Helper.get_breastsBPR(pawn); if (part != null) { - + if (pawn.GetBreastComp() != null) yield return part; } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Reflect.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Reflect.cs index 1289c0f..8df18e6 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Reflect.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Reflect.cs @@ -22,14 +22,14 @@ namespace RJW_Menstruation public static object GetPropertyValue(this Type type, string name) { BindingFlags flags = BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - PropertyInfo propertyInfo = type?.GetProperty(name,flags); + PropertyInfo propertyInfo = type?.GetProperty(name, flags); return propertyInfo?.GetValue(null); } public static object GetPropertyValue(this object obj, string name) { BindingFlags flags = BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - PropertyInfo propertyInfo = obj?.GetType().GetProperty(name,flags); + PropertyInfo propertyInfo = obj?.GetType().GetProperty(name, flags); return propertyInfo?.GetValue(obj); } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/TextureCache.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/TextureCache.cs index 937fdb9..f383986 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/TextureCache.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/TextureCache.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; +using UnityEngine; using Verse; -using UnityEngine; namespace RJW_Menstruation { diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Things.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Things.cs index 324f428..e427e0f 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Things.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Things.cs @@ -1,8 +1,7 @@ -using System; -using System.Xml; -using System.Collections.Generic; -using RimWorld; +using RimWorld; using rjw; +using System.Collections.Generic; +using System.Xml; using UnityEngine; using Verse; @@ -20,10 +19,7 @@ namespace RJW_Menstruation public HybridExtension GetHybridExtension(string race) { if (hybridExtension.NullOrEmpty()) return null; - else - { - return hybridExtension.Find(x => x.thingDef.defName.Equals(race)); - } + else return hybridExtension.Find(x => x.thingDef.defName.Equals(race)); } public PawnKindDef GetHybridWith(string race) @@ -67,21 +63,15 @@ namespace RJW_Menstruation { DirectXmlCrossRefLoader.RegisterObjectWantsCrossRef(this, "thingDef", xmlRoot.Name); XmlNodeList childNodes = xmlRoot.ChildNodes; - + if (childNodes.Count >= 1) foreach (XmlNode node in childNodes) { - #if DEBUG - Log.Message(xmlRoot.Name + "HybridInfo: " + node.Name + " " + node.InnerText); - #endif +#if DEBUG + Log.Message(xmlRoot.Name + "HybridInfo: " + node.Name + " " + node.InnerText); +#endif hybridInfo.Add(node.Name, ParseHelper.FromString(node.InnerText)); } - - - } - - - } public class HybridInformations : IExposable @@ -145,9 +135,6 @@ namespace RJW_Menstruation Scribe_Values.Look(ref thingDefName, "thingDefName"); Scribe_Collections.Look(ref hybridExtension, "hybridExtension", LookMode.Deep, new object[0]); } - - - } public class HybridExtensionExposable : HybridExtension, IExposable @@ -197,10 +184,6 @@ namespace RJW_Menstruation } } - - - - public class AbsorberModExtension : DefModExtension { public bool leakAfterDirty = false; @@ -222,14 +205,12 @@ namespace RJW_Menstruation public Color fluidColor = Color.white; - - public virtual void DirtyEffect() { } public virtual void WearEffect() { absorbedfluids += 0.1f; - if(dirty) wearhours++; + if (dirty) wearhours++; } public override Color DrawColorTwo => fluidColor; @@ -250,7 +231,7 @@ namespace RJW_Menstruation public override void WearEffect() { - if(dirty) wearhours++; + if (dirty) wearhours++; absorbedfluids += 0.5f; } @@ -299,13 +280,5 @@ namespace RJW_Menstruation color = value; } } - - - } - - - - - } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Translations.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Translations.cs index 5260ed4..6189613 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Translations.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Translations.cs @@ -11,7 +11,6 @@ namespace RJW_Menstruation public static readonly string Stage_Ovulatory = "Stage_Ovulatory".Translate(); public static readonly string Stage_Luteal = "Stage_Luteal".Translate(); public static readonly string Stage_Bleeding = "Stage_Bleeding".Translate(); - public static readonly string Stage_Fertilized = "Stage_Fertilized".Translate(); public static readonly string Stage_Pregnant = "Stage_Pregnant".Translate(); public static readonly string Stage_Recover = "Stage_Recover".Translate(); public static readonly string Stage_None = "Stage_None".Translate(); @@ -100,23 +99,23 @@ namespace RJW_Menstruation public static readonly string Option23_Label_1 = "Option23_Label_1".Translate(); public static readonly string Option23_Label_2 = "Option23_Label_2".Translate(); public static readonly string Option24_Label = "Option24_Label".Translate(); - public static readonly string Option24_Desc = "Option24_Desc".Translate(); + public static readonly string Option24_Desc = "Option24_Desc".Translate(); public static readonly string Option25_Label = "Option25_Label".Translate(); - public static readonly string Option25_Desc = "Option25_Desc".Translate(); + public static readonly string Option25_Desc = "Option25_Desc".Translate(); public static readonly string Option26_Label = "Option26_Label".Translate(); - public static readonly string Option26_Desc = "Option26_Desc".Translate(); + public static readonly string Option26_Desc = "Option26_Desc".Translate(); public static readonly string Option27_Label = "Option27_Label".Translate(); - public static readonly string Option27_Desc = "Option27_Desc".Translate(); + public static readonly string Option27_Desc = "Option27_Desc".Translate(); public static readonly string Option28_Label = "Option28_Label".Translate(); public static readonly string Option28_Tooltip = "Option28_Tooltip".Translate(); public static readonly string Option29_Label = "Option29_Label".Translate(); - public static readonly string Option29_Desc = "Option29_Desc".Translate(); + public static readonly string Option29_Desc = "Option29_Desc".Translate(); public static readonly string Option30_Label = "Option30_Label".Translate(); - public static readonly string Option30_Desc = "Option30_Desc".Translate(); + public static readonly string Option30_Desc = "Option30_Desc".Translate(); public static readonly string Option31_Label = "Option31_Label".Translate(); - public static readonly string Option31_Desc = "Option31_Desc".Translate(); + public static readonly string Option31_Desc = "Option31_Desc".Translate(); public static readonly string Option32_Label = "Option32_Label".Translate(); - public static readonly string Option32_Desc = "Option32_Desc".Translate(); + public static readonly string Option32_Desc = "Option32_Desc".Translate(); public static readonly string Option_EnableGatherCumGizmo_Label = "Option_EnableGatherCumGizmo_Label".Translate(); public static readonly string Option_EstrusOverride_Label = "Option_EstrusOverride_Label".Translate(); public static readonly string Option_EstrusOverride_Desc = "Option_EstrusOverride_Desc".Translate(); diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_HybridCustom.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_HybridCustom.cs index a0fbb49..4df0978 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_HybridCustom.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_HybridCustom.cs @@ -1,10 +1,7 @@ -using System; +using RimWorld; +using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; -using rjw; using UnityEngine; using Verse; using Verse.Sound; @@ -26,17 +23,11 @@ namespace RJW_Menstruation public void BuildRaceList() { raceList.Clear(); - if (!VariousDefOf.AllRaces.NullOrEmpty()) - foreach(ThingDef def in VariousDefOf.AllRaces) + if (!VariousDefOf.AllRaces.NullOrEmpty()) + foreach (ThingDef def in VariousDefOf.AllRaces) { - if (def.race != null) - { - if (Configurations.IsOverrideExist(def)) continue; - else - { - raceList.Add(new FloatMenuOption(def.label, delegate { AddHybridOverride(def);}, def.uiIcon, Color.white )); - } - } + if (def.race == null || Configurations.IsOverrideExist(def)) continue; + raceList.Add(new FloatMenuOption(def.label, delegate { AddHybridOverride(def); }, def.uiIcon, Color.white)); } raceList.SortBy(x => x.Label); } @@ -44,17 +35,15 @@ namespace RJW_Menstruation public void AddHybridOverride(ThingDef def) { FloatMenuOption option = raceList.FirstOrDefault(x => x.Label.Equals(def?.label)); - if (option != null) + if (option == null) return; + raceList.Remove(option); + if (Configurations.HybridOverride.NullOrEmpty()) { - raceList.Remove(option); - if (Configurations.HybridOverride.NullOrEmpty()) - { - Configurations.HybridOverride = new List(); - } - Configurations.HybridOverride.Add(new HybridInformations(def)); - Configurations.HybridOverride.SortBy(x => x.GetDef?.label ?? "Undefined"); + Configurations.HybridOverride = new List(); } - + Configurations.HybridOverride.Add(new HybridInformations(def)); + Configurations.HybridOverride.SortBy(x => x.GetDef?.label ?? "Undefined"); + } public override Vector2 InitialSize @@ -124,7 +113,7 @@ namespace RJW_Menstruation buttonRect.x -= 100; if (Widgets.ButtonText(buttonRect, "Undo")) { - var element = removeList.Last(); + HybridInformations element = removeList.Last(); Configurations.HybridOverride.Add(element); Configurations.HybridOverride.SortBy(x => x.GetDef?.label ?? "Undefined"); removeList.Remove(element); @@ -138,17 +127,17 @@ namespace RJW_Menstruation } - + Rect outRect = new Rect(inRect.x, inRect.y + 30f, inRect.width, inRect.height - 30f); - Rect mainRect = new Rect(inRect.x, inRect.y + 30f, inRect.width - 30f, Math.Max(24f*Configurations.HybridOverride?.Count() ?? 1,10f)); + Rect mainRect = new Rect(inRect.x, inRect.y + 30f, inRect.width - 30f, Math.Max(24f * Configurations.HybridOverride?.Count() ?? 1, 10f)); Listing_Standard listmain = new Listing_Standard(); - + Widgets.BeginScrollView(outRect, ref scroll, mainRect); listmain.Begin(mainRect); - if (!Configurations.HybridOverride.NullOrEmpty()) - foreach(HybridInformations extension in Configurations.HybridOverride) + if (!Configurations.HybridOverride.NullOrEmpty()) + foreach (HybridInformations extension in Configurations.HybridOverride) { - if (extension.GetDef != null) DoRow(listmain.GetRect(24f),extension); + if (extension.GetDef != null) DoRow(listmain.GetRect(24f), extension); } Widgets.EndScrollView(); listmain.End(); @@ -266,7 +255,7 @@ namespace RJW_Menstruation SoundDefOf.TabClose.PlayOneShotOnCamera(); Find.WindowStack.Add(new Dialog_EditHybrid(info)); } - + } @@ -279,18 +268,19 @@ namespace RJW_Menstruation protected void BuildRaceList() { raceList.Clear(); - if (!VariousDefOf.AllRaces.NullOrEmpty()) - foreach (ThingDef def in VariousDefOf.AllRaces) + if (VariousDefOf.AllRaces.NullOrEmpty()) return; + + foreach (ThingDef def in VariousDefOf.AllRaces) + { + if (def.race != null) { - if (def.race != null) + if (info.hybridExtension.Exists(x => x.DefName == def.defName)) continue; + else { - if (info.hybridExtension.Exists(x => x.DefName == def.defName)) continue; - else - { - raceList.Add(new FloatMenuOption(def.label, delegate { AddHybridInfo(def); }, Widgets.GetIconFor(def), Color.white)); - } + raceList.Add(new FloatMenuOption(def.label, delegate { AddHybridInfo(def); }, Widgets.GetIconFor(def), Color.white)); } } + } raceList.SortBy(x => x.Label); } @@ -320,11 +310,11 @@ namespace RJW_Menstruation buttonRect.x -= 100; if (Widgets.ButtonText(buttonRect, "Undo")) { - var element = removeList.Last(); + HybridExtensionExposable element = removeList.Last(); info.hybridExtension.Add(element); removeList.Remove(element); } - + foreach (HybridExtensionExposable element in removeList) { info.hybridExtension.Remove(element); @@ -333,7 +323,7 @@ namespace RJW_Menstruation float additionalHeight = 0f; - if (!info.hybridExtension.NullOrEmpty()) foreach(HybridExtensionExposable e in info.hybridExtension) + if (!info.hybridExtension.NullOrEmpty()) foreach (HybridExtensionExposable e in info.hybridExtension) { additionalHeight += (e.hybridInfo?.Count() ?? 1) * rowH; } @@ -356,7 +346,7 @@ namespace RJW_Menstruation } - + Widgets.EndScrollView(); listmain.End(); } @@ -376,7 +366,7 @@ namespace RJW_Menstruation if (Widgets.ButtonText(buttonRect, "Add")) { List list = new List(); - if (!VariousDefOf.AllRaces.NullOrEmpty()) foreach(ThingDef def in VariousDefOf.AllRaces) + if (!VariousDefOf.AllRaces.NullOrEmpty()) foreach (ThingDef def in VariousDefOf.AllRaces) { if (def.race != null) { @@ -392,7 +382,7 @@ namespace RJW_Menstruation list.SortBy(x => x.Label); Find.WindowStack.Add(new FloatMenu(list)); } - + } buttonRect.x -= 80f; @@ -403,18 +393,18 @@ namespace RJW_Menstruation if (!extension.hybridInfo.EnumerableNullOrEmpty()) { totalWeight = 0; - foreach(KeyValuePair element in extension.hybridInfo) + foreach (KeyValuePair element in extension.hybridInfo) { totalWeight += element.Value; } - + List keys = new List(extension.hybridInfo.Keys); foreach (string key in keys) { DoSubRow(sublist.GetRect(rowH), key, extension, removeelements); } } - if(!removeelements.NullOrEmpty()) foreach(string key in removeelements) + if (!removeelements.NullOrEmpty()) foreach (string key in removeelements) { extension.hybridInfo.Remove(key); } @@ -425,7 +415,7 @@ namespace RJW_Menstruation } - protected void DoSubRow(Rect rect, string key, HybridExtensionExposable extension , List removeelements) + protected void DoSubRow(Rect rect, string key, HybridExtensionExposable extension, List removeelements) { bool isPawnKind = false; int value = (int)extension.hybridInfo.TryGetValue(key); @@ -471,15 +461,15 @@ namespace RJW_Menstruation } label += ": " + key; Widgets.Label(rect, " - " + label); - Widgets.TextFieldNumeric(buttonRect, ref value, ref valuestr,0,9999999); + Widgets.TextFieldNumeric(buttonRect, ref value, ref valuestr, 0, 9999999); extension.hybridInfo.SetOrAdd(key, value); buttonRect.x -= 80f; Widgets.Label(buttonRect, String.Format("{0,0:P2}", value / totalWeight)); Widgets.DrawHighlightIfMouseover(rect); - TooltipHandler.TipRegion(rect, Translations.CustomHybrid_Tooltip(info.GetDef?.label ?? "Undefined", extension.GetDef?.label ?? "Undefined", label, String.Format("{0,0:0.########%}", value/totalWeight))); + TooltipHandler.TipRegion(rect, Translations.CustomHybrid_Tooltip(info.GetDef?.label ?? "Undefined", extension.GetDef?.label ?? "Undefined", label, String.Format("{0,0:0.########%}", value / totalWeight))); } - + } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs index 63d8537..7bbbfad 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using RimWorld; +using RimWorld; using rjw; +using System; +using System.Collections.Generic; using System.Linq; using UnityEngine; using Verse; @@ -92,7 +92,7 @@ namespace RJW_Menstruation int index = pawns.IndexOf(window.pawn); SoundDefOf.TabOpen.PlayOneShotOnCamera(); Pawn newpawn = pawns[(index + 1) % pawns.Count]; - window.ChangePawn(newpawn, newpawn.GetMenstruationComp()); + window.ChangePawn(newpawn, newpawn.GetFirstMenstruationComp()); } else if (window.pawn != pawn) { @@ -151,16 +151,15 @@ namespace RJW_Menstruation fontstyleleft.normal.textColor = Color.white; float preginfoheight = 0f; - bool pregnant = pawn.IsPregnant(); - Hediff hediff = PregnancyHelper.GetPregnancy(pawn); - if (pregnant && Utility.ShowFetusImage((Hediff_BasePregnancy)hediff)) + Hediff_BasePregnancy hediff = comp.Pregnancy; + if (hediff != null && Utility.ShowFetusImage(hediff)) { womb = comp.GetPregnancyIcon(hediff); if (hediff is Hediff_MultiplePregnancy m) { if (m.GestationProgress < 0.2f) cum = comp.GetCumIcon(); else cum = ContentFinder.Get(("Womb/Empty"), true); - Pawn fetus = pawn.GetFetus(); + Pawn fetus = comp.GetFetus(); if (fetus != null && Utility.ShowFetusInfo()) { string feinfo = m.GetBabyInfo(); @@ -188,7 +187,7 @@ namespace RJW_Menstruation { if (b.GestationProgress < 0.2f) cum = comp.GetCumIcon(); else cum = ContentFinder.Get(("Womb/Empty"), true); - Pawn fetus = pawn.GetFetus(); + Pawn fetus = comp.GetFetus(); if (fetus != null && Utility.ShowFetusInfo()) { preginfoheight = fontheight; @@ -230,7 +229,7 @@ namespace RJW_Menstruation if (pawn.story != null) GUI.Label(pawnLabel2Rect, pawn.ageTracker.AgeBiologicalYears + ", " + pawn.story.Title, fontstylecenter); GUI.color = Color.white; - + float wombrecth = 0; if (Configurations.DrawWombStatus) { @@ -249,7 +248,7 @@ namespace RJW_Menstruation } Rect wombInfoRect = new Rect(0f, mainRect.yMax - wombrecth - fontheight - 2, wombRectWidth, fontheight - 4f); - Rect progressRect = new Rect(wombInfoRect.x,wombInfoRect.yMax,wombRectWidth, 4f); + Rect progressRect = new Rect(wombInfoRect.x, wombInfoRect.yMax, wombRectWidth, 4f); buttonstyle.normal.textColor = Color.white; //boxstyle.normal.background = Texture2D.whiteTexture; buttonstyle.alignment = TextAnchor.MiddleLeft; @@ -286,7 +285,7 @@ namespace RJW_Menstruation cumlistRect = new Rect(pawnRectWidth, fontheight, 150f, mainRect.yMax - wombRectHeight - fontheight); } - Rect infoRect = new Rect(0, pawnRectHeight + 2*fontheight, pawnRectWidth, pawnRect.yMax + 2*fontheight - wombInfoRect.y); + Rect infoRect = new Rect(0, pawnRectHeight + 2 * fontheight, pawnRectWidth, pawnRect.yMax + 2 * fontheight - wombInfoRect.y); DrawInfos(infoRect); @@ -369,7 +368,7 @@ namespace RJW_Menstruation GUI.color = new Color(1.00f, 0.47f, 0.47f, 1); GUI.Box(rect, "", boxstyle); - + pawn.DrawBreastIcon(BreastIconRect, Mouse.IsOver(BreastIconRect) && Input.GetMouseButton(0)); @@ -388,11 +387,11 @@ namespace RJW_Menstruation float statvalue; const float height = 24f; statvalue = pawn.GetStatValue(xxx.sex_drive_stat); - FillableBarLabeled(lineRect, " " + xxx.sex_drive_stat.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue/2 ,TextureCache.SlaaneshTexture,Texture2D.blackTexture, xxx.sex_drive_stat.description); + FillableBarLabeled(lineRect, " " + xxx.sex_drive_stat.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue / 2, TextureCache.SlaaneshTexture, Texture2D.blackTexture, xxx.sex_drive_stat.description); lineRect.y += height; statvalue = pawn.GetStatValue(xxx.vulnerability_stat); - FillableBarLabeled(lineRect, " " + xxx.vulnerability_stat.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue/2, TextureCache.KhorneTexture,Texture2D.blackTexture, xxx.vulnerability_stat.description); + FillableBarLabeled(lineRect, " " + xxx.vulnerability_stat.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue / 2, TextureCache.KhorneTexture, Texture2D.blackTexture, xxx.vulnerability_stat.description); lineRect.y += height; statvalue = pawn.GetStatValue(xxx.sex_stat); @@ -409,27 +408,11 @@ namespace RJW_Menstruation statvalue = pawn.records.GetValue(xxx.CountOfBirthEgg); FillableBarLabeled(lineRect, " " + xxx.CountOfBirthEgg.LabelCap.CapitalizeFirst() + " " + statvalue, statvalue / 100, TextureCache.NurgleTexture, Texture2D.blackTexture, xxx.CountOfBirthEgg.description); - lineRect.y += height; - - statvalue = pawn.records.GetValue(xxx.CountOfWhore); - if (statvalue > 0) - { - FillableBarLabeled(lineRect, " " + xxx.CountOfWhore.LabelCap.CapitalizeFirst() + " " + statvalue, statvalue / 50, TextureCache.SlaaneshTexture, Texture2D.blackTexture, xxx.CountOfWhore.description); - statvalue = pawn.records.GetValue(xxx.EarnedMoneyByWhore); - lineRect.y += height; - FillableBarLabeled(lineRect, " " + VariousDefOf.RJW_EarnedMoneyByWhore.label.CapitalizeFirst() + " " + statvalue, statvalue / 10000, TextureCache.GhalmarazTexture, Texture2D.blackTexture); - - lineRect.y += height; - } - else - { - lineRect.y += height; - lineRect.y += height; - } + lineRect.y += height * 3; statvalue = Configurations.ImplantationChance * comp.ImplantFactor; float fertchance = comp.GetFertilityChance(); - FillableBarLabeled(lineRect, " " + xxx.reproduction.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue, TextureCache.FertilityTexture, Texture2D.blackTexture, Translations.FertilityDesc(String.Format("{0:0.##}", fertchance*100))); + FillableBarLabeled(lineRect, " " + xxx.reproduction.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue, TextureCache.FertilityTexture, Texture2D.blackTexture, Translations.FertilityDesc(String.Format("{0:0.##}", fertchance * 100))); Rect overayRect = new Rect(lineRect.x, lineRect.y, lineRect.width * Math.Min(1.0f, fertchance), lineRect.height); GUI.DrawTexture(overayRect, TextureCache.FertChanceTex); lineRect.y += height; @@ -437,7 +420,7 @@ namespace RJW_Menstruation private void FillableBarLabeled(Rect rect, string label, float fillPercent, Texture2D filltexture, Texture2D bgtexture, string tooltip = null) { - Widgets.FillableBar(rect, Math.Min(fillPercent,1.0f), filltexture, bgtexture, true); + Widgets.FillableBar(rect, Math.Min(fillPercent, 1.0f), filltexture, bgtexture, true); GUI.Label(rect, label, fontstyleleft); Widgets.DrawHighlightIfMouseover(rect); if (tooltip != null) TooltipHandler.TipRegion(rect, tooltip); diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Gizmo_Womb.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Gizmo_Womb.cs index 57f8dd1..7b60c02 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Gizmo_Womb.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Gizmo_Womb.cs @@ -37,7 +37,7 @@ namespace RJW_Menstruation Widgets.FillableBar(progressRect, comp.StageProgress, comp.GetStageTexture); } - + diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs index 095b740..38d40a3 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs @@ -1,13 +1,11 @@ using RimWorld; using rjw; using System; -using System.Linq; using System.Collections.Generic; +using System.Linq; using UnityEngine; using Verse; using Verse.Sound; -using System.Threading; -using System.Threading.Tasks; namespace RJW_Menstruation @@ -16,7 +14,7 @@ namespace RJW_Menstruation { public static Color blood = new Color(0.78f, 0, 0); //public static Color nippleblack = new Color(0.215f, 0.078f, 0); // 81,20,0 - public static ColorInt white = new ColorInt(255,255,255,255); + public static ColorInt white = new ColorInt(255, 255, 255, 255); @@ -49,10 +47,15 @@ namespace RJW_Menstruation public static class Utility { - public static System.Random random = new System.Random(Environment.TickCount); - - - + public static PawnKindDef GetRacesPawnKind(Pawn pawn) + { + if (pawn == null) return null; + if (pawn.kindDef?.race == pawn.def) return pawn.kindDef; + return VariousDefOf.AllKinds.Find(kind => kind.race == pawn.def && kind.defName.Contains("Colonist")) ?? + VariousDefOf.AllKinds.Find(kind => kind.race == pawn.def) ?? + pawn.def.race?.AnyPawnKind ?? + pawn.kindDef; + } public static float GetCumVolume(this Pawn pawn) { @@ -94,16 +97,13 @@ namespace RJW_Menstruation public static HediffComp_Breast GetBreastComp(this Pawn pawn) { - var hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn))?.FindAll((Hediff h) => h is Hediff_PartBaseNatural || h is Hediff_PartBaseArtifical); + List hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn))?.FindAll((Hediff h) => h is Hediff_PartBaseNatural || h is Hediff_PartBaseArtifical); HediffComp_Breast result; if (hedifflist.NullOrEmpty()) return null; - else + foreach (Hediff h in hedifflist) { - foreach(Hediff h in hedifflist) - { - result = h.TryGetComp(); - if (result != null) return result; - } + result = h.TryGetComp(); + if (result != null) return result; } return null; } @@ -125,66 +125,43 @@ namespace RJW_Menstruation public static bool HasMenstruationComp(this Pawn pawn) { - var hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll((Hediff h) => h.def.defName.ToLower().Contains("vagina")); - HediffComp_Menstruation result; - if (hedifflist.NullOrEmpty()) return false; - else - { - foreach (Hediff h in hedifflist) - { - result = h.TryGetComp(); - if (result != null) return true; - } - } - return false; + return pawn.GetMenstruationComps().Any(); } public static bool HasMenstruationComp(this Hediff hediff) { - if (hediff is Hediff_PartBaseNatural || hediff is Hediff_PartBaseArtifical) + if ((hediff is Hediff_PartBaseNatural || hediff is Hediff_PartBaseArtifical) && hediff.TryGetComp() != null) + return true; + else return false; + } + + + public static float GetFarthestPregnancyProgress(this Pawn pawn) + { + return pawn.health.hediffSet.GetHediffs().MaxBy(hediff => hediff.GestationProgress)?.GestationProgress ?? -1; + } + + public static float GetPregnancyProgress(this HediffComp_Menstruation comp) + { + if (comp.Pregnancy == null) return -1; + else return comp.Pregnancy.GestationProgress; + } + + public static Pawn GetFetus(this HediffComp_Menstruation comp) + { + if (comp.Pregnancy == null) return null; + if (!comp.Pregnancy.babies.NullOrEmpty()) return comp.Pregnancy.babies.First(); + else { - if (hediff.TryGetComp() != null) return true; + Log.Error("Baby not exist: baby was not created or removed. Remove pregnancy."); + comp.Pregnancy.Miscarry(); + return null; } - return false; } - - public static float GetPregnancyProgress(this Pawn pawn) + public static void DrawBreastIcon(this Pawn pawn, Rect rect, bool drawOrigin = false) { - Hediff hediff = PregnancyHelper.GetPregnancy(pawn); - if (hediff is Hediff_BasePregnancy h) - { - return h.GestationProgress; - } - return -1; - } - - public static Pawn GetFetus(this Pawn pawn) - { - Hediff hediff = PregnancyHelper.GetPregnancy(pawn); - if (hediff is Hediff_BasePregnancy h) - { - if (!h.babies.NullOrEmpty()) return h.babies.First(); - else - { - Log.Error("Baby not exist: baby was not created or removed. Remove pregnancy."); - pawn.health.RemoveHediff(hediff); - return null; - } - } - - - return null; - } - - public static Hediff_BasePregnancy GetRJWPregnancy(this Pawn pawn) - { - return (Hediff_BasePregnancy)pawn.health.hediffSet.hediffs.FirstOrDefault(x => x is Hediff_BasePregnancy); - } - - public static void DrawBreastIcon(this Pawn pawn, Rect rect , bool drawOrigin = false) - { - var hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("breast")); + Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("breast")); Texture2D breast, nipple, areola; if (hediff != null) { @@ -227,7 +204,7 @@ namespace RJW_Menstruation nippleicon = icon + "_Nipple0" + GetNippleIndex(nipplesize); areolaicon = icon + "_Areola0" + GetAreolaIndex(areolasize); - + breast = ContentFinder.Get(icon, false); areola = ContentFinder.Get(areolaicon, false); @@ -299,78 +276,75 @@ namespace RJW_Menstruation milkcomp = pawn.GetComp(); } - if (milkcomp != null) + if (milkcomp == null) return; + if (milkcomp is CompMilkable milkable) { - if (milkcomp is CompMilkable milkable) + bool active = (bool)milkcomp.GetPropertyValue("Active"); + if (active) { - bool active = (bool)milkcomp.GetPropertyValue("Active"); - if (active) - { - CompMilkable m = milkable; - res = Math.Max(m.Fullness, res); - Widgets.FillableBar(rect, Math.Min(res, 1.0f), TextureCache.MilkTexture, Texture2D.blackTexture, true); - DrawMilkBottle(rect, pawn, VariousDefOf.Job_LactateSelf, m.Fullness); - } + CompMilkable m = milkable; + res = Math.Max(m.Fullness, res); + Widgets.FillableBar(rect, Math.Min(res, 1.0f), TextureCache.MilkTexture, Texture2D.blackTexture, true); + DrawMilkBottle(rect, pawn, VariousDefOf.Job_LactateSelf, m.Fullness); } - else + } + else + { + bool active = (bool)milkcomp.GetPropertyValue("Active"); + if (active) { - bool active = (bool)milkcomp.GetPropertyValue("Active"); - if (active) - { - float fullness = (float)milkcomp.GetMemberValue("fullness"); - res = Math.Max(fullness, res); - Widgets.FillableBar(rect, Math.Min(res, 1.0f), TextureCache.MilkTexture, Texture2D.blackTexture, true); - DrawMilkBottle(rect, pawn, VariousDefOf.Job_LactateSelf_MC, fullness); - } + float fullness = (float)milkcomp.GetMemberValue("fullness"); + res = Math.Max(fullness, res); + Widgets.FillableBar(rect, Math.Min(res, 1.0f), TextureCache.MilkTexture, Texture2D.blackTexture, true); + DrawMilkBottle(rect, pawn, VariousDefOf.Job_LactateSelf_MC, fullness); } } } - public static void DrawMilkBottle(Rect rect, Pawn pawn, JobDef milkjob,float fullness) + public static void DrawMilkBottle(Rect rect, Pawn pawn, JobDef milkjob, float fullness) { Texture2D texture; Rect buttonrect = new Rect(rect.x, rect.y, rect.height, rect.height); - if (fullness > 0.0f) - { - if (fullness < 0.3f) texture = ContentFinder.Get("Milk/Milkbottle_Small", false); - else if (fullness < 0.7f) texture = ContentFinder.Get("Milk/Milkbottle_Medium", false); - else texture = ContentFinder.Get("Milk/Milkbottle_Large", false); - GUIContent icon = new GUIContent(texture); - GUIStyle style = GUIStyle.none; - style.normal.background = texture; - string tooltip = Translations.Button_MilkTooltip; + if (fullness <= 0.0f) return; - TooltipHandler.TipRegion(buttonrect, tooltip); - if (GUI.Button(buttonrect, icon, style)) + if (fullness < 0.3f) texture = ContentFinder.Get("Milk/Milkbottle_Small", false); + else if (fullness < 0.7f) texture = ContentFinder.Get("Milk/Milkbottle_Medium", false); + else texture = ContentFinder.Get("Milk/Milkbottle_Large", false); + GUIContent icon = new GUIContent(texture); + GUIStyle style = GUIStyle.none; + style.normal.background = texture; + string tooltip = Translations.Button_MilkTooltip; + + TooltipHandler.TipRegion(buttonrect, tooltip); + if (GUI.Button(buttonrect, icon, style)) + { + if (fullness < 0.1f + || !pawn.IsColonistPlayerControlled + || pawn.Downed) SoundDefOf.ClickReject.PlayOneShotOnCamera(); + else { - if (fullness < 0.1f - || !pawn.IsColonistPlayerControlled - || pawn.Downed) SoundDefOf.ClickReject.PlayOneShotOnCamera(); - else - { - SoundDefOf.Click.PlayOneShotOnCamera(); - pawn.jobs.TryTakeOrderedJob(new Verse.AI.Job(milkjob, pawn)); - } + SoundDefOf.Click.PlayOneShotOnCamera(); + pawn.jobs.TryTakeOrderedJob(new Verse.AI.Job(milkjob, pawn)); } - Widgets.DrawHighlightIfMouseover(buttonrect); } + Widgets.DrawHighlightIfMouseover(buttonrect); } public static string GetVaginaLabel(this Pawn pawn) { - var hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)).Find((Hediff h) => h.def.defName.ToLower().Contains("vagina")); + Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)).Find(h => VariousDefOf.AllVaginas.Contains(h.def)); return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")" + "\n" + xxx.CountOfSex.LabelCap.CapitalizeFirst() + ": " + pawn.records.GetAsInt(xxx.CountOfSex); } public static string GetAnusLabel(this Pawn pawn) { - var hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("anus")); + Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("anus")); if (hediff != null) return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")"; else return ""; } public static string GetBreastLabel(this Pawn pawn) { - var hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("breast")); + Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("breast")); if (hediff != null) return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")"; else return ""; } @@ -422,25 +396,20 @@ namespace RJW_Menstruation { Pawn res = pawn.GetFather(); if (res != null) return res; - else - { - - res = pawn.relations?.GetFirstDirectRelationPawn(PawnRelationDefOf.Parent, x => x != mother) ?? null; - if (res == null) res = pawn.relations?.GetFirstDirectRelationPawn(VariousDefOf.Relation_birthgiver, x => x != mother) ?? null; - return res; - } + else res = pawn.relations?.GetFirstDirectRelationPawn(PawnRelationDefOf.Parent, x => x != mother) ?? null; + return res; } public static float RandGaussianLike(float min, float max, int iterations = 3) { - double res = 0; + float res = 0; for (int i = 0; i < iterations; i++) { - res += random.NextDouble(); + res += Rand.Value; } res /= iterations; - return (float)res*(max-min) + min; + return res * (max - min) + min; } @@ -449,7 +418,7 @@ namespace RJW_Menstruation float tmult = Mathf.Pow(1 - t, num); return tmult * a + (1 - tmult) * b; } - + public static float VariationRange(this float num, float variant) { return num * Rand.Range(1.0f - variant, 1.0f + variant); @@ -457,20 +426,7 @@ namespace RJW_Menstruation public static bool ShouldShowWombGizmo(this Pawn pawn) { - - if (Configurations.EnableWombIcon) - { - if (!pawn.IsAnimal()) - { - return true; - } - else if (Configurations.EnableAnimalCycle) - { - return true; - } - } - return false; + return Configurations.EnableWombIcon && (!pawn.IsAnimal() || Configurations.EnableAnimalCycle); } - } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs index 40ac6df..141d5c5 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs @@ -1,8 +1,8 @@ using RimWorld; using rjw; -using System.Linq; using System; using System.Collections.Generic; +using System.Linq; using Verse; namespace RJW_Menstruation @@ -11,6 +11,7 @@ namespace RJW_Menstruation { public static readonly ThingDef CumFilth = DefDatabase.GetNamed("FilthCum"); + public static readonly ThingDef GirlCumFilth = DefDatabase.GetNamed("FilthGirlCum"); public static readonly ThingDef Tampon = DefDatabase.GetNamed("Absorber_Tampon"); public static readonly ThingDef Tampon_Dirty = DefDatabase.GetNamed("Absorber_Tampon_Dirty"); public static readonly ThingDef FilthMixture = DefDatabase.GetNamed("FilthMixture"); @@ -22,9 +23,6 @@ namespace RJW_Menstruation public static readonly HediffDef Hediff_Estrus_Concealed = DefDatabase.GetNamed("Hediff_Estrus_Concealed"); public static readonly HediffDef Hediff_ASA = DefDatabase.GetNamed("Hediff_ASA"); public static readonly StatDef MaxAbsorbable = DefDatabase.GetNamed("MaxAbsorbable"); - // Obsolete, kept for compatibility for now - public static readonly PawnRelationDef Relation_birthgiver = DefDatabase.AllDefs.FirstOrDefault(d => d.defName == "RJW_Sire"); - public static readonly PawnRelationDef Relation_spawn = DefDatabase.AllDefs.FirstOrDefault(d => d.defName == "RJW_Pup"); public static readonly NeedDef SexNeed = DefDatabase.GetNamed("Sex"); public static readonly JobDef VaginaWashing = DefDatabase.GetNamed("VaginaWashing"); public static readonly JobDef Job_LactateSelf = DefDatabase.GetNamed("LactateSelf"); @@ -42,28 +40,26 @@ namespace RJW_Menstruation public static readonly ThoughtDef UnwantedPregnancyMild = DefDatabase.GetNamed("UnwantedPregnancyMild"); public static readonly ThoughtDef TookContraceptivePill = DefDatabase.GetNamed("TookContraceptivePill"); public static readonly ThoughtDef HateTookContraceptivePill = DefDatabase.GetNamed("HateTookContraceptivePill"); - public static readonly HediffDef_PartBase Vagina = DefDatabase.GetNamed("Vagina"); - public static readonly CompProperties_Menstruation VaginaCompProperties = (CompProperties_Menstruation)Vagina.comps.FirstOrDefault(x => x is CompProperties_Menstruation); + public static readonly CompProperties_Menstruation HumanVaginaCompProperties = (CompProperties_Menstruation)Genital_Helper.average_vagina.comps.FirstOrDefault(x => x is CompProperties_Menstruation); public static readonly KeyBindingDef OpenStatusWindowKey = DefDatabase.GetNamed("OpenStatusWindow"); - public static readonly PawnColumnDef RJW_EarnedMoneyByWhore = DefDatabase.GetNamed("RJW_EarnedMoneyByWhore"); public static readonly RecordDef AmountofCreampied = DefDatabase.GetNamed("AmountofCreampied"); public static readonly RecordDef AmountofFertilizedEggs = DefDatabase.GetNamed("AmountofFertilizedEggs"); + public static readonly TaleDef TaleCameInside = DefDatabase.GetNamed("CameInside"); private static List allraces = null; private static List allkinds = null; + private static HashSet allvaginas = null; public static List AllRaces { get { - if (allraces == null) - { - - List allThings = DefDatabase.AllDefsListForReading; - allraces = allThings.FindAll(x => x.race != null && x.race.IsFlesh); - } + if (allraces != null) return allraces; + + List allThings = DefDatabase.AllDefsListForReading; + allraces = allThings.FindAll(x => x.race != null && x.race.IsFlesh); return allraces; } } @@ -71,16 +67,37 @@ namespace RJW_Menstruation { get { - if (allkinds == null) - { - List allKinds = DefDatabase.AllDefsListForReading; - allkinds = allKinds.FindAll(x => x.race != null); - } + if (allkinds != null) return allkinds; + + List allKinds = DefDatabase.AllDefsListForReading; + allkinds = allKinds.FindAll(x => x.race != null); return allkinds; } } + public static HashSet AllVaginas + { + get + { + if (allvaginas != null) return allvaginas; + allvaginas = new HashSet(); - + List allHediffs = DefDatabase.AllDefsListForReading; + foreach(HediffDef hediffDef in allHediffs) + { + if (hediffDef.comps.NullOrEmpty()) continue; + foreach (HediffCompProperties comp in hediffDef.comps) + { + if (comp.compClass == typeof(HediffComp_Menstruation) || comp.compClass.IsSubclassOf(typeof(HediffComp_Menstruation))) + { + allvaginas.Add(hediffDef); + break; + } + } + } + + return allvaginas; + } + } // Defs from Milkable Colonists public static readonly HediffDef Hediff_Lactating_Drug = DefDatabase.GetNamedSilentFail("Lactating_Drug"); @@ -88,12 +105,5 @@ namespace RJW_Menstruation public static readonly HediffDef Hediff_Lactating_Permanent = DefDatabase.GetNamedSilentFail("Lactating_Permanent"); public static readonly HediffDef Hediff_Heavy_Lactating_Permanent = DefDatabase.GetNamedSilentFail("Heavy_Lactating_Permanent"); public static readonly JobDef Job_LactateSelf_MC = DefDatabase.GetNamedSilentFail("LactateSelf_MC"); - - - - - - - } } diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/GatheredCumMixture.cs b/1.3/source/RJW_Menstruation/SexperienceModule/GatheredCumMixture.cs index 1600282..b40ef61 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/GatheredCumMixture.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/GatheredCumMixture.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Verse; -using RimWorld; -using RJWSexperience; -using RJW_Menstruation; +using System.Collections.Generic; using UnityEngine; +using Verse; namespace RJW_Menstruation.Sexperience { @@ -34,8 +27,8 @@ namespace RJW_Menstruation.Sexperience if (res && other is GatheredCumMixture mixture) { GatheredCumMixture othercum = mixture; - cumColor = Colors.CMYKLerp(cumColor,othercum.cumColor,count/(amount+count)); - if (!othercum.ingredients.NullOrEmpty()) for (int i=0; i MakeNewToils() { - - HediffComp_Menstruation Comp = pawn.GetMenstruationComp(); //this.FailOn(delegate //{ // return !(Comp.TotalCumPercent > 0.001); @@ -38,23 +31,26 @@ namespace RJW_Menstruation.Sexperience { initAction = delegate () { - if (Comp.TotalCumPercent > 0.001) - { - CumMixture mixture = Comp.MixtureOut(RJWSexperience.VariousDefOf.GatheredCum, 0.5f); - float amount = mixture.Volume; - if (mixture.ispurecum) + bool anyExcreted = false; + foreach (HediffComp_Menstruation comp in pawn.GetMenstruationComps()) + if (comp.TotalCumPercent > 0.001) { - Bucket.AddCum(amount); + CumMixture mixture = comp.MixtureOut(RJWSexperience.VariousDefOf.GatheredCum, 0.5f); + float amount = mixture.Volume; + if (mixture.ispurecum) + { + Bucket.AddCum(amount); + } + else + { + GatheredCumMixture cummixture = (GatheredCumMixture)ThingMaker.MakeThing(VariousDefOf.GatheredCumMixture); + cummixture.InitwithCum(mixture); + Bucket.AddCum(amount, cummixture); + } + anyExcreted = true; } - else - { - GatheredCumMixture cummixture = (GatheredCumMixture)ThingMaker.MakeThing(VariousDefOf.GatheredCumMixture); - cummixture.InitwithCum(mixture); - Bucket.AddCum(amount, cummixture); - } - } - else ReadyForNextToil(); - if (Comp.TotalCumPercent > 0.001) JumpToToil(excreting); + if (!anyExcreted) ReadyForNextToil(); + if (pawn.GetMenstruationComps().Any(c => c.TotalCumPercent > 0.001)) JumpToToil(excreting); } }; diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/GetGizmos.cs b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/GetGizmos.cs index e96e9d1..392b18d 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/GetGizmos.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/GetGizmos.cs @@ -1,14 +1,7 @@ -using System; +using HarmonyLib; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Verse; -using RimWorld; using UnityEngine; -using RJWSexperience; -using rjw; -using HarmonyLib; +using Verse; namespace RJW_Menstruation.Sexperience @@ -32,7 +25,7 @@ namespace RJW_Menstruation.Sexperience defaultLabel = label, defaultDesc = description, icon = icon, - isActive = delegate() { return comp.DoCleanWomb; }, + isActive = delegate () { return comp.DoCleanWomb; }, toggleAction = delegate { comp.DoCleanWomb = !comp.DoCleanWomb; diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Harmony.cs b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Harmony.cs index db23583..5fd4777 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Harmony.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Harmony.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using HarmonyLib; +using HarmonyLib; using System.Reflection; using Verse; @@ -14,7 +9,7 @@ namespace RJW_Menstruation.Sexperience { static First() { - var har = new Harmony("RJW_Menstruation.Sexperience"); + Harmony har = new Harmony("RJW_Menstruation.Sexperience"); har.PatchAll(Assembly.GetExecutingAssembly()); } } diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Menstruation_Patch.cs b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Menstruation_Patch.cs index b3df374..3a65a43 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Menstruation_Patch.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Menstruation_Patch.cs @@ -1,16 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RJW_Menstruation; -using HarmonyLib; -using rjw; +using HarmonyLib; using RimWorld; +using UnityEngine; using Verse; using Verse.Sound; -using UnityEngine; -using RJWSexperience; namespace RJW_Menstruation.Sexperience { @@ -24,7 +16,7 @@ namespace RJW_Menstruation.Sexperience Rect buttonRect = new Rect(rect.x, rect.yMax - ICONSIZE, ICONSIZE, ICONSIZE).ContractedBy(2f); if (__instance.Comp.DoCleanWomb) { - Widgets.DrawTextureFitted(buttonRect,TextureCache.GatherCum_Bucket,1.0f); + Widgets.DrawTextureFitted(buttonRect, TextureCache.GatherCum_Bucket, 1.0f); TooltipHandler.TipRegion(buttonRect, Translations.Dialog_DoCleanWomb_Tooltip); } else diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Pawn_Patch.cs b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Pawn_Patch.cs index 68648c4..e979368 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Pawn_Patch.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/Pawn_Patch.cs @@ -1,14 +1,10 @@ -using System; +using HarmonyLib; +using RimWorld; +using RJWSexperience; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Verse; -using Verse.AI; -using RimWorld; -using HarmonyLib; using UnityEngine; -using RJWSexperience; +using Verse; namespace RJW_Menstruation.Sexperience { @@ -17,25 +13,20 @@ namespace RJW_Menstruation.Sexperience { public static void Postfix(Vector3 clickPos, Pawn pawn, List opts) { - var targets = GenUI.TargetsAt(clickPos, TargetingParameters.ForBuilding()); - HediffComp_Menstruation comp = pawn.GetMenstruationComp(); + IEnumerable targets = GenUI.TargetsAt(clickPos, TargetingParameters.ForBuilding()); - if (comp != null && comp.TotalCumPercent > 0.001f) - foreach (LocalTargetInfo t in targets) - { - if (t.Thing is Building building) + if (pawn.GetMenstruationComps().Any(comp => comp.TotalCumPercent > 0.001f)) + foreach (LocalTargetInfo t in targets) { - if (building is Building_CumBucket) + if (t.Thing is Building building) { - opts.AddDistinct(MakeMenu(pawn, building)); - break; + if (building is Building_CumBucket) + { + opts.AddDistinct(MakeMenu(pawn, building)); + break; + } } } - } - - - - } public static FloatMenuOption MakeMenu(Pawn pawn, LocalTargetInfo target) diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/RJW_Patch.cs b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/RJW_Patch.cs index 9a344a4..b8d536e 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/Patch/RJW_Patch.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/Patch/RJW_Patch.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; +using HarmonyLib; +using rjw; +using RJWSexperience; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; using Verse; using Verse.AI; -using rjw; -using RJW_Menstruation; -using HarmonyLib; -using RJWSexperience; namespace RJW_Menstruation.Sexperience { @@ -20,8 +14,7 @@ namespace RJW_Menstruation.Sexperience [HarmonyPatch("HasJobOnThing")] public static bool HasJobOnThing(Pawn pawn, ref bool __result) { - HediffComp_Menstruation comp = pawn.GetMenstruationComp(); - if (comp != null && comp.DoCleanWomb && comp.TotalCumPercent > 0.001f && pawn.Map.listerBuildings.ColonistsHaveBuilding(VariousDefOf.CumBucket)) + if (pawn.GetMenstruationComps().Any(comp => comp.DoCleanWomb && comp.TotalCumPercent > 0.001f) && pawn.Map.listerBuildings.ColonistsHaveBuilding(VariousDefOf.CumBucket)) { __result = true; return false; @@ -33,8 +26,7 @@ namespace RJW_Menstruation.Sexperience [HarmonyPatch("JobOnThing")] public static void JobOnThing(Pawn pawn, ref Job __result) { - HediffComp_Menstruation comp = pawn.GetMenstruationComp(); - if (comp != null && comp.DoCleanWomb && comp.TotalCumPercent > 0.001f) + if (pawn.GetMenstruationComps().Any(comp => comp.DoCleanWomb && comp.TotalCumPercent > 0.001f)) { Building_CumBucket bucket = pawn.FindClosestBucket(); @@ -43,10 +35,6 @@ namespace RJW_Menstruation.Sexperience __result = JobMaker.MakeJob(VariousDefOf.VaginaWashingwithBucket, null, bucket, bucket.Position); } } - } - - - } } diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/Properties/AssemblyInfo.cs b/1.3/source/RJW_Menstruation/SexperienceModule/Properties/AssemblyInfo.cs index fa02342..a2226aa 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/Properties/AssemblyInfo.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 diff --git a/1.3/source/RJW_Menstruation/SexperienceModule/VariousDefOf.cs b/1.3/source/RJW_Menstruation/SexperienceModule/VariousDefOf.cs index fef502c..617eb47 100644 --- a/1.3/source/RJW_Menstruation/SexperienceModule/VariousDefOf.cs +++ b/1.3/source/RJW_Menstruation/SexperienceModule/VariousDefOf.cs @@ -1,9 +1,4 @@ -using RimWorld; -using rjw; -using System.Linq; -using System; -using System.Collections.Generic; -using Verse; +using Verse; namespace RJW_Menstruation.Sexperience { diff --git a/About/Manifest.xml b/About/Manifest.xml index 21cc793..d56ea34 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,7 +1,7 @@ RJW Menstruation - 1.0.6.6 + 1.0.7.0 diff --git a/changelogs.txt b/changelogs.txt index 9134a88..f2d3030 100644 --- a/changelogs.txt +++ b/changelogs.txt @@ -1,3 +1,25 @@ +Version 1.0.7.0 + - Not save compatible with previous versions. Expect glitches and many red errors if you try. However, things should stabilize eventually. + - Designed for RJW 5.0.0, but should work with previous versions. + + - Support for multiple vaginas, including each having a separate pregnancy. + - More reliably generate a baby's race correctly when using pawnkind diversification mods. + - Overhauled many things under the hood. + - Cycle randomization completely redone. Everyone now has a (hidden) cycle speed and cycle variability. + - Ovary initialization redone. All pawns now get a total number of eggs based on their age and racial properties. + - Coming inside someone with an IUD will give the same total amount of fluid as without, just at a lower fertility. + - The chance to fertilize has been changed to an exponential curve instead of a linear one. This will increase the chances of pregnancy at low amounts of semen and slightly reduce it at high amounts. + - Semen now has a fertility percentage instead of "fertile volume". + - The exact time between fertilization and implantation has been adjusted. + - Removing a vagina will end any pregnancy it has in progress. Please wait until the baby is born first. + - Your colonists can create artwork of someone being born. + - They can also create artwork of someone coming inside someone else. + + - Default values changed to account for the new math. The new defaults will have the same odds of pregnancy with a 10ml ejaculation at ovulation (in a human) as before: + - Fertilization chance from 10%/mL to 15% + - Cum decay from 30%/hour to 15% + - Fertility decay from 20%/hour to 5% + Version 1.0.6.6 - Ovipostors add on average 1.5x as much cum to a womb than before. - The womb tick timing is now more consistent across a save and load, and also spread out across pawns.