Compare commits

..

1 commit

Author SHA1 Message Date
Akiyami Solo
4382decbc7 Merge branch 'dev' into 'dev'
Breast fullness is not displayed and the "milk yourself" action is not invoked on a pawn when the rjw-mc-biotech mod is present

See merge request lutepickle/rjw_menstruation!6
2024-02-11 23:35:27 +00:00
10 changed files with 122 additions and 57 deletions

Binary file not shown.

View file

@ -145,4 +145,10 @@
</comps> </comps>
</value> </value>
</Operation> </Operation>
</Patch> </Patch>

View file

@ -110,6 +110,9 @@ namespace RJW_Menstruation
else return base.ShouldBeInEstrus(); else return base.ShouldBeInEstrus();
} }
protected override float RandomOvulationChance => 0; protected override float RandomOvulationChance()
{
return 0;
}
} }
} }

View file

@ -127,6 +127,7 @@ namespace RJW_Menstruation
protected float implantationChanceCache = -1.0f; protected float implantationChanceCache = -1.0f;
protected int opcache = -1; protected int opcache = -1;
protected float antisperm = 0.0f; protected float antisperm = 0.0f;
protected float? originvagsize = null;
// RJW pregnancy, or Biotech pregnancy/labor/laborpushing // RJW pregnancy, or Biotech pregnancy/labor/laborpushing
protected Hediff pregnancy = null; protected Hediff pregnancy = null;
@ -178,8 +179,7 @@ namespace RJW_Menstruation
public float HoursBetweenSimulations => (float)TickInterval / GenDate.TicksPerHour; public float HoursBetweenSimulations => (float)TickInterval / GenDate.TicksPerHour;
public Hediff Pregnancy public Hediff Pregnancy {
{
get get
{ {
if (pregnancy == null) return null; if (pregnancy == null) return null;
@ -322,7 +322,6 @@ namespace RJW_Menstruation
// Implant factor will be based solely on pawn age, plus any rollover from ovulation chance // Implant factor will be based solely on pawn age, plus any rollover from ovulation chance
float factor = 1.0f; float factor = 1.0f;
StatDefOf.Fertility.GetStatPart<StatPart_FertilityByGenderAge>()?.TransformValue(StatRequest.For(Pawn), ref factor); StatDefOf.Fertility.GetStatPart<StatPart_FertilityByGenderAge>()?.TransformValue(StatRequest.For(Pawn), ref factor);
if (factor <= 0.0f) return 0.0f;
if (OvulationChance > 1.0f) factor *= OvulationChance; if (OvulationChance > 1.0f) factor *= OvulationChance;
return Props.baseImplantationChanceFactor * FertilityModifier * factor; return Props.baseImplantationChanceFactor * FertilityModifier * factor;
} }
@ -564,6 +563,19 @@ namespace RJW_Menstruation
} }
} }
public float OriginVagSize
{
get
{
if (originvagsize == null)
{
originvagsize = parent.Severity;
}
return originvagsize ?? 0.1f;
}
set => originvagsize = value;
}
public int CurStageIntervalTicks public int CurStageIntervalTicks
{ {
get => currentIntervalTicks; get => currentIntervalTicks;
@ -644,6 +656,7 @@ namespace RJW_Menstruation
Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true); Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true);
Scribe_Values.Look(ref eggstack, "eggstack", 0); Scribe_Values.Look(ref eggstack, "eggstack", 0);
Scribe_Values.Look(ref estrusflag, "estrusflag", false); Scribe_Values.Look(ref estrusflag, "estrusflag", false);
Scribe_Values.Look(ref originvagsize, "originvagsize", originvagsize, true);
Scribe_Values.Look(ref DoCleanWomb, "DoCleanWomb", false); Scribe_Values.Look(ref DoCleanWomb, "DoCleanWomb", false);
Scribe_References.Look(ref pregnancy, "pregnancy"); Scribe_References.Look(ref pregnancy, "pregnancy");
if (Scribe.mode == LoadSaveMode.PostLoadInit) if (Scribe.mode == LoadSaveMode.PostLoadInit)
@ -668,8 +681,10 @@ namespace RJW_Menstruation
opcache = -1; opcache = -1;
if (Pawn.genes == null || !ModsConfig.BiotechActive) return; if (Pawn.genes == null || !ModsConfig.BiotechActive) return;
foreach (MenstruationModExtension extension in Pawn.genes.GenesListForReading.Select(gene => gene.def.GetModExtension<MenstruationModExtension>()).Where(ext => ext != null)) foreach (MenstruationModExtension extension in Pawn.genes.GenesListForReading.Select(gene => gene.def.GetModExtension<MenstruationModExtension>()))
{ {
if (extension == null) continue;
eggLifeSpanTicks = (int)(eggLifeSpanTicks * extension.eggLifeTimeFactor); eggLifeSpanTicks = (int)(eggLifeSpanTicks * extension.eggLifeTimeFactor);
if (extension.alwaysEstrus) estrusLevel = EstrusLevel.Visible; if (extension.alwaysEstrus) estrusLevel = EstrusLevel.Visible;
else if (extension.neverEstrus) estrusLevel = EstrusLevel.None; else if (extension.neverEstrus) estrusLevel = EstrusLevel.None;
@ -1562,6 +1577,9 @@ namespace RJW_Menstruation
return amount; return amount;
} }
protected void EggDecay() protected void EggDecay()
{ {
HashSet<Egg> deadeggs = new HashSet<Egg>(); HashSet<Egg> deadeggs = new HashSet<Egg>();
@ -1638,7 +1656,7 @@ namespace RJW_Menstruation
eggnum = 1f; eggnum = 1f;
} }
eggnum *= ovulationFactor; eggnum *= ovulationFactor;
int toOvulate = Math.Max(1, (int)eggnum + eggstack); int toOvulate = (int)eggnum + eggstack;
int ovulated = 0; int ovulated = 0;
for (int i = 0; i < toOvulate; i++) for (int i = 0; i < toOvulate; i++)
@ -1649,7 +1667,7 @@ namespace RJW_Menstruation
} }
ovarypower -= ovulated; ovarypower -= ovulated;
eggstack = 0; eggstack = 0;
if (Configurations.Debug && ovulated < toOvulate) if (Configurations.Debug && ovulated != toOvulate)
Log.Message($"{Pawn} ovulated {ovulated}/{toOvulate} eggs ({OvulationChance.ToStringPercent()} chance)"); Log.Message($"{Pawn} ovulated {ovulated}/{toOvulate} eggs ({OvulationChance.ToStringPercent()} chance)");
GoNextStage(Stage.Luteal); GoNextStage(Stage.Luteal);
@ -1896,13 +1914,16 @@ namespace RJW_Menstruation
else return Rand.Range(0.6f, 1.0f); else return Rand.Range(0.6f, 1.0f);
} }
protected virtual float RandomOvulationChance => (float)Props.ovulationIntervalHours / GenDate.HoursPerDay; protected virtual float RandomOvulationChance()
{
return (float)Props.ovulationIntervalHours / GenDate.HoursPerDay;
}
protected Stage RandomStage() protected Stage RandomStage()
{ {
Stage stage = Rand.ElementByWeight( Stage stage = Rand.ElementByWeight(
Stage.Follicular, Props.follicularIntervalDays - Props.bleedingIntervalDays, Stage.Follicular, Props.follicularIntervalDays - Props.bleedingIntervalDays,
Stage.Ovulatory, RandomOvulationChance, Stage.Ovulatory, RandomOvulationChance(),
Stage.Luteal, Props.lutealIntervalDays, Stage.Luteal, Props.lutealIntervalDays,
Stage.Bleeding, Props.bleedingIntervalDays); Stage.Bleeding, Props.bleedingIntervalDays);
@ -2014,6 +2035,28 @@ namespace RJW_Menstruation
public class HediffComp_Anus : HediffComp public class HediffComp_Anus : HediffComp
{ {
public CompProperties_Anus Props => (CompProperties_Anus)props; protected float? originanussize;
public float OriginAnusSize
{
get
{
if (originanussize == null)
{
originanussize = parent.Severity;
}
return originanussize ?? 0.1f;
}
}
public override void CompExposeData()
{
base.CompExposeData();
Scribe_Values.Look(ref originanussize, "originanussize", originanussize, true);
}
public override void CompPostTick(ref float severityAdjustment)
{
}
} }
} }

