using RimWorld; using System.Linq; using Verse; namespace RJW_Menstruation { public class CompProperties_PeriodicOvulator : CompProperties_Menstruation { public FloatRange cycleIntervalDays; // From the start of one cycle to the start of the next public CompProperties_PeriodicOvulator() { compClass = typeof(HediffComp_PeriodicOvulator); } } public class HediffComp_PeriodicOvulator : HediffComp_Menstruation { public int hoursToNextCycle = -100000; public int averageCycleIntervalHours = -1; public new CompProperties_PeriodicOvulator Props; protected override void InitializeExtraValues() { base.InitializeExtraValues(); Props = (CompProperties_PeriodicOvulator)props; if (averageCycleIntervalHours < 0) { averageCycleIntervalHours = (int)(24f * Props.cycleIntervalDays.RandomInRange / cycleSpeed); if (hoursToNextCycle < -50000) hoursToNextCycle = Rand.Range(0, averageCycleIntervalHours); // 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) curStage = Stage.Anestrus; } } protected override float RaceCyclesPerYear() { // 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 } protected override void BeforeSimulator() { base.BeforeSimulator(); if (hoursToNextCycle > 0) hoursToNextCycle -= Configurations.CycleAcceleration; } public override void CompExposeData() { base.CompExposeData(); Scribe_Values.Look(ref hoursToNextCycle, "hoursToNextCycle", hoursToNextCycle, true); Scribe_Values.Look(ref averageCycleIntervalHours, "averageCycleIntervalHours", averageCycleIntervalHours, true); } protected override void BleedingAction() { if (curStageHrs >= currentIntervalHours) { 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); estrusflag = false; GoNextStage(Stage.Anestrus); return; } else base.BleedingAction(); } protected override void PregnantAction() { base.PregnantAction(); if (curStage != Stage.Pregnant) // Go halfway into the cycle hoursToNextCycle = (int)(averageCycleIntervalHours * (1 + Rand.Range(-cycleVariability, cycleVariability))) / 2; } protected override void AnestrusAction() { if (hoursToNextCycle <= 0) { hoursToNextCycle = (int)(averageCycleIntervalHours * (1 + Rand.Range(-cycleVariability, cycleVariability))); if (IsBreedingSeason()) GoNextStage(Stage.Follicular); return; } StayCurrentStage(); } public override void CopyCycleProperties(HediffComp_Menstruation original) { base.CopyCycleProperties(original); if (original is HediffComp_PeriodicOvulator comp) averageCycleIntervalHours = comp.averageCycleIntervalHours; } } }