using RimWorld; 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 ticksToNextCycle = -100000; public int averageCycleIntervalTicks = -1; public new CompProperties_PeriodicOvulator Props; protected override void PreInitialize() { base.PreInitialize(); Props = (CompProperties_PeriodicOvulator)props; } protected override void 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) && (averageCycleIntervalTicks - ticksToNextCycle) / 2 >= GenDate.TicksPerDay * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed) GoNextStage(Stage.Anestrus); } } protected override float RaceCyclesPerYear() { // Don't bother trying to work seasonal breeding into the math // Base it off of the shortest cycle interval of the vagina return GenDate.DaysPerYear / (Props.cycleIntervalDays.TrueMin / Configurations.CycleAccelerationDefault); } protected override void BeforeSimulator() { base.BeforeSimulator(); if (ticksToNextCycle > 0) ticksToNextCycle -= TickInterval * Configurations.CycleAcceleration; } public override void CompExposeData() { base.CompExposeData(); 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 TicksToNextStage() { if (curStage == Stage.Anestrus && ticksToNextCycle > 0) return ticksToNextCycle / Configurations.CycleAcceleration; else return base.TicksToNextStage(); } protected override void LutealAction() { base.LutealAction(); if (curStage == Stage.Follicular) GoNextStage(Stage.Anestrus); } protected override void BleedingAction() { base.BleedingAction(); if (curStage != Stage.Bleeding) { estrusflag = false; GoNextStage(Stage.Anestrus); } } protected override void PregnantAction() { base.PregnantAction(); if (curStage != Stage.Pregnant) // Go halfway into the cycle ticksToNextCycle = (int)Utility.VariationRange(averageCycleIntervalTicks, cycleVariability) / 2; } protected override void AnestrusAction() { if (ticksToNextCycle <= 0 && IsBreedingSeason()) { ticksToNextCycle = (int)Utility.VariationRange(averageCycleIntervalTicks, cycleVariability); GoNextStage(Stage.Follicular); } } public override void CopyCycleProperties(HediffComp_Menstruation original) { base.CopyCycleProperties(original); if (original is HediffComp_PeriodicOvulator comp) averageCycleIntervalTicks = comp.averageCycleIntervalTicks; } } }