View file

@ -36,7 +36,7 @@ namespace RJW_Menstruation
if (ticksToNextCycle < -50000) if (ticksToNextCycle < -50000)
ticksToNextCycle = Rand.Range(0, averageCycleIntervalTicks); ticksToNextCycle = Rand.Range(0, averageCycleIntervalTicks);
// Make the cutoff halfway into cycle, just to be sure there isn't a double-cycle the first time // 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) if ((curStage == Stage.Follicular || curStage == Stage.Luteal || curStage == Stage.Bleeding)
&& (averageCycleIntervalTicks - ticksToNextCycle) / 2 >= GenDate.TicksPerDay * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed) && (averageCycleIntervalTicks - ticksToNextCycle) / 2 >= GenDate.TicksPerDay * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed)
GoNextStage(Stage.Anestrus); GoNextStage(Stage.Anestrus);
} }

View file

@ -141,7 +141,7 @@ namespace RJW_Menstruation
else if (gestationProgress < 0.8f) icon = fetustex + "04"; else if (gestationProgress < 0.8f) icon = fetustex + "04";
else icon = fetustex + "05"; else icon = fetustex + "05";
return TryGetTwinsIcon(icon, babycount) ?? ContentFinder<Texture2D>.Get(icon, true); return TryGetTwinsIcon(icon, babycount) ?? ContentFinder<Texture2D>.Get((icon), true);
} }
public static Texture2D TryGetTwinsIcon(string path, int babycount) public static Texture2D TryGetTwinsIcon(string path, int babycount)
@ -160,7 +160,7 @@ namespace RJW_Menstruation
List<Hediff_InsectEgg> insectEggs = new List<Hediff_InsectEgg>(); List<Hediff_InsectEgg> insectEggs = new List<Hediff_InsectEgg>();
comp.Pawn.health.hediffSet.GetHediffs(ref insectEggs); comp.Pawn.health.hediffSet.GetHediffs(ref insectEggs);
if (insectEggs?.Sum(hediff => hediff.eggssize) > 1.0f) return null; // same logic as "Stuffed" in GetInsectEggedIcon if (!insectEggs.NullOrEmpty() && insectEggs.Sum(hediff => hediff.eggssize) > 1.0f) return null; // same logic as "Stuffed" in GetInsectEggedIcon
string icon = comp.WombTex; string icon = comp.WombTex;
float cumpercent = comp.TotalCumPercent; float cumpercent = comp.TotalCumPercent;
@ -183,7 +183,7 @@ namespace RJW_Menstruation
else if (cumpercent < 0.89f) icon += "_Cum_15"; else if (cumpercent < 0.89f) icon += "_Cum_15";
else if (cumpercent < 0.95f) icon += "_Cum_16"; else if (cumpercent < 0.95f) icon += "_Cum_16";
else icon += "_Cum_17"; else icon += "_Cum_17";
Texture2D cumtex = ContentFinder<Texture2D>.Get(icon, true); Texture2D cumtex = ContentFinder<Texture2D>.Get((icon), true);
return cumtex; return cumtex;
} }
public static Texture2D GetInsectEggedIcon(this HediffComp_Menstruation comp) public static Texture2D GetInsectEggedIcon(this HediffComp_Menstruation comp)
@ -306,13 +306,15 @@ namespace RJW_Menstruation
} }
public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp) public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp, bool drawOrigin = false)
{ {
Hediff hediff = comp?.parent; Hediff hediff = comp?.parent;
if (hediff == null) return ContentFinder<Texture2D>.Get("Genitals/Vagina00", true); if (hediff == null) return ContentFinder<Texture2D>.Get("Genitals/Vagina00", true);
//HediffComp_Menstruation comp = hediff.GetMenstruationComp(); //HediffComp_Menstruation comp = hediff.GetMenstruationComp();
string icon; string icon;
float severity = hediff.Severity; float severity;
if (drawOrigin) severity = comp.OriginVagSize;
else severity = hediff.Severity;
if (comp != null) icon = comp.VagTex; if (comp != null) icon = comp.VagTex;
else icon = "Genitals/Vagina"; else icon = "Genitals/Vagina";
@ -329,18 +331,30 @@ namespace RJW_Menstruation
else if (severity < 1.01f) icon += "10"; //cavernous else if (severity < 1.01f) icon += "10"; //cavernous
else icon += "11"; //abyssal else icon += "11"; //abyssal
return ContentFinder<Texture2D>.Get(icon, true); return ContentFinder<Texture2D>.Get((icon), true);
} }
public static Texture2D GetAnalIcon(this Pawn pawn) public static Texture2D GetAnalIcon(this Pawn pawn, bool drawOrigin = false)
{ {
Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ?? Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ??
pawn.health.hediffSet.hediffs.FirstOrDefault(h => h.def.defName.ToLower().Contains("anus")); pawn.health.hediffSet.hediffs.FirstOrDefault(h => h.def.defName.ToLower().Contains("anus"));
if (hediff == null) return ContentFinder<Texture2D>.Get("Genitals/Anal00", true); if (hediff == null) return ContentFinder<Texture2D>.Get(("Genitals/Anal00"), true);
string icon = ((CompProperties_Anus)hediff.GetAnusComp()?.props)?.analTex ?? "Genitals/Anal";
float severity = hediff.Severity;
string icon;
float severity;
HediffComp_Anus comp = hediff.GetAnusComp();
if (comp != null)
{
CompProperties_Anus Props = (CompProperties_Anus)comp.props;
icon = Props.analTex ?? "Genitals/Anal";
if (drawOrigin) severity = comp.OriginAnusSize;
else severity = hediff.Severity;
}
else
{
icon = "Genitals/Anal";
severity = hediff.Severity;
}
if (severity < 0.20f) icon += "00"; //micro if (severity < 0.20f) icon += "00"; //micro
else if (severity < 0.40f) icon += "01"; //tight else if (severity < 0.40f) icon += "01"; //tight
else if (severity < 0.60f) icon += "02"; //average else if (severity < 0.60f) icon += "02"; //average
@ -348,7 +362,7 @@ namespace RJW_Menstruation
else if (severity < 1.01f) icon += "04"; //cavernous else if (severity < 1.01f) icon += "04"; //cavernous
else icon += "05"; //abyssal else icon += "05"; //abyssal
return ContentFinder<Texture2D>.Get(icon, true); return ContentFinder<Texture2D>.Get((icon), true);
} }
public static float GestationHours(this Hediff hediff) public static float GestationHours(this Hediff hediff)

