diff --git a/1.4/Assemblies/RJW_Menstruation.dll b/1.4/Assemblies/RJW_Menstruation.dll index 3ed15f2..3d3fb88 100644 Binary files a/1.4/Assemblies/RJW_Menstruation.dll and b/1.4/Assemblies/RJW_Menstruation.dll differ diff --git a/1.4/Languages/English/Keyed/RJW_Menstruation.xml b/1.4/Languages/English/Keyed/RJW_Menstruation.xml index a1c65b3..18611bd 100644 --- a/1.4/Languages/English/Keyed/RJW_Menstruation.xml +++ b/1.4/Languages/English/Keyed/RJW_Menstruation.xml @@ -56,6 +56,12 @@ Cum will lose fertility by this amount every hour This value affects fertilization chance indirectly. Cycle acceleration Accelerate menstruation cycle This can cause early menopause and infertility. Setting this lower than x12 is recommended. Rimworld's timescale: x6(default) + Colonist update interval + How often the womb of each of your colonists, prisoners, and slaves update. Lowering this will improve accuracy, increasing this can improve performance. + Non-colonist update interval + How often the womb of humans you don't control update. Lowering this will improve accuracy, increasing this can improve performance. + Animal update interval + How often the womb of animals update. Lowering this will improve accuracy, increasing this can improve performance. Debug Show debug information. Womb status diff --git a/1.4/MilkModule/Assemblies/MilkModule.dll b/1.4/MilkModule/Assemblies/MilkModule.dll index c56319f..a9bde84 100644 Binary files a/1.4/MilkModule/Assemblies/MilkModule.dll and b/1.4/MilkModule/Assemblies/MilkModule.dll differ diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs index d450c4d..25d8ce1 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs @@ -1,4 +1,5 @@ -using rjw; +using RimWorld; +using rjw; using System; using System.Collections.Generic; using UnityEngine; @@ -17,6 +18,9 @@ namespace RJW_Menstruation public const float CumFertilityDecayRatioDefault = 0.05f; public const int CumFertilityDecayRatioAdjustDefault = 50; public const int CycleAccelerationDefault = 6; + public const int ColonistTickIntervalDefault = 2500; // 1 hour + public const int NonColonistTickIntervalDefault = 2500; + public const int AnimalTickIntervalDefault = 2500; public const float EnzygoticTwinsChanceDefault = 0.002f; public const int EnzygoticTwinsChanceAdjustDefault = 2; public const int MaxEnzygoticTwinsDefault = 9; @@ -41,6 +45,9 @@ namespace RJW_Menstruation public static float CumFertilityDecayRatio = CumFertilityDecayRatioDefault; public static int CumFertilityDecayRatioAdjust = CumFertilityDecayRatioAdjustDefault; public static int CycleAcceleration = CycleAccelerationDefault; + public static int ColonistTickInterval = ColonistTickIntervalDefault; + public static int NonColonistTickInterval = NonColonistTickIntervalDefault; + public static int AnimalTickInterval = AnimalTickIntervalDefault; public static bool EnableWombIcon = true; public static bool EnableDraftedIcon = true; public static bool EnableAnimalCycle = false; @@ -85,6 +92,9 @@ namespace RJW_Menstruation EnableGatherCumGizmo = true; EnableAnimalCycle = false; CycleAcceleration = CycleAccelerationDefault; + ColonistTickInterval = ColonistTickIntervalDefault; + NonColonistTickInterval = NonColonistTickIntervalDefault; + AnimalTickInterval = AnimalTickIntervalDefault; EstrusOverridesHookupSettings = false; EstrusFuckabilityToHookup = RJWHookupSettings.MinimumFuckabilityToHookup; EstrusAttractivenessToHookup = RJWHookupSettings.MinimumAttractivenessToHookup; @@ -188,6 +198,9 @@ namespace RJW_Menstruation Scribe_Values.Look(ref CumFertilityDecayRatioAdjust, "CumFertilityDecayRatioAdjust", CumFertilityDecayRatioAdjust, true); Scribe_Values.Look(ref CumFertilityDecayRatio, "CumFertilityDecayRatio", CumFertilityDecayRatio, true); Scribe_Values.Look(ref CycleAcceleration, "CycleAcceleration", CycleAcceleration, true); + Scribe_Values.Look(ref ColonistTickInterval, "ColonistTickInterval", ColonistTickInterval, true); + Scribe_Values.Look(ref NonColonistTickInterval, "NonColonistTickInterval", NonColonistTickInterval, true); + Scribe_Values.Look(ref AnimalTickInterval, "AnimalTickInterval", AnimalTickInterval, true); Scribe_Values.Look(ref EnableWombIcon, "EnableWombIcon", EnableWombIcon, true); Scribe_Values.Look(ref EnableDraftedIcon, "EnableDraftedIcon", EnableDraftedIcon, true); Scribe_Values.Look(ref EnableAnimalCycle, "EnableAnimalCycle", EnableAnimalCycle, true); @@ -274,8 +287,9 @@ namespace RJW_Menstruation public override void DoSettingsWindowContents(Rect inRect) { Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f); - float mainRectHeight = 30f + + float mainRectHeight = 126f + (Configurations.EnableWombIcon || Configurations.EnableButtonInHT ? 400f : 0f) + + (Configurations.EnableAnimalCycle ? 48f : 0f) + (Configurations.EstrusOverridesHookupSettings ? 144f : 0f) + (Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy ? (Configurations.EnableEnzygoticTwins ? 175f : 75f) : 0f) + (Configurations.PregnancySource == Configurations.PregnancyType.Biotech ? 75f : 0f) + @@ -403,11 +417,11 @@ namespace RJW_Menstruation string estimatedlifespan; if (semenlifespan < 0) { - estimatedlifespan = String.Format(": Infinite", semenlifespan); + estimatedlifespan = string.Format(": Infinite", semenlifespan); } else { - estimatedlifespan = String.Format(": {0:0}h", semenlifespan); + estimatedlifespan = string.Format(": {0:0}h", semenlifespan); } listmain.LabelDouble(Translations.Option6_Label + " " + Configurations.CumFertilityDecayRatio * 100 + "%", Translations.EstimatedCumLifespan + estimatedlifespan, Translations.Option6_Desc); Configurations.CumFertilityDecayRatioAdjust = (int)listmain.Slider(Configurations.CumFertilityDecayRatioAdjust, 0, 1000); @@ -416,6 +430,20 @@ namespace RJW_Menstruation listmain.Label(Translations.Option7_Label + " x" + Configurations.CycleAcceleration, -1, Translations.Option7_Desc); Configurations.CycleAcceleration = (int)listmain.Slider(Configurations.CycleAcceleration, 1, 50); + Adjust = Configurations.ColonistTickInterval / 25; + listmain.LabelDouble(Translations.Option_ColonistUpdateInterval_Label, GenDate.ToStringTicksToPeriod(Configurations.ColonistTickInterval), Translations.Option_ColonistUpdateInterval_Desc); + Configurations.ColonistTickInterval = (int)listmain.Slider(Adjust, 0, 400) * 25; + + Adjust = Configurations.NonColonistTickInterval / 25; + listmain.LabelDouble(Translations.Option_NonColonistUpdateInterval_Label, GenDate.ToStringTicksToPeriod(Configurations.NonColonistTickInterval), Translations.Option_NonColonistUpdateInterval_Desc); + Configurations.NonColonistTickInterval = (int)listmain.Slider(Adjust, 0, 400) * 25; + + if(Configurations.EnableAnimalCycle) + { + Adjust = Configurations.AnimalTickInterval / 25; + listmain.LabelDouble(Translations.Option_AnimalUpdateInterval_Label, GenDate.ToStringTicksToPeriod(Configurations.AnimalTickInterval), Translations.Option_AnimalUpdateInterval_Desc); + Configurations.AnimalTickInterval = (int)listmain.Slider(Adjust, 0, 400) * 25; + } float var2 = EstimatedBleedingAmountPerHour; float var1 = Math.Max(EstimatedBleedingAmount, var2); diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Cum.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Cum.cs index c1f9931..a51bdc9 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Cum.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Cum.cs @@ -205,8 +205,10 @@ namespace RJW_Menstruation { // comp is used for Hydrogen's RJW Muscle Injury float totalleak = volume; - volume *= Math.Max(0, (1 - (Configurations.CumDecayRatio * (1 - DecayResist)) * leakfactor)); - fertility *= Math.Max(0, 1 - (Configurations.CumFertilityDecayRatio * (1 - DecayResist) + antisperm)); + float decayPerInterval = 1 - Mathf.Pow(1 - Configurations.CumDecayRatio, comp.TickInterval / GenDate.TicksPerHour); + float fertilityDecayPerInterval = 1 - Mathf.Pow(Configurations.CumFertilityDecayRatio, comp.TickInterval / GenDate.TicksPerHour); + volume *= Math.Max(0, 1 - decayPerInterval * (1 - DecayResist) * leakfactor); + fertility *= Math.Max(0, 1 - (fertilityDecayPerInterval * (1 - DecayResist) + antisperm)); CutMinor(); totalleak -= volume; return totalleak; 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 15e013b..0bea073 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 @@ -70,7 +70,7 @@ namespace RJW_Menstruation case Stage.Ovulatory: return true; case Stage.Luteal: - return IsEggExist && curStageHrs < EggLifespanHours; + return IsEggExist && curStageTicks < EggLifespanTicks; default: return false; } @@ -84,11 +84,11 @@ namespace RJW_Menstruation switch (curStage) { case Stage.Follicular: - return curStageHrs > currentIntervalHours - Props.estrusDaysBeforeOvulation * 24; + return curStageTicks > currentIntervalTicks - Props.estrusDaysBeforeOvulation * GenDate.TicksPerDay; case Stage.Ovulatory: return true; case Stage.Luteal: - return IsEggExist && curStageHrs < EggLifespanHours; + return IsEggExist && curStageTicks < EggLifespanTicks; default: return false; } 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 78e7a77..7024462 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 @@ -29,6 +29,7 @@ namespace RJW_Menstruation public float baseImplantationChanceFactor; public float basefertilizationChanceFactor; public int follicularIntervalDays = 14; //before ovulation including beginning of bleeding + public int ovulationIntervalHours = 12; //between the end of follicular and the egg emerging 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 @@ -63,17 +64,16 @@ namespace RJW_Menstruation public class HediffComp_Menstruation : HediffComp { const float minmakefilthvalue = 1.0f; - //const int ovarypowerthreshold = 72; - - const int tickInterval = GenDate.TicksPerHour; - const int maxImplantDelayHours = 30 * 24; - const int minImplantAgeHours = 3 * 24; + const int maxImplantDelayHours = 30 * GenDate.HoursPerDay; + const int minImplantAgeHours = 3 * GenDate.HoursPerDay; const float pulloutSuccessRate = 0.8f; const float fetishPulloutSuccessModifier = 0.25f; public CompProperties_Menstruation Props; public Stage curStage = Stage.Follicular; - public int curStageHrs = 0; + public int curStageTicks = 0; // Actual number of ticks equals this / cycleAcceleration + private int tickInterval = -1; + const int recalculateTickInterval = GenDate.TicksPerDay; public bool loaded = false; public bool initError = false; public int ovarypower = -100000; @@ -114,7 +114,7 @@ namespace RJW_Menstruation protected List eggs; protected float cycleSpeed = -1; protected float cycleVariability = -1; - protected int currentIntervalHours = -1; + protected int currentIntervalTicks = -1; // Actual number of ticks equals this / cycleAcceleration protected float crampPain = -1; protected Need sexNeed = null; protected string customwombtex = null; @@ -126,7 +126,7 @@ namespace RJW_Menstruation // RJW pregnancy, or Biotech pregnancy/labor/laborpushing protected Hediff pregnancy = null; - protected int eggLifeSpanHours = 48; + protected int eggLifeSpanTicks = 2 * GenDate.TicksPerDay; protected EstrusLevel estrusLevel = EstrusLevel.Visible; protected float ovulationFactor = 1f; protected bool noBleeding = false; @@ -155,6 +155,21 @@ namespace RJW_Menstruation new CurvePoint(1.0f,0.5f) }; + public int TickInterval + { + get + { + if (tickInterval <= 0) + { + if (Pawn.IsAnimal()) tickInterval = Configurations.AnimalTickInterval; + else if (Pawn.IsColonist || Pawn.IsPrisonerOfColony || Pawn.IsSlaveOfColony) tickInterval = Configurations.ColonistTickInterval; + else tickInterval = Configurations.NonColonistTickInterval; + if (tickInterval <= 0) tickInterval = 1; + } + return tickInterval; + } + } + public Hediff Pregnancy { get { @@ -480,12 +495,12 @@ namespace RJW_Menstruation /// /// returns fertstage. if not fertilized returns -1 /// - public int IsFertilized + public int EggFertilizedTime { get { if (eggs?.All(egg => !egg.fertilized) ?? true) return -1; - return eggs.Max(egg => egg.fertstage); + return eggs.Max(egg => egg.ticksSinceFertilization); } } public IEnumerable GetCummersAndFertilizers() @@ -502,9 +517,9 @@ namespace RJW_Menstruation get => !eggs.NullOrEmpty(); } - public int EggLifespanHours + public int EggLifespanTicks { - get => eggLifeSpanHours; + get => eggLifeSpanTicks; } public virtual bool IsDangerDay @@ -516,11 +531,11 @@ namespace RJW_Menstruation switch (curStage) { case Stage.Follicular: - return curStageHrs > 0.7f * currentIntervalHours; + return curStageTicks > 0.7f * currentIntervalTicks; case Stage.Ovulatory: return true; case Stage.Luteal: - return curStageHrs < EggLifespanHours; + return curStageTicks < EggLifespanTicks; default: return false; } @@ -559,16 +574,16 @@ namespace RJW_Menstruation set => originvagsize = value; } - public float CurStageIntervalHours + public int CurStageIntervalTicks { - get => currentIntervalHours; + get => currentIntervalTicks; } public float StageProgress { get { - if (pregnancy == null) return Mathf.Clamp01(curStageHrs / CurStageIntervalHours); + if (pregnancy == null) return Mathf.Clamp01((float)curStageTicks / currentIntervalTicks); bool is_discovered = false; switch (pregnancy) { @@ -590,7 +605,7 @@ namespace RJW_Menstruation if (Pawn.story?.bodyType == BodyTypeDefOf.Thin) discoveryTime = 0.25f; 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 * 24)); + float lutealProgressWhenImplanted = Math.Min(0.5f, maxImplantDelayHours / (Props.lutealIntervalDays * GenDate.HoursPerDay)); return GenMath.LerpDouble(0, discoveryTime, lutealProgressWhenImplanted, 1.0f, pregnancy.Severity); } @@ -608,13 +623,23 @@ namespace RJW_Menstruation public override void CompExposeData() { base.CompExposeData(); + if (Scribe.mode == LoadSaveMode.LoadingVars) + { + int curStageHrs = -1; + int currentIntervalHours = -1; + Scribe_Values.Look(ref curStageHrs, "curStageHrs", curStageHrs, true); + Scribe_Values.Look(ref currentIntervalHours, "currentIntervalHours", currentIntervalHours, true); + if (curStageHrs >= 0) curStageTicks = curStageHrs * GenDate.TicksPerHour; + if (currentIntervalHours >= 0) currentIntervalTicks = currentIntervalHours * GenDate.TicksPerHour; + } + Scribe_Collections.Look(ref cums, saveDestroyedThings: true, label: "cums", lookMode: LookMode.Deep, ctorArgs: new object[0]); 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 curStageTicks, "curStageTicks", curStageTicks, 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 currentIntervalTicks, "currentIntervalTicks", currentIntervalTicks, 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); @@ -635,16 +660,16 @@ namespace RJW_Menstruation public void Notify_UpdatedGenes() { - eggLifeSpanHours = Props.eggLifespanDays * 24; + eggLifeSpanTicks = Props.eggLifespanDays * GenDate.TicksPerDay; estrusLevel = Props.concealedEstrus ? EstrusLevel.Concealed : EstrusLevel.Visible; ovulationFactor = 1f; noBleeding = false; if (Pawn.genes == null || !ModsConfig.BiotechActive) return; - if (Pawn.genes.HasGene(VariousDefOf.ShortEggLifetime)) eggLifeSpanHours = eggLifeSpanHours * 3 / 4; - else if (Pawn.genes.HasGene(VariousDefOf.DoubleEggLifetime)) eggLifeSpanHours *= 2; - else if (Pawn.genes.HasGene(VariousDefOf.QuadEggLifetime)) eggLifeSpanHours *= 4; + if (Pawn.genes.HasGene(VariousDefOf.ShortEggLifetime)) eggLifeSpanTicks = eggLifeSpanTicks * 3 / 4; + else if (Pawn.genes.HasGene(VariousDefOf.DoubleEggLifetime)) eggLifeSpanTicks *= 2; + else if (Pawn.genes.HasGene(VariousDefOf.QuadEggLifetime)) eggLifeSpanTicks *= 4; if (Pawn.genes.HasGene(VariousDefOf.NeverEstrus)) estrusLevel = EstrusLevel.None; else if (Pawn.genes.HasGene(VariousDefOf.FullEstrus)) estrusLevel = EstrusLevel.Visible; @@ -688,7 +713,8 @@ namespace RJW_Menstruation Initialize(); } - if (!Pawn.IsHashIntervalTick(tickInterval)) return; + 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 (initError) Log.Warning($"Attempting to process {Pawn}'s womb uninitialized"); @@ -784,9 +810,9 @@ namespace RJW_Menstruation } } - protected virtual int HoursToNextStage() + protected virtual int TicksToNextStage() { - return Math.Max(0,(currentIntervalHours - curStageHrs) / Configurations.CycleAcceleration); + return Math.Max(0,(currentIntervalTicks - curStageTicks) / Configurations.CycleAcceleration); } public override string CompDebugString() @@ -794,7 +820,7 @@ namespace RJW_Menstruation if (curStage == Stage.None || curStage == Stage.Infertile || curStage == Stage.Pregnant) return base.CompDebugString(); StringBuilder debugString = new StringBuilder(); debugString.Append($"Time to next state: "); - debugString.Append(GenDate.ToStringTicksToPeriod(HoursToNextStage() * GenDate.TicksPerHour)); + debugString.Append(GenDate.ToStringTicksToPeriod(TicksToNextStage())); return debugString.ToString(); } @@ -805,11 +831,7 @@ namespace RJW_Menstruation /// public Cum GetNotCum(string notcumlabel) { - if (!cums.NullOrEmpty()) foreach (Cum cum in cums) - { - if (cum.notcum && cum.notcumLabel.Equals(notcumlabel)) return cum; - } - return null; + return cums?.Find(cum => cum.notcum && cum.notcumLabel.Equals(notcumlabel)); } /// @@ -825,17 +847,17 @@ namespace RJW_Menstruation /// /// Inject pawn's cum into womb /// - /// + /// /// /// /// - public void CumIn(Pawn pawn, float volume, float fertility = 1.0f, bool precum = false) + public void CumIn(Pawn cummer, float volume, float fertility = 1.0f, bool precum = false) { if (volume <= 0) return; - if (!precum && fertility > 0 && IsDangerDay && pawn.relations.GetPregnancyApproachForPartner(Pawn) == PregnancyApproach.AvoidPregnancy) + if (!precum && fertility > 0 && IsDangerDay && cummer.relations.GetPregnancyApproachForPartner(Pawn) == PregnancyApproach.AvoidPregnancy) { float successChance = pulloutSuccessRate; - if (pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish)) successChance *= fetishPulloutSuccessModifier; + if (cummer.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish)) successChance *= fetishPulloutSuccessModifier; if (Pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish)) successChance *= fetishPulloutSuccessModifier; if (Rand.Chance(successChance)) return; } @@ -848,14 +870,14 @@ namespace RJW_Menstruation bool merged = false; if (!cums.NullOrEmpty()) foreach (Cum cum in cums) { - if (cum.pawn.Equals(pawn)) + if (cum.pawn.Equals(cummer)) { cum.MergeWithCum(volume, fertility); merged = true; } cum.DismishForce(cumoutrate); } - if (!merged) cums.Add(new Cum(pawn, volume * (1 - cumoutrate), fertility)); + if (!merged) cums.Add(new Cum(cummer, volume * (1 - cumoutrate), fertility)); } else { @@ -863,20 +885,20 @@ namespace RJW_Menstruation bool merged = false; if (!cums.NullOrEmpty()) foreach (Cum cum in cums) { - if (cum.pawn.Equals(pawn)) + if (cum.pawn.Equals(cummer)) { cum.MergeWithCum(volume, fertility); merged = true; } } - if (!merged) cums.Add(new Cum(pawn, volume, fertility)); + if (!merged) cums.Add(new Cum(cummer, volume, fertility)); } cumd = TotalCumPercent - cumd; if (!precum) { Pawn.records.AddTo(VariousDefOf.AmountofCreampied, volume); - AfterCumIn(pawn); + AfterCumIn(cummer); AfterFluidIn(cumd); } } @@ -884,12 +906,12 @@ namespace RJW_Menstruation /// /// Inject pawn's fluid into womb /// - /// + /// /// /// /// /// - public void CumIn(Pawn pawn, float volume, string notcumlabel, float decayresist = 0, ThingDef filthdef = null) + public void CumIn(Pawn cummer, float volume, string notcumlabel, float decayresist = 0, ThingDef filthdef = null) { if (volume <= 0) return; float tmp = TotalCum + volume; @@ -900,14 +922,14 @@ namespace RJW_Menstruation bool merged = false; if (!cums.NullOrEmpty()) foreach (Cum cum in cums) { - if (cum.notcum && cum.pawn.Equals(pawn) && cum.notcumLabel.Equals(notcumlabel)) + if (cum.notcum && cum.pawn.Equals(cummer) && cum.notcumLabel.Equals(notcumlabel)) { cum.MergeWithFluid(volume, decayresist, filthdef); merged = true; } cum.DismishForce(cumoutrate); } - if (!merged) cums.Add(new Cum(pawn, volume * (1 - cumoutrate), notcumlabel, decayresist, filthdef)); + if (!merged) cums.Add(new Cum(cummer, volume * (1 - cumoutrate), notcumlabel, decayresist, filthdef)); } else { @@ -915,13 +937,13 @@ namespace RJW_Menstruation bool merged = false; if (!cums.NullOrEmpty()) foreach (Cum cum in cums) { - if (cum.notcum && cum.pawn.Equals(pawn) && cum.notcumLabel.Equals(notcumlabel)) + if (cum.notcum && cum.pawn.Equals(cummer) && cum.notcumLabel.Equals(notcumlabel)) { cum.MergeWithFluid(volume, decayresist, filthdef); merged = true; } } - if (!merged) cums.Add(new Cum(pawn, volume, notcumlabel, decayresist, filthdef)); + if (!merged) cums.Add(new Cum(cummer, volume, notcumlabel, decayresist, filthdef)); } cumd = TotalCumPercent - cumd; AfterNotCumIn(); @@ -961,8 +983,8 @@ namespace RJW_Menstruation absorber = (Absorber)Pawn.apparel?.WornApparel?.Find(x => x is Absorber); if (absorber != null) { - absorber.WearEffect(); - if (absorber.dirty && absorber.EffectAfterDirty) absorber.DirtyEffect(); + absorber.WearEffect(TickInterval); + if (absorber.dirty && absorber.EffectAfterDirty) absorber.DirtyEffect(TickInterval); } } @@ -994,13 +1016,13 @@ namespace RJW_Menstruation float leakfactor = 1.0f; float totalleak = 0f; float cumd = TotalCumPercent; + int preCumAmount = Mathf.CeilToInt(TotalCum); List filthlabels = new List(); BeforeCumOut(out Absorber absorber); if (cums.NullOrEmpty()) return; if (TotalCum > Props.maxCumCapacity * Pawn.BodySize) leakfactor = Math.Min(1 + (TotalCum - Props.maxCumCapacity * Pawn.BodySize) / 10, 2f); if (absorber != null && absorber.dirty && !absorber.LeakAfterDirty) leakfactor = 0f; if (Pawn.CurJobDef == xxx.knotted) leakfactor = 0f; - HashSet removecums = new HashSet(); foreach (Cum cum in cums) { cum.CumEffects(Pawn); @@ -1009,11 +1031,14 @@ namespace RJW_Menstruation totalleak += AbsorbCum(vd, absorber); string tmp = "FilthLabelWithSource".Translate(cum.FilthDef.label, cum.pawn?.LabelShort ?? "Unknown", 1.ToString()); filthlabels.Add(tmp.Replace(" x1", "")); - if (cum.ShouldRemove()) removecums.Add(cum); } - if (cums.Count > 1) MakeCumFilthMixture(totalleak, filthlabels); - else if (cums.Count == 1) MakeCumFilth(cums.First(), totalleak); - cums.RemoveAll(cum => removecums.Contains(cum)); + int postCumAmount = Mathf.CeilToInt(TotalCum); + for (int i = 0; i < postCumAmount - preCumAmount; i++) // Emit a filth every time the integer cum amount drops + { + if (cums.Count > 1) MakeCumFilthMixture(totalleak, filthlabels); + else if (cums.Count == 1) MakeCumFilth(cums.First(), totalleak); + } + cums.RemoveAll(cum => cum.ShouldRemove()); cumd = TotalCumPercent - cumd; if (totalleak >= 1.0f) AfterCumOut(); AfterFluidOut(cumd); @@ -1127,17 +1152,17 @@ namespace RJW_Menstruation InitOvary(); - if (currentIntervalHours < 0) + if (currentIntervalTicks < 0) { if (ShouldBeInfertile()) curStage = Stage.Infertile; else if (!IsBreedingSeason()) curStage = Stage.Anestrus; else curStage = RandomStage(); if (curStage == Stage.Follicular) - currentIntervalHours = PeriodRandomizer(Stage.Follicular) - PeriodRandomizer(Stage.Bleeding); + currentIntervalTicks = PeriodRandomizer(Stage.Follicular) - PeriodRandomizer(Stage.Bleeding); else - currentIntervalHours = PeriodRandomizer(curStage); - if (currentIntervalHours <= 0) currentIntervalHours = 1; - else if (currentIntervalHours < curStageHrs) curStageHrs = currentIntervalHours; + currentIntervalTicks = PeriodRandomizer(curStage); + if (currentIntervalTicks < 0) currentIntervalTicks = 0; + else if (currentIntervalTicks < curStageTicks) curStageTicks = currentIntervalTicks; } if (crampPain < 0) crampPain = PainRandomizer(); InitializeExtraValues(); @@ -1242,11 +1267,11 @@ namespace RJW_Menstruation switch (curStage) { case Stage.Follicular: - return curStageHrs > currentIntervalHours - Props.estrusDaysBeforeOvulation * 24; + return curStageTicks > currentIntervalTicks - Props.estrusDaysBeforeOvulation * GenDate.TicksPerDay; case Stage.Ovulatory: return true; case Stage.Luteal: - return curStageHrs < EggLifespanHours; + return curStageTicks < EggLifespanTicks; default: return false; } @@ -1296,9 +1321,11 @@ namespace RJW_Menstruation if (eligibleCum.Count == 0) return null; float totalFertPower = eligibleCum.Sum(cum => cum.FertVolume); + + float fertFailChancePerHour = Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor); + float fertFailChancePerInterval = Mathf.Pow(fertFailChancePerHour, (float)TickInterval / GenDate.TicksPerHour); - if (Rand.Chance(Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor))) - return null; + if (Rand.Chance(fertFailChancePerInterval)) return null; Pawn.records.AddTo(VariousDefOf.AmountofFertilizedEggs, 1); float selection = Rand.Range(0.0f, totalFertPower); @@ -1323,8 +1350,8 @@ namespace RJW_Menstruation foreach (Egg egg in eggs) { if (!egg.fertilized || - egg.fertstage < minImplantAgeHours || - egg.position < Math.Min(Props.lutealIntervalDays * 24 / 2, maxImplantDelayHours)) + egg.ticksSinceFertilization < minImplantAgeHours * GenDate.TicksPerHour || + egg.ageTicks < Math.Min(Props.lutealIntervalDays * GenDate.TicksPerDay / 2, maxImplantDelayHours * GenDate.TicksPerHour)) continue; else if (egg.fertilizer == null) { @@ -1408,8 +1435,8 @@ namespace RJW_Menstruation if (pregnancy is Hediff_BasePregnancy rjw_preg) { // TODO: advance biotech pregnancy - rjw_preg.p_start_tick -= egg.fertstage / Configurations.CycleAcceleration * GenDate.TicksPerHour; - rjw_preg.p_end_tick -= egg.fertstage / Configurations.CycleAcceleration * GenDate.TicksPerHour; + rjw_preg.p_start_tick -= egg.ticksSinceFertilization / Configurations.CycleAcceleration; + rjw_preg.p_end_tick -= egg.ticksSinceFertilization / Configurations.CycleAcceleration; } } } @@ -1434,7 +1461,9 @@ namespace RJW_Menstruation protected void BleedOut() { - CumIn(Pawn, Rand.Range(0.02f * Configurations.BleedingAmount, 0.04f * Configurations.BleedingAmount), Translations.Menstrual_Blood, -5.0f, Pawn.def.race?.BloodDef ?? ThingDefOf.Filth_Blood); + // ~1.5 per hour times acceleration + float bledAmount = 0.03f * Configurations.BleedingAmount * Configurations.CycleAcceleration * Rand.Range(0.5f, 1.5f) * TickInterval / GenDate.TicksPerHour; + CumIn(Pawn, bledAmount, Translations.Menstrual_Blood, -5.0f, Pawn.def.race?.BloodDef ?? ThingDefOf.Filth_Blood); Cum blood = GetNotCum(Translations.Menstrual_Blood); if (blood != null) blood.Color = BloodColor; } @@ -1501,12 +1530,12 @@ namespace RJW_Menstruation HashSet deadeggs = new HashSet(); foreach (Egg egg in eggs) { - egg.position += Configurations.CycleAcceleration; - if (egg.fertilized) egg.fertstage += Configurations.CycleAcceleration; + egg.ageTicks += TickInterval * Configurations.CycleAcceleration; + if (egg.fertilized) egg.ticksSinceFertilization += TickInterval * Configurations.CycleAcceleration; else { - egg.lifespanhrs -= Configurations.CycleAcceleration; - if (egg.lifespanhrs < 0) deadeggs.Add(egg); + egg.lifeSpanTicks -= TickInterval * Configurations.CycleAcceleration; + if (egg.lifeSpanTicks < 0) deadeggs.Add(egg); } } eggs.RemoveAll(egg => deadeggs.Contains(egg)); @@ -1517,7 +1546,7 @@ namespace RJW_Menstruation Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_MenstrualCramp, Pawn); hediff.Severity = crampPain * Rand.Range(0.9f, 1.1f); HediffCompProperties_SeverityPerDay Prop = (HediffCompProperties_SeverityPerDay)hediff.TryGetComp().props; - Prop.severityPerDay = -hediff.Severity / (currentIntervalHours / 24) * Configurations.CycleAcceleration; + Prop.severityPerDay = -hediff.Severity / (currentIntervalTicks / GenDate.TicksPerDay) * Configurations.CycleAcceleration; Pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(Pawn)); } @@ -1529,14 +1558,14 @@ namespace RJW_Menstruation GoNextStage(Stage.Anestrus); return; } - else if (curStageHrs >= currentIntervalHours) + else if (curStageTicks >= currentIntervalTicks) { GoOvulatoryStage(); } else { - curStageHrs += Configurations.CycleAcceleration; - if (!estrusflag && curStageHrs > currentIntervalHours - Props.estrusDaysBeforeOvulation * 24) + curStageTicks += TickInterval * Configurations.CycleAcceleration; + if (!estrusflag && curStageTicks > currentIntervalTicks - Props.estrusDaysBeforeOvulation * GenDate.TicksPerDay) { estrusflag = true; SetEstrus(); @@ -1547,6 +1576,11 @@ namespace RJW_Menstruation protected virtual void OvulatoryAction() { + if (curStageTicks < currentIntervalTicks) + { + curStageTicks += TickInterval * Configurations.CycleAcceleration; + return; + } estrusflag = false; float eggnum; try @@ -1570,7 +1604,7 @@ namespace RJW_Menstruation for (int i = 0; i < toOvulate; i++) if (i < eggstack || Rand.Chance(ovulationChance)) // eggstack comes from drugs and are guaranteed ovulated { - eggs.Add(new Egg((int)(EggLifespanHours / CycleFactor))); + eggs.Add(new Egg((int)(EggLifespanTicks / CycleFactor))); ++ovulated; } ovarypower -= ovulated; @@ -1583,7 +1617,7 @@ namespace RJW_Menstruation protected virtual void LutealAction() { - if (curStageHrs >= currentIntervalHours) + if (curStageTicks >= currentIntervalTicks) { eggs.Clear(); if (EggHealth < 1f / 4f || (EggHealth < 1f / 3f && Rand.Chance(0.3f))) //skips bleeding @@ -1605,13 +1639,13 @@ namespace RJW_Menstruation } else { - curStageHrs += Configurations.CycleAcceleration; + curStageTicks += TickInterval * Configurations.CycleAcceleration; StayCurrentStage(); } } else { - curStageHrs += Configurations.CycleAcceleration; + curStageTicks += TickInterval * Configurations.CycleAcceleration; StayCurrentStage(); } @@ -1619,23 +1653,23 @@ namespace RJW_Menstruation protected virtual void BleedingAction() { - if (curStageHrs >= currentIntervalHours) + if (curStageTicks >= currentIntervalTicks) { Hediff hediff = Pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp); if (hediff != null && !Pawn.GetMenstruationComps().Any(comp => comp != this && comp.curStage == Stage.Bleeding)) Pawn.health.RemoveHediff(hediff); - int totalFollicularHours = PeriodRandomizer(Stage.Follicular); // 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 + int totalFollicularTicks = PeriodRandomizer(Stage.Follicular); // The total amount of time for both bleeding and follicular + if (totalFollicularTicks <= currentIntervalTicks) // We've bled for so long that we completely missed the follicular phase GoOvulatoryStage(); else { - currentIntervalHours = totalFollicularHours - currentIntervalHours; // I.e., the remaining follicular hours equals the total minus the bleeding hours elapsed + currentIntervalTicks = totalFollicularTicks - currentIntervalTicks; // I.e., the remaining follicular time equals the total minus the bleeding time elapsed GoNextStage(Stage.Follicular, false); } } else { - if (curStageHrs < currentIntervalHours / 4) for (int i = 0; i < Configurations.CycleAcceleration; i++) BleedOut(); - curStageHrs += Configurations.CycleAcceleration; + if (curStageTicks < currentIntervalTicks / 4) BleedOut(); + curStageTicks += TickInterval * Configurations.CycleAcceleration; StayCurrentStage(); } } @@ -1651,7 +1685,7 @@ namespace RJW_Menstruation if (pregnancy != null && Pawn.health.hediffSet.hediffs.Contains(pregnancy)) { - curStageHrs += 1; + curStageTicks += TickInterval; StayCurrentStageConst(Stage.Pregnant); } else @@ -1663,7 +1697,7 @@ namespace RJW_Menstruation protected virtual void RecoverAction() { - if (curStageHrs >= currentIntervalHours) + if (curStageTicks >= currentIntervalTicks) { if (ShouldBeInfertile()) { @@ -1680,7 +1714,7 @@ namespace RJW_Menstruation } else { - curStageHrs += Configurations.CycleAcceleration; + curStageTicks += TickInterval * Configurations.CycleAcceleration; StayCurrentStage(); } } @@ -1776,8 +1810,8 @@ namespace RJW_Menstruation public void GoNextStage(Stage nextstage, bool calculateHours = true) { - curStageHrs = 0; - if (calculateHours) currentIntervalHours = PeriodRandomizer(nextstage); + curStageTicks = 0; + if (calculateHours) currentIntervalTicks = PeriodRandomizer(nextstage); curStage = nextstage; } @@ -1819,15 +1853,17 @@ namespace RJW_Menstruation switch (stage) { case Stage.Follicular: - return (int)(Props.follicularIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 1.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 1.5f)); + return (int)(Props.follicularIntervalDays * GenDate.TicksPerDay * (1 + Rand.Range(-cycleVariability, cycleVariability) * 1.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 1.5f)); + case Stage.Ovulatory: + return Props.ovulationIntervalHours * GenDate.TicksPerHour; // No variability for now case Stage.Luteal: - return (int)(Props.lutealIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f)); + return (int)(Props.lutealIntervalDays * GenDate.TicksPerDay * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f)); case Stage.Bleeding: - return (int)(Props.bleedingIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f)); + return (int)(Props.bleedingIntervalDays * GenDate.TicksPerDay * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f)); case Stage.Recover: - return (int)(Props.recoveryIntervalDays * 24 * Rand.Range(0.95f, 1.05f)); + return (int)(Props.recoveryIntervalDays * GenDate.TicksPerDay * Rand.Range(0.95f, 1.05f)); case Stage.Pregnant: - return (int)MenstruationUtility.GestationHours(pregnancy); + return (int)(MenstruationUtility.GestationHours(pregnancy) * GenDate.TicksPerHour); default: return 1; } @@ -1863,13 +1899,13 @@ namespace RJW_Menstruation switch (stage) { case Stage.Follicular: - curStageHrs = Rand.Range(0, (Props.follicularIntervalDays - Props.bleedingIntervalDays) * 24); + curStageTicks = Rand.Range(0, (Props.follicularIntervalDays - Props.bleedingIntervalDays) * GenDate.TicksPerDay); break; case Stage.Luteal: - curStageHrs = Rand.Range(0, Props.lutealIntervalDays * 24); + curStageTicks = Rand.Range(0, Props.lutealIntervalDays * GenDate.TicksPerDay); break; case Stage.Bleeding: - curStageHrs = Rand.Range(0, Props.bleedingIntervalDays * 24); + curStageTicks = Rand.Range(0, Props.bleedingIntervalDays * GenDate.TicksPerDay); break; } return stage; @@ -1915,34 +1951,46 @@ namespace RJW_Menstruation public class Egg : IExposable { public bool fertilized; - public int lifespanhrs; + public int lifeSpanTicks; public Pawn fertilizer; - public int position; - public int fertstage = 0; + public int ageTicks; + public int ticksSinceFertilization = 0; public Egg() { fertilized = false; - lifespanhrs = (int)(96 * Configurations.EggLifespanMultiplier); + lifeSpanTicks = (int)(96 * GenDate.TicksPerHour * Configurations.EggLifespanMultiplier); fertilizer = null; - position = 0; + ageTicks = 0; } public Egg(int lifespanhrs) { fertilized = false; - this.lifespanhrs = (int)(lifespanhrs * Configurations.EggLifespanMultiplier); + lifeSpanTicks = (int)(lifespanhrs * GenDate.TicksPerHour * Configurations.EggLifespanMultiplier); fertilizer = null; - position = 0; + ageTicks = 0; } public void ExposeData() { + if (Scribe.mode == LoadSaveMode.LoadingVars) + { + int lifespanhrs = -1; + int position = -1; + int fertstage = -1; + Scribe_Values.Look(ref lifespanhrs, "lifespanhrs", lifespanhrs, true); + Scribe_Values.Look(ref position, "position", position, true); + Scribe_Values.Look(ref fertstage, "fertstage", fertstage, true); + if (lifespanhrs >= 0) lifeSpanTicks = lifespanhrs * GenDate.TicksPerHour; + if (position >= 0) ageTicks = position * GenDate.TicksPerHour; + if (fertstage >= 0) ticksSinceFertilization = fertstage * GenDate.TicksPerHour; + } Scribe_References.Look(ref fertilizer, "fertilizer", true); Scribe_Values.Look(ref fertilized, "fertilized", fertilized, true); - Scribe_Values.Look(ref lifespanhrs, "lifespanhrs", lifespanhrs, true); - Scribe_Values.Look(ref position, "position", position, true); - Scribe_Values.Look(ref fertstage, "fertstage", fertstage, true); + Scribe_Values.Look(ref lifeSpanTicks, "lifeSpanTicks", lifeSpanTicks, true); + Scribe_Values.Look(ref ageTicks, "ageTicks", ageTicks, true); + Scribe_Values.Look(ref ticksSinceFertilization, "ticksSinceFertilization", ticksSinceFertilization, true); } } 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 6611547..eb1ac1a 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 @@ -16,8 +16,8 @@ namespace RJW_Menstruation public class HediffComp_PeriodicOvulator : HediffComp_Menstruation { - public int hoursToNextCycle = -100000; - public int averageCycleIntervalHours = -1; + public int ticksToNextCycle = -100000; + public int averageCycleIntervalTicks = -1; public new CompProperties_PeriodicOvulator Props; @@ -25,14 +25,14 @@ namespace RJW_Menstruation { base.InitializeExtraValues(); Props = (CompProperties_PeriodicOvulator)props; - if (averageCycleIntervalHours < 0) + if (averageCycleIntervalTicks < 0) { - averageCycleIntervalHours = (int)(24f * Props.cycleIntervalDays.RandomInRange / cycleSpeed); - if (hoursToNextCycle < -50000) - hoursToNextCycle = Rand.Range(0, averageCycleIntervalHours); + 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.Luteal || curStage == Stage.Bleeding) - && (averageCycleIntervalHours - hoursToNextCycle) / 2 >= 24 * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed) + && (averageCycleIntervalTicks - ticksToNextCycle) / 2 >= GenDate.TicksPerDay * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed) GoNextStage(Stage.Anestrus); } } @@ -41,31 +41,40 @@ namespace RJW_Menstruation { // Don't bother trying to work seasonal breeding into the math // Due to the enormous variation in possible cycle gaps, cheat and base it off the individual - return averageCycleIntervalHours * cycleSpeed / (24 * 360); // cancel out their cycleSpeed from initialization to get their "normal" speed + return averageCycleIntervalTicks * cycleSpeed / GenDate.TicksPerYear; // cancel out their cycleSpeed from initialization to get their "normal" speed } protected override void BeforeSimulator() { base.BeforeSimulator(); - if (hoursToNextCycle > 0) hoursToNextCycle -= Configurations.CycleAcceleration; + if (ticksToNextCycle > 0) ticksToNextCycle -= TickInterval * Configurations.CycleAcceleration; } public override void CompExposeData() { base.CompExposeData(); - Scribe_Values.Look(ref hoursToNextCycle, "hoursToNextCycle", hoursToNextCycle, true); - Scribe_Values.Look(ref averageCycleIntervalHours, "averageCycleIntervalHours", averageCycleIntervalHours, true); + if (Scribe.mode == LoadSaveMode.LoadingVars) + { + int hoursToNextCycle = -1; + int averageCycleIntervalHours = -1; + Scribe_Values.Look(ref hoursToNextCycle, "hoursToNextCycle", hoursToNextCycle, true); + Scribe_Values.Look(ref averageCycleIntervalHours, "averageCycleIntervalHours", averageCycleIntervalHours, true); + if (hoursToNextCycle >= 0) ticksToNextCycle = hoursToNextCycle * GenDate.TicksPerHour; + if (averageCycleIntervalHours >= 0) averageCycleIntervalTicks = averageCycleIntervalHours * GenDate.TicksPerHour; + } + Scribe_Values.Look(ref ticksToNextCycle, "ticksToNextCycle", ticksToNextCycle, true); + Scribe_Values.Look(ref averageCycleIntervalTicks, "averageCycleIntervalTicks", averageCycleIntervalTicks, true); } - protected override int HoursToNextStage() + protected override int TicksToNextStage() { - if (curStage == Stage.Anestrus && hoursToNextCycle > 0) return hoursToNextCycle / Configurations.CycleAcceleration; - else return base.HoursToNextStage(); + if (curStage == Stage.Anestrus && ticksToNextCycle > 0) return ticksToNextCycle / Configurations.CycleAcceleration; + else return base.TicksToNextStage(); } protected override void BleedingAction() { - if (curStageHrs >= currentIntervalHours) + if (curStageTicks >= currentIntervalTicks) { Hediff hediff = Pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp); if (hediff != null && !Pawn.GetMenstruationComps().Any(comp => comp != this && comp.curStage == Stage.Bleeding)) Pawn.health.RemoveHediff(hediff); @@ -81,14 +90,14 @@ namespace RJW_Menstruation base.PregnantAction(); if (curStage != Stage.Pregnant) // Go halfway into the cycle - hoursToNextCycle = (int)(averageCycleIntervalHours * (1 + Rand.Range(-cycleVariability, cycleVariability))) / 2; + ticksToNextCycle = (int)(averageCycleIntervalTicks * (1 + Rand.Range(-cycleVariability, cycleVariability))) / 2; } protected override void AnestrusAction() { - if (hoursToNextCycle <= 0) + if (ticksToNextCycle <= 0) { - hoursToNextCycle = (int)(averageCycleIntervalHours * (1 + Rand.Range(-cycleVariability, cycleVariability))); + ticksToNextCycle = (int)(averageCycleIntervalTicks * (1 + Rand.Range(-cycleVariability, cycleVariability))); if (IsBreedingSeason()) GoNextStage(Stage.Follicular); return; } @@ -99,7 +108,7 @@ namespace RJW_Menstruation { base.CopyCycleProperties(original); if (original is HediffComp_PeriodicOvulator comp) - averageCycleIntervalHours = comp.averageCycleIntervalHours; + averageCycleIntervalTicks = comp.averageCycleIntervalTicks; } } } 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 833d5e9..f352a1b 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs @@ -219,6 +219,7 @@ namespace RJW_Menstruation } public static Texture2D GetEggIcon(this HediffComp_Menstruation comp, bool includeOvary) { + float ovulationChance = comp.OvulationChance; const float ovaryChanceToShow_01 = 0.4f; const float ovaryChanceToShow_02 = 1.0f; switch (comp.CurrentVisibleStage) @@ -231,28 +232,28 @@ namespace RJW_Menstruation job.Sexprops != null && !job.Sexprops.usedCondom && (job.Sexprops.sexType == xxx.rjwSextype.Vaginal || job.Sexprops.sexType == xxx.rjwSextype.DoublePenetration)) - return ContentFinder.Get((comp.OvulationChance >= ovaryChanceToShow_01) ? "Ovaries/Ovary_01" : "Ovaries/Ovary_00", true); + return ContentFinder.Get((ovulationChance >= ovaryChanceToShow_01) ? "Ovaries/Ovary_01" : "Ovaries/Ovary_00", true); else break; } - if (comp.curStageHrs > comp.CurStageIntervalHours - 30) // Approximate time for ovulation to occur - return ContentFinder.Get((comp.OvulationChance >= ovaryChanceToShow_01) ? "Ovaries/Ovary_01" : "Ovaries/Ovary_00", true); + if (comp.curStageTicks > comp.CurStageIntervalTicks - 30 * GenDate.TicksPerHour) // Approximate time for ovulation to occur + return ContentFinder.Get((ovulationChance >= ovaryChanceToShow_01) ? "Ovaries/Ovary_01" : "Ovaries/Ovary_00", true); else break; case HediffComp_Menstruation.Stage.Ovulatory: if (!includeOvary) break; - if (comp.OvulationChance >= ovaryChanceToShow_02) + if (ovulationChance >= ovaryChanceToShow_02) return ContentFinder.Get("Ovaries/Ovary_02", true); - else if (comp.OvulationChance >= ovaryChanceToShow_01) + else if (ovulationChance >= ovaryChanceToShow_01) return ContentFinder.Get("Ovaries/Ovary_01", true); else return ContentFinder.Get("Ovaries/Ovary_00", true); case HediffComp_Menstruation.Stage.Luteal: if (!comp.IsEggExist) break; - int fertstage = comp.IsFertilized; - if (fertstage >= 0) + int fertTime = comp.EggFertilizedTime; + if (fertTime >= 0) { - if (fertstage <= Configurations.CycleAcceleration) return ContentFinder.Get("Eggs/Egg_Fertilizing02", true); - else if (fertstage <= 18) return ContentFinder.Get("Eggs/Egg_Fertilized00", true); - else if (fertstage <= 54) return ContentFinder.Get("Eggs/Egg_Fertilized01", true); + if (fertTime <= GenDate.TicksPerHour * Configurations.CycleAcceleration) return ContentFinder.Get("Eggs/Egg_Fertilizing02", true); + else if (fertTime <= 18 * GenDate.TicksPerHour) return ContentFinder.Get("Eggs/Egg_Fertilized00", true); + else if (fertTime <= 54 * GenDate.TicksPerHour) return ContentFinder.Get("Eggs/Egg_Fertilized01", true); else return ContentFinder.Get("Eggs/Egg_Fertilized02", true); } else if (comp.IsEggFertilizing) diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs index 7185ccf..4571fae 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using RimWorld; using rjw; using System.Collections.Generic; using System.Linq; @@ -47,7 +48,7 @@ namespace RJW_Menstruation if (Configurations.Debug) { description - .AppendFormat("{0}: {1}\n", comp.curStage, comp.curStageHrs); + .AppendFormat("{0}: {1}\n", comp.curStage, comp.curStageTicks / GenDate.TicksPerHour); if (comp.Pregnancy is Hediff_BasePregnancy rjwpreg) description .AppendFormat("due: {0}\n", rjwpreg.DueDate()); else if (comp.Pregnancy is Hediff_Pregnant biopreg) description diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs index e427e0f..e240bd0 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs @@ -197,7 +197,8 @@ namespace RJW_Menstruation public float absorbedfluids = 0; public bool dirty = false; - public int wearhours = 0; + public int wearTicks = 0; + protected virtual float PassiveAbsorptionPerHour => 0.1f; public virtual bool LeakAfterDirty => def.GetModExtension().leakAfterDirty; public virtual bool EffectAfterDirty => def.GetModExtension().effectsAfterDirty; public virtual ThingDef DirtyDef => def.GetModExtension().dirtyDef; @@ -205,12 +206,12 @@ namespace RJW_Menstruation public Color fluidColor = Color.white; - public virtual void DirtyEffect() { } + public virtual void DirtyEffect(int tickInterval) { } - public virtual void WearEffect() + public virtual void WearEffect(int tickInterval) { - absorbedfluids += 0.1f; - if (dirty) wearhours++; + absorbedfluids += PassiveAbsorptionPerHour * tickInterval / GenDate.TicksPerHour; + if (dirty) wearTicks += tickInterval; } public override Color DrawColorTwo => fluidColor; @@ -218,9 +219,15 @@ namespace RJW_Menstruation public override void ExposeData() { base.ExposeData(); + if(Scribe.mode == LoadSaveMode.LoadingVars) + { + int wearhours = -1; + Scribe_Values.Look(ref wearhours, "wearhours", wearhours, true); + if (wearhours >= 0) wearTicks = wearhours * GenDate.TicksPerHour; + } Scribe_Values.Look(ref absorbedfluids, "absorbedfluids", absorbedfluids, true); Scribe_Values.Look(ref dirty, "dirty", dirty, true); - Scribe_Values.Look(ref wearhours, "wearhours", wearhours, true); + Scribe_Values.Look(ref wearTicks, "wearTicks", wearTicks, true); Scribe_Values.Look(ref fluidColor, "fluidColor", fluidColor, true); } @@ -228,16 +235,11 @@ namespace RJW_Menstruation public class Absorber_Tampon : Absorber { - - public override void WearEffect() + protected override float PassiveAbsorptionPerHour => 0.5f; + public override void DirtyEffect(int tickInterval) { - if (dirty) wearhours++; - absorbedfluids += 0.5f; - } - public override void DirtyEffect() - { - if (wearhours > MinHrstoDirtyEffect && Rand.Chance(0.01f) && !Wearer.apparel.IsLocked(this)) + 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/Translations.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs index 1a67ebf..dd2982f 100644 --- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs +++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs @@ -60,6 +60,12 @@ namespace RJW_Menstruation public static readonly string Option6_Desc = "Option6_Desc".Translate(); public static readonly string Option7_Label = "Option7_Label".Translate(); public static readonly string Option7_Desc = "Option7_Desc".Translate(); + public static readonly string Option_ColonistUpdateInterval_Label = "Option_ColonistUpdateInterval_Label".Translate(); + public static readonly string Option_ColonistUpdateInterval_Desc = "Option_ColonistUpdateInterval_Desc".Translate(); + public static readonly string Option_NonColonistUpdateInterval_Label = "Option_NonColonistUpdateInterval_Label".Translate(); + public static readonly string Option_NonColonistUpdateInterval_Desc = "Option_NonColonistUpdateInterval_Desc".Translate(); + public static readonly string Option_AnimalUpdateInterval_Label = "Option_AnimalUpdateInterval_Label".Translate(); + public static readonly string Option_AnimalUpdateInterval_Desc = "Option_AnimalUpdateInterval_Desc".Translate(); public static readonly string Option8_Label = "Option8_Label".Translate(); public static readonly string Option8_Desc = "Option8_Desc".Translate(); public static readonly string Option9_Label = "Option9_Label".Translate(); diff --git a/changelogs.txt b/changelogs.txt index 5dc6a70..85e123c 100644 --- a/changelogs.txt +++ b/changelogs.txt @@ -1,6 +1,7 @@ Version 1.0.9.0 - Fix errors when opening the womb dialog of some low fertility pawns. - Updated Traditional Chinese translation by Hydrogen. + - New options to update wombs more or less often, defaulting to every hour. - Menstruation-related genes will now stay on females during initial pawn setup. Version 1.0.8.9