diff --git a/1.4/Assemblies/RJW_Menstruation.dll b/1.4/Assemblies/RJW_Menstruation.dll index 1e66766..ce34bd7 100644 Binary files a/1.4/Assemblies/RJW_Menstruation.dll and b/1.4/Assemblies/RJW_Menstruation.dll differ diff --git a/1.4/Patches/Hediffs_PrivateParts.xml b/1.4/Patches/Hediffs_PrivateParts.xml index 58bd529..6b6a570 100644 --- a/1.4/Patches/Hediffs_PrivateParts.xml +++ b/1.4/Patches/Hediffs_PrivateParts.xml @@ -144,5 +144,11 @@ - + + + + + + + \ No newline at end of file diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs index 3b4ab9c..d09eba9 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs @@ -110,6 +110,9 @@ namespace RJW_Menstruation else return base.ShouldBeInEstrus(); } - protected override float RandomOvulationChance => 0; + protected override float RandomOvulationChance() + { + return 0; + } } } diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs index f7793e1..f970ff8 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs @@ -127,6 +127,7 @@ namespace RJW_Menstruation protected float implantationChanceCache = -1.0f; protected int opcache = -1; protected float antisperm = 0.0f; + protected float? originvagsize = null; // RJW pregnancy, or Biotech pregnancy/labor/laborpushing protected Hediff pregnancy = null; @@ -178,8 +179,7 @@ namespace RJW_Menstruation public float HoursBetweenSimulations => (float)TickInterval / GenDate.TicksPerHour; - public Hediff Pregnancy - { + public Hediff Pregnancy { get { if (pregnancy == null) return null; @@ -255,7 +255,7 @@ namespace RJW_Menstruation public float TotalCum { - get => cums?.Sum(cum => cum.Volume) ?? 0; + get => cums?.Sum(cum => cum.Volume) ?? 0; } public float TotalFertCum { @@ -322,7 +322,6 @@ namespace RJW_Menstruation // Implant factor will be based solely on pawn age, plus any rollover from ovulation chance float factor = 1.0f; StatDefOf.Fertility.GetStatPart()?.TransformValue(StatRequest.For(Pawn), ref factor); - if (factor <= 0.0f) return 0.0f; if (OvulationChance > 1.0f) factor *= OvulationChance; return Props.baseImplantationChanceFactor * FertilityModifier * factor; } @@ -357,7 +356,7 @@ namespace RJW_Menstruation { if (cums.NullOrEmpty()) yield return Translations.Info_noCum; else foreach (Cum cum in cums) - yield return string.Format("{0}: {1:0.##}ml", cum.notcum ? cum.notcumLabel : cum.pawn?.Label, cum.Volume); + yield return string.Format("{0}: {1:0.##}ml", cum.notcum ? cum.notcumLabel : cum.pawn?.Label, cum.Volume); } } public Color GetCumMixtureColor @@ -564,6 +563,19 @@ namespace RJW_Menstruation } } + public float OriginVagSize + { + get + { + if (originvagsize == null) + { + originvagsize = parent.Severity; + } + return originvagsize ?? 0.1f; + } + set => originvagsize = value; + } + public int CurStageIntervalTicks { get => currentIntervalTicks; @@ -596,7 +608,7 @@ namespace RJW_Menstruation else if (Pawn.story?.bodyType == BodyTypeDefOf.Female) discoveryTime = 0.35f; // Estimated; there's no way to get the exact value after the fact without writing it into the save float lutealProgressWhenImplanted = Math.Min(0.5f, maxImplantDelayHours / (Props.lutealIntervalDays * GenDate.HoursPerDay)); - + return GenMath.LerpDouble(0, discoveryTime, lutealProgressWhenImplanted, 1.0f, pregnancy.Severity); } } @@ -644,6 +656,7 @@ namespace RJW_Menstruation Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true); Scribe_Values.Look(ref eggstack, "eggstack", 0); Scribe_Values.Look(ref estrusflag, "estrusflag", false); + Scribe_Values.Look(ref originvagsize, "originvagsize", originvagsize, true); Scribe_Values.Look(ref DoCleanWomb, "DoCleanWomb", false); Scribe_References.Look(ref pregnancy, "pregnancy"); if (Scribe.mode == LoadSaveMode.PostLoadInit) @@ -666,10 +679,12 @@ namespace RJW_Menstruation ovulationFactor = 1f; noBleeding = false; opcache = -1; - - if (Pawn.genes == null || !ModsConfig.BiotechActive) return; - foreach (MenstruationModExtension extension in Pawn.genes.GenesListForReading.Select(gene => gene.def.GetModExtension()).Where(ext => ext != null)) + + if (Pawn.genes == null || !ModsConfig.BiotechActive) return; + foreach (MenstruationModExtension extension in Pawn.genes.GenesListForReading.Select(gene => gene.def.GetModExtension())) { + if (extension == null) continue; + eggLifeSpanTicks = (int)(eggLifeSpanTicks * extension.eggLifeTimeFactor); if (extension.alwaysEstrus) estrusLevel = EstrusLevel.Visible; else if (extension.neverEstrus) estrusLevel = EstrusLevel.None; @@ -706,7 +721,7 @@ namespace RJW_Menstruation { if (Pawn.IsHashIntervalTick(recalculateTickInterval)) TickInterval = -1; // Every so often, force TickInterval to be recalculated in case the pawn's status changed. if (!Pawn.IsHashIntervalTick(TickInterval)) return; - + if (!ShouldSimulate()) return; // Initialize immediately if needed, but if there's an error, then don't spam it every tick @@ -715,7 +730,7 @@ namespace RJW_Menstruation Log.Warning($"{Pawn}'s womb is ticking, but was not initialized first"); Initialize(); } - + if (initError) Log.Warning($"Attempting to process {Pawn}'s womb uninitialized"); if (Pregnancy != null && curStage != Stage.Pregnant) @@ -725,7 +740,7 @@ namespace RJW_Menstruation } BeforeSimulator(); - + if (ShouldBeInfertile()) GoNextStage(Stage.Infertile); switch (curStage) { @@ -802,7 +817,7 @@ namespace RJW_Menstruation tip.Append(": "); tip.Append(GetCurStageLabel); string fertInfo = GetFertilizingInfo; - if (CurrentVisibleStage == Stage.Luteal && fertInfo.Length > 0) + if(CurrentVisibleStage == Stage.Luteal && fertInfo.Length > 0) { tip.AppendLine(); tip.Append(fertInfo); @@ -813,7 +828,7 @@ namespace RJW_Menstruation protected virtual int TicksToNextStage() { - return Math.Max(0, (currentIntervalTicks - curStageTicks) / Configurations.CycleAcceleration); + return Math.Max(0,(currentIntervalTicks - curStageTicks) / Configurations.CycleAcceleration); } public override string CompDebugString() @@ -1158,7 +1173,7 @@ namespace RJW_Menstruation if (cycleSpeed < 0f) cycleSpeed = Utility.RandGaussianLike(0.8f, 1.2f); if (cycleVariability < 0f) cycleVariability = MenstruationUtility.RandomVariabilityPercent(); - + InitOvary(); if (currentIntervalTicks < 0) @@ -1346,7 +1361,7 @@ namespace RJW_Menstruation //float fertFailChancePerHour = Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor); //float fertFailChancePerInterval = Mathf.Pow(fertFailChancePerHour, (float)TickInterval / GenDate.TicksPerHour); float fertFailChancePerInterval = Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor * HoursBetweenSimulations); - + if (Rand.Chance(fertFailChancePerInterval)) return null; Pawn.records.AddTo(VariousDefOf.AmountofFertilizedEggs, 1); @@ -1476,7 +1491,7 @@ namespace RJW_Menstruation float interspeciesFactor = InterspeciesImplantFactor(egg.fertilizer); float implantChance = Configurations.ImplantationChance * ImplantChance * interspeciesFactor; Log.Message($"Fertilized egg of {Pawn} failed to implant (chance {implantChance.ToStringPercent()}, " + - (interspeciesFactor < 1.0f ? $"interspecies factor {interspeciesFactor.ToStringPercent()}, " : "") + + (interspeciesFactor < 1.0f ? $"interspecies factor {interspeciesFactor.ToStringPercent()}, " : "" ) + $"father {egg.fertilizer})"); } deadeggs.Add(egg); @@ -1562,6 +1577,9 @@ namespace RJW_Menstruation return amount; } + + + protected void EggDecay() { HashSet deadeggs = new HashSet(); @@ -1638,7 +1656,7 @@ namespace RJW_Menstruation eggnum = 1f; } eggnum *= ovulationFactor; - int toOvulate = Math.Max(1, (int)eggnum + eggstack); + int toOvulate = (int)eggnum + eggstack; int ovulated = 0; for (int i = 0; i < toOvulate; i++) @@ -1649,7 +1667,7 @@ namespace RJW_Menstruation } ovarypower -= ovulated; eggstack = 0; - if (Configurations.Debug && ovulated < toOvulate) + if (Configurations.Debug && ovulated != toOvulate) Log.Message($"{Pawn} ovulated {ovulated}/{toOvulate} eggs ({OvulationChance.ToStringPercent()} chance)"); GoNextStage(Stage.Luteal); @@ -1796,10 +1814,10 @@ namespace RJW_Menstruation } else pawnMemories.TryGainMemory(VariousDefOf.CameInsideFFetish, cummer); } - else if (Pawn.relations.OpinionOf(cummer) <= -5) - pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideF, cummer); - else if (Pawn.IsInEstrus() && Pawn.relations.OpinionOf(cummer) < RJWHookupSettings.MinimumRelationshipToHookup) - pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideFEstrus, cummer); + else if (Pawn.relations.OpinionOf(cummer) <= -5) + pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideF, cummer); + else if (Pawn.IsInEstrus() && Pawn.relations.OpinionOf(cummer) < RJWHookupSettings.MinimumRelationshipToHookup) + pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideFEstrus, cummer); else if (!Pawn.relations.DirectRelationExists(PawnRelationDefOf.Spouse, cummer) && !Pawn.relations.DirectRelationExists(PawnRelationDefOf.Fiance, cummer)) { if (Pawn.health.capacities.GetLevel(xxx.reproduction) < 0.50f) pawnMemories.TryGainMemory(VariousDefOf.CameInsideFLowFert, cummer); @@ -1896,13 +1914,16 @@ namespace RJW_Menstruation else return Rand.Range(0.6f, 1.0f); } - protected virtual float RandomOvulationChance => (float)Props.ovulationIntervalHours / GenDate.HoursPerDay; + protected virtual float RandomOvulationChance() + { + return (float)Props.ovulationIntervalHours / GenDate.HoursPerDay; + } protected Stage RandomStage() { Stage stage = Rand.ElementByWeight( Stage.Follicular, Props.follicularIntervalDays - Props.bleedingIntervalDays, - Stage.Ovulatory, RandomOvulationChance, + Stage.Ovulatory, RandomOvulationChance(), Stage.Luteal, Props.lutealIntervalDays, Stage.Bleeding, Props.bleedingIntervalDays); @@ -2014,6 +2035,28 @@ namespace RJW_Menstruation public class HediffComp_Anus : HediffComp { - public CompProperties_Anus Props => (CompProperties_Anus)props; + protected float? originanussize; + + public float OriginAnusSize + { + get + { + if (originanussize == null) + { + originanussize = parent.Severity; + } + return originanussize ?? 0.1f; + } + } + + public override void CompExposeData() + { + base.CompExposeData(); + Scribe_Values.Look(ref originanussize, "originanussize", originanussize, true); + } + + public override void CompPostTick(ref float severityAdjustment) + { + } } } diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs index e663ec2..eb344c3 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs @@ -29,14 +29,14 @@ namespace RJW_Menstruation protected override void InitializeExtraValues() { - base.InitializeExtraValues(); + base.InitializeExtraValues(); if (averageCycleIntervalTicks < 0) { averageCycleIntervalTicks = (int)(Props.cycleIntervalDays.RandomInRange * GenDate.TicksPerDay / cycleSpeed); if (ticksToNextCycle < -50000) ticksToNextCycle = Rand.Range(0, averageCycleIntervalTicks); // Make the cutoff halfway into cycle, just to be sure there isn't a double-cycle the first time - if ((curStage == Stage.Follicular || curStage == Stage.Ovulatory || curStage == Stage.Luteal || curStage == Stage.Bleeding) + if ((curStage == Stage.Follicular || curStage == Stage.Luteal || curStage == Stage.Bleeding) && (averageCycleIntervalTicks - ticksToNextCycle) / 2 >= GenDate.TicksPerDay * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed) GoNextStage(Stage.Anestrus); } diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs index 2092d1f..ac5a51d 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs @@ -141,7 +141,7 @@ namespace RJW_Menstruation else if (gestationProgress < 0.8f) icon = fetustex + "04"; else icon = fetustex + "05"; - return TryGetTwinsIcon(icon, babycount) ?? ContentFinder.Get(icon, true); + return TryGetTwinsIcon(icon, babycount) ?? ContentFinder.Get((icon), true); } public static Texture2D TryGetTwinsIcon(string path, int babycount) @@ -160,7 +160,7 @@ namespace RJW_Menstruation List insectEggs = new List(); comp.Pawn.health.hediffSet.GetHediffs(ref insectEggs); - if (insectEggs?.Sum(hediff => hediff.eggssize) > 1.0f) return null; // same logic as "Stuffed" in GetInsectEggedIcon + if (!insectEggs.NullOrEmpty() && insectEggs.Sum(hediff => hediff.eggssize) > 1.0f) return null; // same logic as "Stuffed" in GetInsectEggedIcon string icon = comp.WombTex; float cumpercent = comp.TotalCumPercent; @@ -183,7 +183,7 @@ namespace RJW_Menstruation else if (cumpercent < 0.89f) icon += "_Cum_15"; else if (cumpercent < 0.95f) icon += "_Cum_16"; else icon += "_Cum_17"; - Texture2D cumtex = ContentFinder.Get(icon, true); + Texture2D cumtex = ContentFinder.Get((icon), true); return cumtex; } public static Texture2D GetInsectEggedIcon(this HediffComp_Menstruation comp) @@ -306,13 +306,15 @@ namespace RJW_Menstruation } - public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp) + public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp, bool drawOrigin = false) { Hediff hediff = comp?.parent; if (hediff == null) return ContentFinder.Get("Genitals/Vagina00", true); //HediffComp_Menstruation comp = hediff.GetMenstruationComp(); string icon; - float severity = hediff.Severity; + float severity; + if (drawOrigin) severity = comp.OriginVagSize; + else severity = hediff.Severity; if (comp != null) icon = comp.VagTex; else icon = "Genitals/Vagina"; @@ -329,18 +331,30 @@ namespace RJW_Menstruation else if (severity < 1.01f) icon += "10"; //cavernous else icon += "11"; //abyssal - return ContentFinder.Get(icon, true); + return ContentFinder.Get((icon), true); } - public static Texture2D GetAnalIcon(this Pawn pawn) + public static Texture2D GetAnalIcon(this Pawn pawn, bool drawOrigin = false) { Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ?? pawn.health.hediffSet.hediffs.FirstOrDefault(h => h.def.defName.ToLower().Contains("anus")); - if (hediff == null) return ContentFinder.Get("Genitals/Anal00", true); - - string icon = ((CompProperties_Anus)hediff.GetAnusComp()?.props)?.analTex ?? "Genitals/Anal"; - float severity = hediff.Severity; + if (hediff == null) return ContentFinder.Get(("Genitals/Anal00"), 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 + { + 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 @@ -348,7 +362,7 @@ namespace RJW_Menstruation else if (severity < 1.01f) icon += "04"; //cavernous else icon += "05"; //abyssal - return ContentFinder.Get(icon, true); + return ContentFinder.Get((icon), true); } public static float GestationHours(this Hediff hediff) @@ -439,7 +453,7 @@ namespace RJW_Menstruation if (precept != null) return true; else return pawn.IsBreeder() || - pawn.HasImpregnationFetish(); + pawn.HasImpregnationFetish(); } public static float DamagePants(this Pawn pawn, float fluidAmount) diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs index c95454a..99670b6 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs @@ -225,7 +225,9 @@ namespace RJW_Menstruation bool newHasStats = !DirtyDef.equippedStatOffsets.NullOrEmpty(); def = DirtyDef; dirty = true; - Wearer.outfits?.forcedHandler?.SetForced(this, false); + OutfitForcedHandler forcedHandler = Wearer.outfits?.forcedHandler; + if (forcedHandler?.IsForced(this) ?? false) + forcedHandler.SetForced(this, false); if (oldHasStats || newHasStats) Wearer.health.capacities.Notify_CapacityLevelsDirty(); Wearer.apparel.Notify_ApparelChanged(); @@ -272,7 +274,7 @@ namespace RJW_Menstruation public override void DirtyEffect(int tickInterval) { - if (wearTicks > MinHrstoDirtyEffect * GenDate.TicksPerHour && Rand.MTBEventOccurs(100.0f, GenDate.TicksPerHour, tickInterval) && !(Wearer.apparel?.IsLocked(this) ?? false)) + if (wearTicks > MinHrstoDirtyEffect * GenDate.TicksPerHour && Rand.MTBEventOccurs(100.0f, GenDate.TicksPerHour, tickInterval) && !Wearer.apparel.IsLocked(this)) { Wearer.health.AddHediff(HediffDefOf.WoundInfection, Genital_Helper.get_genitalsBPR(Wearer)); } diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs index 0affda5..0448aac 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs @@ -388,9 +388,10 @@ namespace RJW_Menstruation Rect genitalIconRect = new Rect(rect.x, rect.y + fontheight, genitalRectWidth, genitalRectHeight); Rect genitalVaginaLabelRect = new Rect(rect.x, rect.y + 10f, genitalRectWidth, fontheight); Rect genitalAnusLabelRect = new Rect(rect.x, rect.y + fontheight + genitalRectHeight, genitalRectWidth, fontheight); + bool showOrigin = Mouse.IsOver(genitalIconRect) && Input.GetMouseButton(0); - vagina = pawn.GetGenitalIcon(comp); - anal = pawn.GetAnalIcon(); + vagina = pawn.GetGenitalIcon(comp, showOrigin); + anal = pawn.GetAnalIcon(showOrigin); GUI.color = new Color(1.00f, 0.47f, 0.47f, 1); GUI.Box(rect, "", boxstyle); GUI.color = Utility.SafeSkinColor(pawn); diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs index a3fdf4c..c956137 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs @@ -58,8 +58,9 @@ namespace RJW_Menstruation get { if (allraces != null) return allraces; - allraces = DefDatabase.AllDefsListForReading.Where(thingdef => thingdef.race?.IsFlesh ?? false).ToList(); + List allThings = DefDatabase.AllDefsListForReading; + allraces = allThings.FindAll(x => x.race != null && x.race.IsFlesh); return allraces; } } @@ -68,8 +69,9 @@ namespace RJW_Menstruation get { if (allkinds != null) return allkinds; - allkinds = DefDatabase.AllDefsListForReading.Where(pawnkinddef => pawnkinddef.race != null).ToList(); + List allKinds = DefDatabase.AllDefsListForReading; + allkinds = allKinds.FindAll(x => x.race != null); return allkinds; } } diff --git a/About/About.xml b/About/About.xml index c4c11a0..9c10224 100644 --- a/About/About.xml +++ b/About/About.xml @@ -1,9 +1,7 @@ - rjw.menstruation RJW Menstruation Cycle lutepickle - https://gitgud.io/lutepickle/rjw_menstruation/
  • 1.2
  • 1.3
  • @@ -30,17 +28,13 @@
  • Abraxas.RJW.RaceSupport
  • rjw.milk.humanoid
  • - - -
  • conit.thebirdsandthebees
  • -
    -
    + rjw.menstruation Adds menstruation mechanics to vaginas: Wombs cycle between follicular, luteal, and bleeding phases Tracks eggs ovulated and cum in wombs to determine pregnancy Womb icon and status window -Estrus and pheromone effects +Estrus effects Race-specific fetus images for many vanilla animals Pregnancies from multiple eggs and different fathers Identical siblings