View file

@ -225,7 +225,9 @@ namespace RJW_Menstruation
bool newHasStats = !DirtyDef.equippedStatOffsets.NullOrEmpty(); bool newHasStats = !DirtyDef.equippedStatOffsets.NullOrEmpty();
def = DirtyDef; def = DirtyDef;
dirty = true; dirty = true;
Wearer.outfits?.forcedHandler?.SetForced(this, false); OutfitForcedHandler forcedHandler = Wearer.outfits?.forcedHandler;
if (forcedHandler?.IsForced(this) ?? false)
forcedHandler.SetForced(this, false);
if (oldHasStats || newHasStats) if (oldHasStats || newHasStats)
Wearer.health.capacities.Notify_CapacityLevelsDirty(); Wearer.health.capacities.Notify_CapacityLevelsDirty();
Wearer.apparel.Notify_ApparelChanged(); Wearer.apparel.Notify_ApparelChanged();
@ -272,7 +274,7 @@ namespace RJW_Menstruation
public override void DirtyEffect(int tickInterval) public override void DirtyEffect(int tickInterval)
{ {
if (wearTicks > MinHrstoDirtyEffect * GenDate.TicksPerHour && Rand.MTBEventOccurs(100.0f, GenDate.TicksPerHour, tickInterval) && !(Wearer.apparel?.IsLocked(this) ?? false)) 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)); Wearer.health.AddHediff(HediffDefOf.WoundInfection, Genital_Helper.get_genitalsBPR(Wearer));
} }

View file

@ -388,9 +388,10 @@ namespace RJW_Menstruation
Rect genitalIconRect = new Rect(rect.x, rect.y + fontheight, genitalRectWidth, genitalRectHeight); Rect genitalIconRect = new Rect(rect.x, rect.y + fontheight, genitalRectWidth, genitalRectHeight);
Rect genitalVaginaLabelRect = new Rect(rect.x, rect.y + 10f, genitalRectWidth, fontheight); Rect genitalVaginaLabelRect = new Rect(rect.x, rect.y + 10f, genitalRectWidth, fontheight);
Rect genitalAnusLabelRect = new Rect(rect.x, rect.y + fontheight + genitalRectHeight, genitalRectWidth, fontheight); Rect genitalAnusLabelRect = new Rect(rect.x, rect.y + fontheight + genitalRectHeight, genitalRectWidth, fontheight);
bool showOrigin = Mouse.IsOver(genitalIconRect) && Input.GetMouseButton(0);
vagina = pawn.GetGenitalIcon(comp); vagina = pawn.GetGenitalIcon(comp, showOrigin);
anal = pawn.GetAnalIcon(); anal = pawn.GetAnalIcon(showOrigin);
GUI.color = new Color(1.00f, 0.47f, 0.47f, 1); GUI.color = new Color(1.00f, 0.47f, 0.47f, 1);
GUI.Box(rect, "", boxstyle); GUI.Box(rect, "", boxstyle);
GUI.color = Utility.SafeSkinColor(pawn); GUI.color = Utility.SafeSkinColor(pawn);

