diff --git a/1.4/Assemblies/RJW_Menstruation.dll b/1.4/Assemblies/RJW_Menstruation.dll
index 32d579b..5f42dbb 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 3df2d06..a1c65b3 100644
--- a/1.4/Languages/English/Keyed/RJW_Menstruation.xml
+++ b/1.4/Languages/English/Keyed/RJW_Menstruation.xml
@@ -120,6 +120,8 @@
Hookup minimum opinion in estrus
Estimated sperm lifespan
Estimated egg lifespan
+ Ovulation {0}
+ Chance of each egg being released during ovulation.
Implantation chance of fertilized eggs.
Chance of fertilization this hour: {0}%
Use basic RJW pregnancy
Use menstruation multiple pregnancy
diff --git a/1.4/MilkModule/Assemblies/MilkModule.dll b/1.4/MilkModule/Assemblies/MilkModule.dll
index 5c953b2..174e407 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/HediffComps/HediffComp_Menstruation.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs
index d438f98..5ec30b2 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
@@ -280,16 +280,63 @@ namespace RJW_Menstruation
return 1.0f;
}
}
- //effect on implant chance
- public float ImplantFactor
+
+ // I hate doing this, but it's the least bad option
+ public bool calculatingOvulationChance = false;
+
+ public float OvulationChance
+ {
+ get
+ {
+ float ovulationChance = 1.0f;
+ if (EggHealth <= 0.0f) return 0.0f;
+ if (EggHealth < 1.0f / 3.0f) ovulationChance = 0.2f;
+ if (ModsConfig.BiotechActive && xxx.is_human(Pawn))
+ {
+ if (Pawn.SterileGenes()) return 0.0f;
+ // Replicate how rjw.PawnCapacityWorker_Fertility.CalculateCapacityLevel does it, but without the age factor
+ if (!Pawn.RaceHasFertility()) return 0.0f;
+ if (AndroidsCompatibility.IsAndroid(Pawn) && parent.def != Genital_Helper.archotech_vagina) return 0.0f;
+ foreach (var part in StatDefOf.Fertility.parts)
+ {
+ if(part is StatPart_FertilityByGenderAge fertilityByAge)
+ {
+ float factor = 1.0f;
+ fertilityByAge.TransformValue(StatRequest.For(Pawn), ref factor);
+ if (factor <= 0.0f) return 0.0f; // Too young or too old
+ }
+ else part.TransformValue(StatRequest.For(Pawn), ref ovulationChance);
+ }
+ try
+ {
+ calculatingOvulationChance = true;
+ ovulationChance *= PawnCapacityUtility.CalculateCapacityLevel(Pawn.health.hediffSet, xxx.reproduction);
+ }
+ finally { calculatingOvulationChance = false; }
+ }
+ return ovulationChance;
+ }
+ }
+ public float ImplantChance
{
get
{
float factor = 1.0f;
if (Pawn.Has(Quirk.Breeder)) factor = 10.0f;
- return Pawn.health.capacities.GetLevel(xxx.reproduction) * Props.baseImplantationChanceFactor * FertilityModifier * factor;
+
+ if (ModsConfig.BiotechActive && xxx.is_human(Pawn))
+ {
+ // Implant factor will be based solely on pawn age, plus any rollover from ovulation chance
+ StatPart_FertilityByGenderAge fertilityStatPart = StatDefOf.Fertility.GetStatPart();
+ fertilityStatPart?.TransformValue(StatRequest.For(Pawn), ref factor);
+ float ovulationOverflow = OvulationChance;
+ if (ovulationOverflow > 1.0f) factor *= ovulationOverflow;
+ return Props.baseImplantationChanceFactor * FertilityModifier * factor;
+ }
+ else return Pawn.health.capacities.GetLevel(xxx.reproduction) * Props.baseImplantationChanceFactor * FertilityModifier * factor;
}
}
+
public IEnumerable GetCumsInfo
{
get
@@ -678,7 +725,7 @@ namespace RJW_Menstruation
BeforeSimulator();
- if (pregnancy == null && (Pawn.health.capacities.GetLevel(xxx.reproduction) <= 0 || EggHealth <= 0 || Pawn.SterileGenes())) GoNextStage(Stage.Infertile);
+ if (pregnancy == null && (ImplantChance <= 0.0f || EggHealth <= 0)) GoNextStage(Stage.Infertile);
switch (curStage)
{
case Stage.Follicular:
@@ -1111,9 +1158,12 @@ namespace RJW_Menstruation
if (cycleSpeed < 0f) cycleSpeed = Utility.RandGaussianLike(0.8f, 1.2f);
if (cycleVariability < 0f) cycleVariability = MenstruationUtility.RandomVariabilityPercent();
+
+ InitOvary();
+
if (currentIntervalHours < 0)
{
- if (Pawn.health.capacities.GetLevel(xxx.reproduction) <= 0 || Pawn.SterileGenes()) curStage = Stage.Infertile;
+ if (ImplantChance <= 0.0f || EggHealth <= 0) curStage = Stage.Infertile;
else if (!IsBreedingSeason()) curStage = Stage.Anestrus;
else curStage = RandomStage();
if (curStage == Stage.Follicular)
@@ -1128,8 +1178,6 @@ namespace RJW_Menstruation
if (cums == null) cums = new List();
if (eggs == null) eggs = new List();
-
- InitOvary();
TakeLoosePregnancy();
//Log.Message(Pawn.Label + " - Initialized menstruation comp");
@@ -1324,7 +1372,7 @@ namespace RJW_Menstruation
deadeggs.Add(egg);
continue;
}
- else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * ImplantFactor * InterspeciesImplantFactor(egg.fertilizer))
+ else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * ImplantChance * InterspeciesImplantFactor(egg.fertilizer))
{
if (Configurations.Debug) Log.Message($"Implanting fertilized egg of {Pawn} into {parent}, father {egg.fertilizer}");
if (pregnancy != null)
@@ -1527,7 +1575,7 @@ namespace RJW_Menstruation
}
else if (curStageHrs >= currentIntervalHours)
{
- GoOvulatoryStage();
+ GoNextStage(Stage.Ovulatory);
}
else
{
@@ -1562,8 +1610,10 @@ namespace RJW_Menstruation
eggnum *= ovulationFactor;
ovulated = (int)eggnum + eggstack;
+ float ovulationChance = OvulationChance;
for (int i = 0; i < ovulated; i++)
- eggs.Add(new Egg((int)(EggLifespanHours / CycleFactor)));
+ if (i < eggstack || Rand.Chance(ovulationChance)) // eggstack comes from drugs and are guaranteed ovulated
+ eggs.Add(new Egg((int)(EggLifespanHours / CycleFactor)));
ovarypower -= ovulated;
eggstack = 0;
@@ -1781,12 +1831,7 @@ namespace RJW_Menstruation
protected virtual void GoOvulatoryStage()
{
- if (EggHealth < 1.0f / 3.0f && Rand.Range(0.0f, 1.0f) < 0.2f) // Skip ovulation if deep into climacteric
- {
- estrusflag = false;
- GoNextStage(Stage.Luteal);
- }
- else GoNextStage(Stage.Ovulatory);
+ GoNextStage(Stage.Ovulatory);
}
//stage can be interrupted in other reasons
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs
index cc1ff7c..b754557 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs
@@ -129,11 +129,11 @@ namespace RJW_Menstruation
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)});
+ 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 || IsPregnant.ReturnType != typeof(bool)) throw new System.InvalidOperationException("IsPregnant not found");
- foreach(CodeInstruction instruction in instructions)
+ foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(IsPregnant))
yield return CodeInstruction.Call(typeof(CanImpregnate_Patch), nameof(PregnancyBlocksImpregnation));
@@ -371,4 +371,27 @@ namespace RJW_Menstruation
}
}
+
+ [HarmonyPatch(typeof(PawnCapacityWorker_Fertility), nameof(PawnCapacityWorker_Fertility.CalculateCapacityLevel))]
+ public static class PawnCapacityWorker_Fertility_Patch
+ {
+ private static float GetFertilityStatOrOne(Thing thing, StatDef stat, bool applyPostProcess, int cacheStaleAfterTicks)
+ {
+ Pawn pawn = (Pawn)thing;
+ if (pawn.GetMenstruationComps().Any(comp => comp.calculatingOvulationChance))
+ return 1.0f;
+ else return thing.GetStatValue(stat, applyPostProcess, cacheStaleAfterTicks);
+ }
+ private static readonly MethodInfo GetStatValue = AccessTools.Method(typeof(StatExtension), "GetStatValue", new System.Type[] { typeof(Thing), typeof(StatDef), typeof(bool), typeof(int) });
+ public static IEnumerable Transpiler(IEnumerable instructions)
+ {
+ if (GetStatValue == null || GetStatValue.ReturnType != typeof(float)) throw new System.InvalidOperationException("GetStatValue not found");
+ foreach (CodeInstruction instruction in instructions)
+ {
+ if (instruction.Calls(GetStatValue))
+ yield return CodeInstruction.Call(typeof(PawnCapacityWorker_Fertility_Patch), nameof(GetFertilityStatOrOne));
+ else yield return instruction;
+ }
+ }
+ }
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
index 7b0862d..1a67ebf 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
@@ -134,6 +134,8 @@ namespace RJW_Menstruation
public static readonly string EstimatedCumLifespan = "EstimatedCumLifespan".Translate();
public static readonly string EstimatedEggLifespan = "EstimatedEggLifespan".Translate();
+ public static string OvulationChanceLabel(string value) => "OvulationChanceLabel".Translate(value);
+ public static readonly string OvulationChanceDesc = "OvulationChanceDesc".Translate();
public static string FertilityDesc(string value) => "FertilityDesc".Translate(value);
public static readonly string Gizmo_GatherCum = "Gizmo_GatherCum".Translate();
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 4d428a9..ec93cfd 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
@@ -450,11 +450,18 @@ namespace RJW_Menstruation
statvalue = pawn.records.GetValue(xxx.CountOfBirthEgg);
FillableBarLabeled(lineRect, " " + xxx.CountOfBirthEgg.LabelCap.CapitalizeFirst() + " " + statvalue, statvalue / 100, TextureCache.RecoverTexture, Texture2D.blackTexture, xxx.CountOfBirthEgg.description);
- lineRect.y += height * 4;
+ lineRect.y += height * 3;
- statvalue = Configurations.ImplantationChance * comp.ImplantFactor;
+ if (ModsConfig.BiotechActive)
+ {
+ statvalue = comp.OvulationChance;
+ FillableBarLabeled(lineRect, " " + Translations.OvulationChanceLabel(statvalue.ToStringPercent()), statvalue, TextureCache.LutealTexture, Texture2D.blackTexture, Translations.OvulationChanceDesc);
+ }
+ lineRect.y += height;
+
+ statvalue = Configurations.ImplantationChance * comp.ImplantChance;
float fertchance = comp.GetFertilityChance();
- FillableBarLabeled(lineRect, " " + xxx.reproduction.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue, TextureCache.LutealTexture, Texture2D.blackTexture, Translations.FertilityDesc(String.Format("{0:0.##}", fertchance * 100)));
+ FillableBarLabeled(lineRect, " " + xxx.reproduction.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue, TextureCache.LutealTexture, 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;
diff --git a/About/Manifest.xml b/About/Manifest.xml
index 5477ddb..24b2e46 100644
--- a/About/Manifest.xml
+++ b/About/Manifest.xml
@@ -1,7 +1,7 @@
RJW Menstruation
- 1.0.8.7
+ 1.0.8.8
diff --git a/changelogs.txt b/changelogs.txt
index 160c7f5..1c41775 100644
--- a/changelogs.txt
+++ b/changelogs.txt
@@ -1,3 +1,11 @@
+Version 1.0.8.8
+ - Fix pawns skipping straight to menopause instead of going through climacteric stages.
+ - Rework ovulation mechanics. A pawn's implantation chance is now dependent on their age.
+ - All other fertility-altering effects instead change the odds of ovulation occuring, rolled per-egg. This chance appears in the womb dialog.
+ - If the chance of ovulation goes above 100%, the implantation chance is increased.
+ - Drugs that increase the number of eggs ovulated are still guaranteed to work.
+ - If Biotech is disabled or not installed, the old fertility system will apply instead.
+
Version 1.0.8.7
- Fix missing texture when using Milkable Colonists.
- Fix estrus and egg lifespan lasting far longer than intended.