mirror of
https://gitgud.io/lutepickle/rjw_menstruation.git
synced 2024-08-14 22:46:52 +00:00
Initial implementation of variable update rate
This commit is contained in:
parent
2696c2b1f0
commit
e37940abcf
13 changed files with 267 additions and 163 deletions
Binary file not shown.
|
@ -56,6 +56,12 @@
|
|||
<Option6_Desc>Cum will lose fertility by this amount every hour This value affects fertilization chance indirectly.</Option6_Desc>
|
||||
<Option7_Label>Cycle acceleration</Option7_Label>
|
||||
<Option7_Desc>Accelerate menstruation cycle This can cause early menopause and infertility. Setting this lower than x12 is recommended. Rimworld's timescale: x6(default)</Option7_Desc>
|
||||
<Option_ColonistUpdateInterval_Label>Colonist update interval</Option_ColonistUpdateInterval_Label>
|
||||
<Option_ColonistUpdateInterval_Desc>How often the womb of each of your colonists, prisoners, and slaves update. Lowering this will improve accuracy, increasing this can improve performance.</Option_ColonistUpdateInterval_Desc>
|
||||
<Option_NonColonistUpdateInterval_Label>Non-colonist update interval</Option_NonColonistUpdateInterval_Label>
|
||||
<Option_NonColonistUpdateInterval_Desc>How often the womb of humans you don't control update. Lowering this will improve accuracy, increasing this can improve performance.</Option_NonColonistUpdateInterval_Desc>
|
||||
<Option_AnimalUpdateInterval_Label>Animal update interval</Option_AnimalUpdateInterval_Label>
|
||||
<Option_AnimalUpdateInterval_Desc>How often the womb of animals update. Lowering this will improve accuracy, increasing this can improve performance.</Option_AnimalUpdateInterval_Desc>
|
||||
<Option8_Label>Debug</Option8_Label>
|
||||
<Option8_Desc>Show debug information.</Option8_Desc>
|
||||
<Option9_Label>Womb status</Option9_Label>
|
||||
|
|
Binary file not shown.
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<Egg> 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
|
|||
/// <summary>
|
||||
/// returns fertstage. if not fertilized returns -1
|
||||
/// </summary>
|
||||
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<Pawn> 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
|
|||
/// <returns></returns>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -825,17 +847,17 @@ namespace RJW_Menstruation
|
|||
/// <summary>
|
||||
/// Inject pawn's cum into womb
|
||||
/// </summary>
|
||||
/// <param name="pawn"></param>
|
||||
/// <param name="cummer"></param>
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="fertility"></param>
|
||||
/// <param name="precum"></param>
|
||||
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
|
|||
/// <summary>
|
||||
/// Inject pawn's fluid into womb
|
||||
/// </summary>
|
||||
/// <param name="pawn"></param>
|
||||
/// <param name="cummer"></param>
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="notcumlabel"></param>
|
||||
/// <param name="decayresist"></param>
|
||||
/// <param name="filthdef"></param>
|
||||
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<string> filthlabels = new List<string>();
|
||||
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<Cum> removecums = new HashSet<Cum>();
|
||||
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);
|
||||
}
|
||||
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 => removecums.Contains(cum));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1297,8 +1322,10 @@ namespace RJW_Menstruation
|
|||
|
||||
float totalFertPower = eligibleCum.Sum(cum => cum.FertVolume);
|
||||
|
||||
if (Rand.Chance(Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor)))
|
||||
return null;
|
||||
float fertFailChancePerHour = Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor);
|
||||
float fertFailChancePerInterval = Mathf.Pow(fertFailChancePerHour, (float)TickInterval / GenDate.TicksPerHour);
|
||||
|
||||
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<Egg> deadeggs = new HashSet<Egg>();
|
||||
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<HediffComp_SeverityPerDay>().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()
|
||||
{
|
||||
Scribe_References.Look(ref fertilizer, "fertilizer", true);
|
||||
Scribe_Values.Look(ref fertilized, "fertilized", fertilized, true);
|
||||
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 lifeSpanTicks, "lifeSpanTicks", lifeSpanTicks, true);
|
||||
Scribe_Values.Look(ref ageTicks, "ageTicks", ageTicks, true);
|
||||
Scribe_Values.Look(ref ticksSinceFertilization, "ticksSinceFertilization", ticksSinceFertilization, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Texture2D>.Get((comp.OvulationChance >= ovaryChanceToShow_01) ? "Ovaries/Ovary_01" : "Ovaries/Ovary_00", true);
|
||||
return ContentFinder<Texture2D>.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<Texture2D>.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<Texture2D>.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<Texture2D>.Get("Ovaries/Ovary_02", true);
|
||||
else if (comp.OvulationChance >= ovaryChanceToShow_01)
|
||||
else if (ovulationChance >= ovaryChanceToShow_01)
|
||||
return ContentFinder<Texture2D>.Get("Ovaries/Ovary_01", true);
|
||||
else
|
||||
return ContentFinder<Texture2D>.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<Texture2D>.Get("Eggs/Egg_Fertilizing02", true);
|
||||
else if (fertstage <= 18) return ContentFinder<Texture2D>.Get("Eggs/Egg_Fertilized00", true);
|
||||
else if (fertstage <= 54) return ContentFinder<Texture2D>.Get("Eggs/Egg_Fertilized01", true);
|
||||
if (fertTime <= GenDate.TicksPerHour * Configurations.CycleAcceleration) return ContentFinder<Texture2D>.Get("Eggs/Egg_Fertilizing02", true);
|
||||
else if (fertTime <= 18 * GenDate.TicksPerHour) return ContentFinder<Texture2D>.Get("Eggs/Egg_Fertilized00", true);
|
||||
else if (fertTime <= 54 * GenDate.TicksPerHour) return ContentFinder<Texture2D>.Get("Eggs/Egg_Fertilized01", true);
|
||||
else return ContentFinder<Texture2D>.Get("Eggs/Egg_Fertilized02", true);
|
||||
}
|
||||
else if (comp.IsEggFertilizing)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<AbsorberModExtension>().leakAfterDirty;
|
||||
public virtual bool EffectAfterDirty => def.GetModExtension<AbsorberModExtension>().effectsAfterDirty;
|
||||
public virtual ThingDef DirtyDef => def.GetModExtension<AbsorberModExtension>().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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue