Initial implementation of new variance code

This commit is contained in:
lutepickle 2022-07-07 10:28:53 -07:00
parent 9c9e120b92
commit 9cc8897103
3 changed files with 95 additions and 88 deletions

View file

@ -43,16 +43,15 @@ namespace RJW_Menstruation
GoNextStage(Stage.Anestrus); GoNextStage(Stage.Anestrus);
return; return;
} }
if (curStageHrs >= FollicularIntervalHours) if (curStageHrs >= currentIntervalhours)
{ {
estrusflag = false; estrusflag = false;
lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor);
GoNextStage(Stage.Luteal); GoNextStage(Stage.Luteal);
} }
else else
{ {
curStageHrs += Configurations.CycleAcceleration; curStageHrs += Configurations.CycleAcceleration;
if (!estrusflag && curStageHrs > FollicularIntervalHours - Props.estrusDaysBeforeOvulation * 24) if (!estrusflag && curStageHrs > currentIntervalhours - Props.estrusDaysBeforeOvulation * 24)
{ {
estrusflag = true; estrusflag = true;
SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation); SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation);
@ -68,22 +67,20 @@ namespace RJW_Menstruation
RemoveClimactericEffect(); RemoveClimactericEffect();
StayCurrentStage(); StayCurrentStage();
} }
else if (curStageHrs >= (follicularIntervalhours - bleedingIntervalhours) * CycleFactor) else if (curStageHrs >= currentIntervalhours)
{ {
estrusflag = false; estrusflag = false;
lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor);
GoNextStage(Stage.ClimactericLuteal); GoNextStage(Stage.ClimactericLuteal);
} }
else if (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.2f) // Might randomly skip to luteal early) else if (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.2f) // Might randomly skip to luteal early)
{ {
estrusflag = false; estrusflag = false;
lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor * 6);
GoNextStage(Stage.ClimactericLuteal); GoNextStage(Stage.ClimactericLuteal);
} }
else else
{ {
curStageHrs += Configurations.CycleAcceleration; curStageHrs += Configurations.CycleAcceleration;
if (!estrusflag && curStageHrs > FollicularIntervalHours - Props.estrusDaysBeforeOvulation * 24) if (!estrusflag && curStageHrs > currentIntervalhours - Props.estrusDaysBeforeOvulation * 24)
{ {
estrusflag = true; estrusflag = true;
SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation); SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation);

View file

@ -65,9 +65,10 @@ namespace RJW_Menstruation
const float minmakefilthvalue = 1.0f; const float minmakefilthvalue = 1.0f;
//const int ovarypowerthreshold = 72; //const int ovarypowerthreshold = 72;
public const int tickInterval = GenDate.TicksPerHour; const int tickInterval = GenDate.TicksPerHour;
public const int maxImplantDelayDays = 30; const int maxImplantDelayDays = 30;
public const int minImplantAgeHours = 72; const int minImplantAgeHours = 72;
public CompProperties_Menstruation Props; public CompProperties_Menstruation Props;
public Stage curStage = Stage.Follicular; public Stage curStage = Stage.Follicular;
public int curStageHrs = 0; public int curStageHrs = 0;
@ -108,10 +109,8 @@ namespace RJW_Menstruation
protected List<Cum> cums; protected List<Cum> cums;
protected List<Egg> eggs; protected List<Egg> eggs;
protected int follicularIntervalhours = -1; protected float cycleSpeed = -1;
protected int lutealIntervalhours = -1; protected float cycleVariability = -1;
protected int bleedingIntervalhours = -1;
protected int recoveryIntervalhours = -1;
protected int currentIntervalhours = -1; protected int currentIntervalhours = -1;
protected float crampPain = -1; protected float crampPain = -1;
protected Need sexNeed = null; protected Need sexNeed = null;
@ -132,14 +131,6 @@ namespace RJW_Menstruation
} }
} }
public int FollicularIntervalHours
{
get
{
return (int)((follicularIntervalhours - bleedingIntervalhours) * CycleFactor);
}
}
public float TotalCum public float TotalCum
{ {
get get
@ -442,7 +433,7 @@ namespace RJW_Menstruation
{ {
case Stage.Follicular: case Stage.Follicular:
case Stage.ClimactericFollicular: case Stage.ClimactericFollicular:
return curStageHrs > 0.7f * (follicularIntervalhours - bleedingIntervalhours); return curStageHrs > 0.7f * currentIntervalhours;
case Stage.Ovulatory: case Stage.Ovulatory:
return true; return true;
case Stage.Luteal: case Stage.Luteal:
@ -509,24 +500,7 @@ namespace RJW_Menstruation
{ {
get get
{ {
switch (curStage) return currentIntervalhours;
{
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;
}
} }
} }
@ -554,10 +528,10 @@ namespace RJW_Menstruation
Scribe_Collections.Look(ref eggs, saveDestroyedThings: true, label: "eggs", 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 curStage, "curStage", curStage, true);
Scribe_Values.Look(ref curStageHrs, "curStageHrs", curStageHrs, true); Scribe_Values.Look(ref curStageHrs, "curStageHrs", curStageHrs, true);
Scribe_Values.Look(ref follicularIntervalhours, "follicularIntervalhours", follicularIntervalhours, true); //Scribe_Values.Look(ref follicularIntervalhours, "follicularIntervalhours", follicularIntervalhours, true);
Scribe_Values.Look(ref lutealIntervalhours, "lutealIntervalhours", lutealIntervalhours, true); //Scribe_Values.Look(ref lutealIntervalhours, "lutealIntervalhours", lutealIntervalhours, true);
Scribe_Values.Look(ref bleedingIntervalhours, "bleedingIntervalhours", bleedingIntervalhours, true); //Scribe_Values.Look(ref bleedingIntervalhours, "bleedingIntervalhours", bleedingIntervalhours, true);
Scribe_Values.Look(ref recoveryIntervalhours, "recoveryIntervalhours", recoveryIntervalhours, true); //Scribe_Values.Look(ref recoveryIntervalhours, "recoveryIntervalhours", recoveryIntervalhours, true);
Scribe_Values.Look(ref currentIntervalhours, "currentIntervalhours", currentIntervalhours, true); Scribe_Values.Look(ref currentIntervalhours, "currentIntervalhours", currentIntervalhours, true);
Scribe_Values.Look(ref crampPain, "crampPain", crampPain, true); Scribe_Values.Look(ref crampPain, "crampPain", crampPain, true);
Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true); Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true);
@ -925,17 +899,16 @@ namespace RJW_Menstruation
if (!Props.infertile) if (!Props.infertile)
{ {
if (follicularIntervalhours < 0) if (cycleSpeed < 1) cycleSpeed = Utility.RandGaussianLike(0.8f, 1.2f);
if (cycleVariability < 1) cycleVariability = Utility.RandomVariabilityPercent();
if (currentIntervalhours < 0)
{ {
follicularIntervalhours = PeriodRandomizer(Props.follicularIntervalDays * 24, Props.deviationFactor); //follicularIntervalhours = PeriodRandomizer(Props.follicularIntervalDays * 24, Props.deviationFactor);
if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young; if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young;
else if (!IsBreedingSeason()) curStage = Stage.Anestrus; else if (!IsBreedingSeason()) curStage = Stage.Anestrus;
else curStage = RandomStage(); else curStage = RandomStage();
currentIntervalhours = PeriodRandomizer(curStage);
} }
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 (crampPain < 0) crampPain = PainRandomizer();
if (cums == null) cums = new List<Cum>(); if (cums == null) cums = new List<Cum>();
if (eggs == null) eggs = new List<Egg>(); if (eggs == null) eggs = new List<Egg>();
@ -1323,7 +1296,7 @@ namespace RJW_Menstruation
Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_MenstrualCramp, parent.pawn); Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_MenstrualCramp, parent.pawn);
hediff.Severity = crampPain * Rand.Range(0.9f, 1.1f); hediff.Severity = crampPain * Rand.Range(0.9f, 1.1f);
HediffCompProperties_SeverityPerDay Prop = (HediffCompProperties_SeverityPerDay)hediff.TryGetComp<HediffComp_SeverityPerDay>().props; HediffCompProperties_SeverityPerDay Prop = (HediffCompProperties_SeverityPerDay)hediff.TryGetComp<HediffComp_SeverityPerDay>().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)); parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn));
} }
@ -1334,14 +1307,14 @@ namespace RJW_Menstruation
GoNextStage(Stage.Anestrus); GoNextStage(Stage.Anestrus);
return; return;
} }
if (curStageHrs >= FollicularIntervalHours) if (curStageHrs >= currentIntervalhours)
{ {
GoNextStage(Stage.Ovulatory); GoNextStage(Stage.Ovulatory);
} }
else else
{ {
curStageHrs += Configurations.CycleAcceleration; curStageHrs += Configurations.CycleAcceleration;
if (!estrusflag && curStageHrs > FollicularIntervalHours - Props.estrusDaysBeforeOvulation * 24) if (!estrusflag && curStageHrs > currentIntervalhours - Props.estrusDaysBeforeOvulation * 24)
{ {
estrusflag = true; estrusflag = true;
SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation); SetEstrus(Props.eggLifespanDays + Props.estrusDaysBeforeOvulation);
@ -1392,12 +1365,10 @@ namespace RJW_Menstruation
Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn); Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn);
hediff.Severity = 0.008f * i; hediff.Severity = 0.008f * i;
parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn)); parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn));
lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor * 6);
GoNextStage(Stage.ClimactericLuteal); GoNextStage(Stage.ClimactericLuteal);
} }
else else
{ {
lutealIntervalhours = PeriodRandomizer(lutealIntervalhours, Props.deviationFactor);
GoNextStage(Stage.Luteal); GoNextStage(Stage.Luteal);
} }
} }
@ -1422,7 +1393,7 @@ namespace RJW_Menstruation
StayCurrentStage(); StayCurrentStage();
} }
} }
else if (curStageHrs <= lutealIntervalhours) else if (curStageHrs <= currentIntervalhours)
{ {
curStageHrs += Configurations.CycleAcceleration; curStageHrs += Configurations.CycleAcceleration;
StayCurrentStage(); StayCurrentStage();
@ -1432,12 +1403,10 @@ namespace RJW_Menstruation
eggs.Clear(); eggs.Clear();
if (Props.bleedingIntervalDays == 0) if (Props.bleedingIntervalDays == 0)
{ {
follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor);
GoNextStage(Stage.Follicular); GoNextStage(Stage.Follicular);
} }
else else
{ {
bleedingIntervalhours = PeriodRandomizer(bleedingIntervalhours, Props.deviationFactor);
if (crampPain >= 0.05f) if (crampPain >= 0.05f)
{ {
AddCrampPain(); AddCrampPain();
@ -1449,16 +1418,22 @@ namespace RJW_Menstruation
protected virtual void BleedingAction() protected virtual void BleedingAction()
{ {
if (curStageHrs >= bleedingIntervalhours) if (curStageHrs >= currentIntervalhours)
{ {
follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor);
Hediff hediff = parent.pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp); Hediff hediff = parent.pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp);
if (hediff != null) parent.pawn.health.RemoveHediff(hediff); if (hediff != null) parent.pawn.health.RemoveHediff(hediff);
GoNextStage(Stage.Follicular); 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
GoNextStage(Stage.Ovulatory);
else
{
currentIntervalhours = totalFollicularHours - currentIntervalhours;
GoNextStage(Stage.Follicular, false);
}
} }
else 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; curStageHrs += Configurations.CycleAcceleration;
StayCurrentStage(); StayCurrentStage();
} }
@ -1490,7 +1465,7 @@ namespace RJW_Menstruation
protected virtual void RecoverAction() protected virtual void RecoverAction()
{ {
if (curStageHrs >= recoveryIntervalhours) if (curStageHrs >= currentIntervalhours)
{ {
if (Configurations.EnableMenopause && ovarypower < OvaryPowerThreshold) if (Configurations.EnableMenopause && ovarypower < OvaryPowerThreshold)
{ {
@ -1502,7 +1477,6 @@ namespace RJW_Menstruation
} }
else else
{ {
follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor);
GoNextStage(Stage.Follicular); GoNextStage(Stage.Follicular);
} }
} }
@ -1523,7 +1497,11 @@ namespace RJW_Menstruation
{ {
StayCurrentStageConst(Stage.Young); StayCurrentStageConst(Stage.Young);
} }
else GoNextStage(IsBreedingSeason() ? Stage.Follicular : Stage.Anestrus); else
{
bool breedingSeason = IsBreedingSeason();
GoNextStage(breedingSeason ? Stage.Follicular : Stage.Anestrus, breedingSeason);
}
} }
protected virtual void ClimactericFollicularAction() protected virtual void ClimactericFollicularAction()
@ -1533,13 +1511,12 @@ namespace RJW_Menstruation
RemoveClimactericEffect(); RemoveClimactericEffect();
StayCurrentStage(); StayCurrentStage();
} }
else if (curStageHrs >= (follicularIntervalhours - bleedingIntervalhours) * CycleFactor) else if (curStageHrs >= currentIntervalhours)
{ {
GoNextStage(Stage.Ovulatory); GoNextStage(Stage.Ovulatory);
} }
else if (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.2f) //skips 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); GoNextStage(Stage.ClimactericLuteal);
} }
else else
@ -1567,7 +1544,7 @@ namespace RJW_Menstruation
StayCurrentStage(); StayCurrentStage();
} }
} }
else if (curStageHrs <= lutealIntervalhours) else if (curStageHrs <= currentIntervalhours)
{ {
curStageHrs += Configurations.CycleAcceleration; curStageHrs += Configurations.CycleAcceleration;
StayCurrentStage(); StayCurrentStage();
@ -1577,17 +1554,14 @@ namespace RJW_Menstruation
eggs.Clear(); eggs.Clear();
if (Props.bleedingIntervalDays == 0) if (Props.bleedingIntervalDays == 0)
{ {
follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor * 6);
GoNextStage(Stage.ClimactericFollicular); GoNextStage(Stage.ClimactericFollicular);
} }
else if (ovarypower < OvaryPowerThreshold / 4 || (ovarypower < OvaryPowerThreshold / 3 && Rand.Range(0.0f, 1.0f) < 0.3f)) //skips bleeding 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); GoNextStage(Stage.ClimactericFollicular);
} }
else else
{ {
bleedingIntervalhours = PeriodRandomizer(bleedingIntervalhours, Props.deviationFactor);
if (crampPain >= 0.05f) if (crampPain >= 0.05f)
{ {
AddCrampPain(); AddCrampPain();
@ -1604,14 +1578,22 @@ namespace RJW_Menstruation
RemoveClimactericEffect(); RemoveClimactericEffect();
StayCurrentStage(); StayCurrentStage();
} }
else if (curStageHrs >= bleedingIntervalhours) else if (curStageHrs >= currentIntervalhours)
{ {
follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor * 6); Hediff hediff = parent.pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp);
GoNextStage(Stage.ClimactericFollicular); if (hediff != null) parent.pawn.health.RemoveHediff(hediff);
int totalFollicularHours = PeriodRandomizer(Stage.Follicular);
if (totalFollicularHours <= currentIntervalhours)
GoNextStage(Stage.Ovulatory);
else
{
currentIntervalhours = totalFollicularHours - currentIntervalhours;
GoNextStage(Stage.Follicular, false);
}
} }
else else
{ {
if (curStageHrs < bleedingIntervalhours / 6) 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; curStageHrs += Configurations.CycleAcceleration;
StayCurrentStage(); StayCurrentStage();
} }
@ -1733,7 +1715,7 @@ namespace RJW_Menstruation
default: default:
curStage = Stage.Follicular; curStage = Stage.Follicular;
curStageHrs = 0; curStageHrs = 0;
if (follicularIntervalhours < 0) follicularIntervalhours = PeriodRandomizer(Props.follicularIntervalDays * 24, Props.deviationFactor); if (currentIntervalhours < 0) currentIntervalhours = PeriodRandomizer(curStage);
HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Follicular), GetNextUpdate(), parent.pawn, false); HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Follicular), GetNextUpdate(), parent.pawn, false);
break; break;
} }
@ -1763,17 +1745,11 @@ namespace RJW_Menstruation
return ((nextOffset - currentOffset + tickInterval - 1) % tickInterval) + 1; return ((nextOffset - currentOffset + tickInterval - 1) % tickInterval) + 1;
} }
protected void GoNextStage(Stage nextstage) protected void GoNextStage(Stage nextstage, bool calculateHours = true)
{ {
curStageHrs = 0; curStageHrs = 0;
curStage = nextstage; float variabilityFactor = nextstage == Stage.ClimactericFollicular || nextstage == Stage.ClimactericLuteal || nextstage == Stage.ClimactericBleeding ? 6f : 1f;
HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(nextstage), GetNextUpdate(), parent.pawn, false); if (calculateHours) currentIntervalhours = PeriodRandomizer(nextstage, variabilityFactor);
}
protected void GoNextStageSetHour(Stage nextstage, int hour)
{
curStageHrs = hour;
curStage = nextstage; curStage = nextstage;
HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(nextstage), GetNextUpdate(), parent.pawn, false); HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(nextstage), GetNextUpdate(), parent.pawn, false);
} }
@ -1794,12 +1770,10 @@ namespace RJW_Menstruation
{ {
if (Props.bleedingIntervalDays == 0) if (Props.bleedingIntervalDays == 0)
{ {
follicularIntervalhours = PeriodRandomizer(follicularIntervalhours, Props.deviationFactor);
GoNextStage(Stage.Follicular); GoNextStage(Stage.Follicular);
} }
else else
{ {
bleedingIntervalhours = PeriodRandomizer(bleedingIntervalhours, Props.deviationFactor);
GoNextStage(Stage.Bleeding); GoNextStage(Stage.Bleeding);
} }
} }
@ -1820,6 +1794,27 @@ namespace RJW_Menstruation
return intervalhours + (int)(intervalhours * Rand.Range(-deviation, deviation)); return intervalhours + (int)(intervalhours * Rand.Range(-deviation, deviation));
} }
protected int PeriodRandomizer(Stage stage, float variabilityFactor = 1f)
{
// 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 * (cycleSpeed * 1.5f) * (1 + Rand.Range(-cycleVariability, cycleVariability) * 1.5f * variabilityFactor));
case Stage.Luteal:
case Stage.ClimactericLuteal:
return (int)(Props.lutealIntervalDays * 24 * (cycleSpeed * 0.5f) * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor));
case Stage.Bleeding:
case Stage.ClimactericBleeding:
return (int)(Props.bleedingIntervalDays * 24 * (cycleSpeed * 0.5f) * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor));
case Stage.Recover:
return (int)(Props.recoveryIntervalDays * 24 * Rand.Range(-0.05f, 0.05f));
default: // Can happen on init, shouldn't happen during a cycle
return 1;
}
}
protected float InterspeciesImplantFactor(Pawn fertilizer) protected float InterspeciesImplantFactor(Pawn fertilizer)
{ {
if (fertilizer.def.defName == parent.pawn.def.defName) return 1.0f; if (fertilizer.def.defName == parent.pawn.def.defName) return 1.0f;

View file

@ -439,6 +439,21 @@ namespace RJW_Menstruation
} }
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;
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 float LerpMultiple(this float a, float b, float t, int num) public static float LerpMultiple(this float a, float b, float t, int num)
{ {
float tmult = Mathf.Pow(1 - t, num); float tmult = Mathf.Pow(1 - t, num);