View file

@ -58,8 +58,9 @@ namespace RJW_Menstruation
get get
{ {
if (allraces != null) return allraces; if (allraces != null) return allraces;
allraces = DefDatabase<ThingDef>.AllDefsListForReading.Where(thingdef => thingdef.race?.IsFlesh ?? false).ToList();
List<ThingDef> allThings = DefDatabase<ThingDef>.AllDefsListForReading;
allraces = allThings.FindAll(x => x.race != null && x.race.IsFlesh);
return allraces; return allraces;
} }
} }
@ -68,8 +69,9 @@ namespace RJW_Menstruation
get get
{ {
if (allkinds != null) return allkinds; if (allkinds != null) return allkinds;
allkinds = DefDatabase<PawnKindDef>.AllDefsListForReading.Where(pawnkinddef => pawnkinddef.race != null).ToList();
List<PawnKindDef> allKinds = DefDatabase<PawnKindDef>.AllDefsListForReading;
allkinds = allKinds.FindAll(x => x.race != null);
return allkinds; return allkinds;
} }
} }

View file

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ModMetaData> <ModMetaData>
<packageId>rjw.menstruation</packageId>
<name>RJW Menstruation Cycle</name> <name>RJW Menstruation Cycle</name>
<author>lutepickle</author> <author>lutepickle</author>
<url>https://gitgud.io/lutepickle/rjw_menstruation/</url>
<supportedVersions> <supportedVersions>
<li>1.2</li> <li>1.2</li>
<li>1.3</li> <li>1.3</li>
@ -30,17 +28,13 @@
<li>Abraxas.RJW.RaceSupport</li> <li>Abraxas.RJW.RaceSupport</li>
<li>rjw.milk.humanoid</li> <li>rjw.milk.humanoid</li>
</loadAfter> </loadAfter>
<incompatibleWithByVersion> <packageId>rjw.menstruation</packageId>
<v1.4>
<li>conit.thebirdsandthebees</li> <!--Breaks fertility calculations-->
</v1.4>
</incompatibleWithByVersion>
<description>Adds menstruation mechanics to vaginas: <description>Adds menstruation mechanics to vaginas:
Wombs cycle between follicular, luteal, and bleeding phases Wombs cycle between follicular, luteal, and bleeding phases
Tracks eggs ovulated and cum in wombs to determine pregnancy Tracks eggs ovulated and cum in wombs to determine pregnancy
Womb icon and status window Womb icon and status window
Estrus and pheromone effects Estrus effects
Race-specific fetus images for many vanilla animals Race-specific fetus images for many vanilla animals
Pregnancies from multiple eggs and different fathers Pregnancies from multiple eggs and different fathers
Identical siblings Identical siblings