mirror of
				https://gitgud.io/lutepickle/rjw_menstruation.git
				synced 2024-08-14 22:46:52 +00:00 
			
		
		
		
	Merge branch 'dev'
This commit is contained in:
		
						commit
						13359beb3d
					
				
					 22 changed files with 506 additions and 504 deletions
				
			
		
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -37,7 +37,7 @@
 | 
			
		|||
  <Dialog_DoCleanWomb_Tooltip>Gather cum into bucket</Dialog_DoCleanWomb_Tooltip>
 | 
			
		||||
  <Dialog_DontCleanWomb_Tooltip>Store cum in womb</Dialog_DontCleanWomb_Tooltip>
 | 
			
		||||
  <Dialog_FatherUnknown>Unknown</Dialog_FatherUnknown>
 | 
			
		||||
	
 | 
			
		||||
    
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
  <Option1_Label_1>Enable womb icon</Option1_Label_1>
 | 
			
		||||
| 
						 | 
				
			
			@ -94,14 +94,12 @@
 | 
			
		|||
  <Option23_Label>Dominant hybrid extension</Option23_Label>
 | 
			
		||||
  <Option23_Label_1>Mother</Option23_Label_1>
 | 
			
		||||
  <Option23_Label_2>Father</Option23_Label_2>
 | 
			
		||||
  <Option24_Label>Transition variance of nipples after pregnancy</Option24_Label>
 | 
			
		||||
  <Option24_Desc>Set how much nipples/areolas should darken/widen on every pregnancy.</Option24_Desc>
 | 
			
		||||
  <Option25_Label>Permanent transition variance of nipples</Option25_Label>
 | 
			
		||||
  <Option25_Desc>Set how much nipples/areolas should darken/widen permanently on every pregnancy.</Option25_Desc>
 | 
			
		||||
  <Option26_Label>Maximum transition</Option26_Label>
 | 
			
		||||
  <Option26_Desc>Nipples/areolas won't be darker/wider than this value.</Option26_Desc>
 | 
			
		||||
  <Option27_Label>Transition speed of nipples</Option27_Label>
 | 
			
		||||
  <Option27_Desc>Set speed of transition of nipples/areolas.
1 = instant transition</Option27_Desc>
 | 
			
		||||
  <Option_MaxBreastIncrementFactor_Label>Breast growth during pregnancy</Option_MaxBreastIncrementFactor_Label>
 | 
			
		||||
  <Option_MaxBreastIncrementFactor_Desc>Change how much a pregnant pawn's breasts will grow when pregnant. Some pawns will grow more than others.</Option_MaxBreastIncrementFactor_Desc>
 | 
			
		||||
  <Option_MaxNippleIncrementFactor_Label>Nipple change during pregnancy</Option_MaxNippleIncrementFactor_Label>
 | 
			
		||||
  <Option_MaxNippleIncrementFactor_Desc>Change how much a pregnant pawn's nipples will change during pregnancy.</Option_MaxNippleIncrementFactor_Desc>
 | 
			
		||||
  <Option_PermanentNippleChange_Label>Permanent nipple change after pregnancy</Option_PermanentNippleChange_Label>
 | 
			
		||||
  <Option_PermanentNippleChange_Desc>Adjusts approximately how much of a pregnant pawn's nipples will remain changed after the pregnancy ends.</Option_PermanentNippleChange_Desc>
 | 
			
		||||
  <Option28_Label>Customize Hybrids</Option28_Label>
 | 
			
		||||
  <Option28_Tooltip>Open custom hybrid editor.
This will overrides hybrid definitions of XML files.</Option28_Tooltip>
 | 
			
		||||
  <Option29_Label>Allow shrink icon</Option29_Label>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -32,8 +32,7 @@ namespace MilkModule
 | 
			
		|||
        {
 | 
			
		||||
            if (breastcomp != null)
 | 
			
		||||
            {
 | 
			
		||||
                breastcomp.AdjustAreolaSize(Rand.Range(0.0f, 0.0001f * Configurations.NipplePermanentTransitionVariance));
 | 
			
		||||
                breastcomp.AdjustNippleSize(Rand.Range(0.0f, 0.0001f * Configurations.NipplePermanentTransitionVariance));
 | 
			
		||||
                breastcomp.AdjustNippleProgress(Rand.Range(0.0f, 0.01f));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,8 +24,7 @@ namespace MilkModule
 | 
			
		|||
            if (__instance.parent is Pawn pawn) comp = pawn.GetBreastComp();
 | 
			
		||||
            if (comp != null)
 | 
			
		||||
            {
 | 
			
		||||
                comp.AdjustAreolaSize(Rand.Range(0.0f, 0.01f * Configurations.NipplePermanentTransitionVariance));
 | 
			
		||||
                comp.AdjustNippleSize(Rand.Range(0.0f, 0.01f * Configurations.NipplePermanentTransitionVariance));
 | 
			
		||||
                comp.AdjustNippleProgress(Rand.Range(0.0f, 0.01f));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,12 @@ namespace RJW_Menstruation
 | 
			
		|||
        public const int EnzygoticTwinsChanceAdjustDefault = 2;
 | 
			
		||||
        public const int MaxEnzygoticTwinsDefault = 9;
 | 
			
		||||
        public const int BleedingAmountDefault = 50;
 | 
			
		||||
        public const float NippleTransitionVarianceDefault = 0.2f;
 | 
			
		||||
        public const float NipplePermanentTransitionVarianceDefault = 0.02f;
 | 
			
		||||
        public const float NippleMaximumTransitionDefault = 0.4f;
 | 
			
		||||
        public const float NippleTransitionSpeedDefault = 0.035f;
 | 
			
		||||
        public const float MaxBreastIncrementFactorDefault = 1.0f;
 | 
			
		||||
        public const float MaxBreastIncrementFactorMax = 2.5f;
 | 
			
		||||
        public const float MaxNippleIncrementFactorDefault = 1.0f;
 | 
			
		||||
        public const float MaxNippleIncrementFactorMax = 2.5f;
 | 
			
		||||
        public const float PermanentNippleChangeDefault = 0.1f;
 | 
			
		||||
        public const float PermanentNippleChangeMax = 0.25f;
 | 
			
		||||
        public const float EggLifespanMultiplierDefault = 1.0f;
 | 
			
		||||
        public const float VaginaMorphPowerDefault = 0.2f;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,19 +69,9 @@ namespace RJW_Menstruation
 | 
			
		|||
        public static float EggLifespanMultiplier = EggLifespanMultiplierDefault;
 | 
			
		||||
        public static bool EnableBirthVaginaMorph = false;
 | 
			
		||||
        public static float VaginaMorphPower = VaginaMorphPowerDefault;
 | 
			
		||||
 | 
			
		||||
        public static float NippleTransitionVariance = NippleTransitionVarianceDefault;
 | 
			
		||||
        public static float NipplePermanentTransitionVariance = NipplePermanentTransitionVarianceDefault;
 | 
			
		||||
        public static float NippleMaximumTransition = NippleMaximumTransitionDefault;
 | 
			
		||||
        public static float NippleTransitionSpeed = NippleTransitionSpeedDefault;
 | 
			
		||||
        public static float NippleTransitionRatio
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return NippleTransitionVariance * NippleTransitionSpeed;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static float MaxBreastIncrementFactor = MaxBreastIncrementFactorDefault;
 | 
			
		||||
        public static float MaxNippleIncrementFactor = MaxNippleIncrementFactorDefault;
 | 
			
		||||
        public static float PermanentNippleChange = PermanentNippleChangeDefault;
 | 
			
		||||
        public static void SettoDefault()
 | 
			
		||||
        {
 | 
			
		||||
            ImplantationChanceAdjust = ImplantationChanceAdjustDefault;
 | 
			
		||||
| 
						 | 
				
			
			@ -101,10 +93,9 @@ namespace RJW_Menstruation
 | 
			
		|||
            MaxEnzygoticTwins = MaxEnzygoticTwinsDefault;
 | 
			
		||||
            BleedingAmount = BleedingAmountDefault;
 | 
			
		||||
            MotherFirst = false;
 | 
			
		||||
            NippleTransitionVariance = NippleTransitionVarianceDefault;
 | 
			
		||||
            NipplePermanentTransitionVariance = NipplePermanentTransitionVarianceDefault;
 | 
			
		||||
            NippleMaximumTransition = NippleMaximumTransitionDefault;
 | 
			
		||||
            NippleTransitionSpeed = NippleTransitionSpeedDefault;
 | 
			
		||||
            MaxBreastIncrementFactor = MaxBreastIncrementFactorDefault;
 | 
			
		||||
            MaxNippleIncrementFactor= MaxNippleIncrementFactorDefault;
 | 
			
		||||
            PermanentNippleChange = PermanentNippleChangeDefault;
 | 
			
		||||
            EggLifespanMultiplier = EggLifespanMultiplierDefault;
 | 
			
		||||
            VaginaMorphPower = VaginaMorphPowerDefault;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -214,10 +205,9 @@ namespace RJW_Menstruation
 | 
			
		|||
            Scribe_Values.Look(ref ShowFlag, "ShowFlag", ShowFlag, true);
 | 
			
		||||
            Scribe_Values.Look(ref UseHybridExtention, "UseHybridExtention", UseHybridExtention, true);
 | 
			
		||||
            Scribe_Values.Look(ref MotherFirst, "MotherFirst", MotherFirst, true);
 | 
			
		||||
            Scribe_Values.Look(ref NippleTransitionVariance, "NippleTransitionVariance", NippleTransitionVariance, true);
 | 
			
		||||
            Scribe_Values.Look(ref NipplePermanentTransitionVariance, "NipplePermanentTransitionVariance", NipplePermanentTransitionVariance, true);
 | 
			
		||||
            Scribe_Values.Look(ref NippleMaximumTransition, "NippleMaximumTransition", NippleMaximumTransition, true);
 | 
			
		||||
            Scribe_Values.Look(ref NippleTransitionSpeed, "NippleTransitionSpeed", NippleTransitionSpeed, true);
 | 
			
		||||
            Scribe_Values.Look(ref MaxBreastIncrementFactor, "MaxBreastIncrementFactor", MaxBreastIncrementFactor, true);
 | 
			
		||||
            Scribe_Values.Look(ref MaxNippleIncrementFactor, "MaxNippleIncrementFactor", MaxNippleIncrementFactor, true);
 | 
			
		||||
            Scribe_Values.Look(ref PermanentNippleChange, "PermanentNippleChange", PermanentNippleChange, true);
 | 
			
		||||
            Scribe_Values.Look(ref AllowShrinkIcon, "AllowShrinkIcon", AllowShrinkIcon, true);
 | 
			
		||||
            Scribe_Values.Look(ref EggLifespanMultiplier, "EggLifespanMultiplier", EggLifespanMultiplier, true);
 | 
			
		||||
            Scribe_Values.Look(ref EnableBirthVaginaMorph, "EnableBirthVaginaMorph", EnableBirthVaginaMorph, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -259,8 +249,8 @@ namespace RJW_Menstruation
 | 
			
		|||
        public RJW_Menstruation(ModContentPack content) : base(content)
 | 
			
		||||
        {
 | 
			
		||||
            GetSettings<Configurations>();
 | 
			
		||||
            Configurations.HARActivated = ModLister.HasActiveModWithName("Humanoid Alien Races 2.0");
 | 
			
		||||
            Configurations.LLActivated = ModLister.HasActiveModWithName("RimJobWorld - Licentia Labs");
 | 
			
		||||
            Configurations.HARActivated = ModLister.GetActiveModWithIdentifier("erdelf.HumanoidAlienRaces") != null;
 | 
			
		||||
            Configurations.LLActivated = ModLister.GetActiveModWithIdentifier("LustLicentia.RJWLabs") != null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +284,7 @@ namespace RJW_Menstruation
 | 
			
		|||
            Widgets.CheckboxLabeled(middleAndRightCells.RightHalf(), Translations.Option_EnableGatherCumGizmo_Label, ref Configurations.EnableGatherCumGizmo, false, null, null, true);
 | 
			
		||||
            if (Configurations.EnableWombIcon || Configurations.EnableButtonInHT)
 | 
			
		||||
            {
 | 
			
		||||
                Listing_Standard wombsection = listmain.BeginSection(400);
 | 
			
		||||
                Listing_Standard wombsection = listmain.BeginSection(350);
 | 
			
		||||
                wombsection.CheckboxLabeled(Translations.Option9_Label, ref Configurations.DrawWombStatus, Translations.Option9_Desc);
 | 
			
		||||
                if (Configurations.DrawWombStatus)
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -352,25 +342,20 @@ namespace RJW_Menstruation
 | 
			
		|||
                    Configurations.ShowFlag ^= Configurations.PawnFlags.Hostile;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Adjust = (int)(Configurations.NippleTransitionVariance * 1000);
 | 
			
		||||
                wombsection.Label(Translations.Option24_Label + " " + Configurations.NippleTransitionVariance * 100 + " / 100", -1, Translations.Option24_Desc);
 | 
			
		||||
                Adjust = (int)(Configurations.MaxBreastIncrementFactor * 1000 / Configurations.MaxBreastIncrementFactorMax);
 | 
			
		||||
                wombsection.Label(Translations.Option_MaxBreastIncrementFactor_Label + " " + Configurations.MaxBreastIncrementFactor * 100 + "%", -1, Translations.Option_MaxBreastIncrementFactor_Desc);
 | 
			
		||||
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
 | 
			
		||||
                Configurations.NippleTransitionVariance = (float)Adjust / 1000;
 | 
			
		||||
                Configurations.MaxBreastIncrementFactor = (float)Adjust / (1000 / Configurations.MaxBreastIncrementFactorMax);
 | 
			
		||||
 | 
			
		||||
                Adjust = (int)(Configurations.NipplePermanentTransitionVariance * 1000);
 | 
			
		||||
                wombsection.Label(Translations.Option25_Label + " " + Configurations.NipplePermanentTransitionVariance * 100 + " / 100", -1, Translations.Option25_Desc);
 | 
			
		||||
                Adjust = (int)(Configurations.MaxNippleIncrementFactor * 1000 / Configurations.MaxNippleIncrementFactorMax);
 | 
			
		||||
                wombsection.Label(Translations.Option_MaxNippleIncrementFactor_Label + " " + Configurations.MaxNippleIncrementFactor * 100 + "%", -1, Translations.Option_MaxNippleIncrementFactor_Desc);
 | 
			
		||||
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
 | 
			
		||||
                Configurations.NipplePermanentTransitionVariance = (float)Adjust / 1000;
 | 
			
		||||
                Configurations.MaxNippleIncrementFactor = (float)Adjust / (1000 / Configurations.MaxNippleIncrementFactorMax);
 | 
			
		||||
 | 
			
		||||
                Adjust = (int)(Configurations.NippleMaximumTransition * 1000);
 | 
			
		||||
                wombsection.Label(Translations.Option26_Label + " " + Configurations.NippleMaximumTransition * 100 + " / 100", -1, Translations.Option26_Desc);
 | 
			
		||||
                Adjust = (int)(Configurations.PermanentNippleChange * 1000 / Configurations.PermanentNippleChangeMax);
 | 
			
		||||
                wombsection.Label(Translations.Option_PermanentNippleChange_Label + " " + Configurations.PermanentNippleChange, -1, Translations.Option_PermanentNippleChange_Desc);
 | 
			
		||||
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
 | 
			
		||||
                Configurations.NippleMaximumTransition = (float)Adjust / 1000;
 | 
			
		||||
 | 
			
		||||
                Adjust = (int)(Configurations.NippleTransitionSpeed * 1000);
 | 
			
		||||
                wombsection.Label(Translations.Option27_Label + " " + Configurations.NippleTransitionSpeed, -1, Translations.Option27_Desc);
 | 
			
		||||
                Adjust = (int)wombsection.Slider(Adjust, 0, 1000);
 | 
			
		||||
                Configurations.NippleTransitionSpeed = (float)Adjust / 1000;
 | 
			
		||||
                Configurations.PermanentNippleChange = (float)Adjust / (1000 / Configurations.PermanentNippleChangeMax);
 | 
			
		||||
 | 
			
		||||
                listmain.EndSection(wombsection);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.curStage = HediffComp_Menstruation.Stage.Follicular;
 | 
			
		||||
            Messages.Message($"{p} is now follicular", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"{p} is now follicular", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [DebugAction("RJW Menstruation", "Set pawn's state to ovulatory", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.curStage = HediffComp_Menstruation.Stage.Ovulatory;
 | 
			
		||||
            Messages.Message($"{p} is now ovulatory", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"{p} is now ovulatory", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [DebugAction("RJW Menstruation", "Set pawn's state to luteal", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.curStage = HediffComp_Menstruation.Stage.Luteal;
 | 
			
		||||
            Messages.Message($"{p} is now luteal", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"{p} is now luteal", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [DebugAction("RJW Menstruation", "Set pawn's state to bleeding", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.curStage = HediffComp_Menstruation.Stage.Bleeding;
 | 
			
		||||
            Messages.Message($"{p} is now bleeding", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"{p} is now bleeding", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
        /*
 | 
			
		||||
        [DebugAction("RJW Menstruation", "Set pawn's state to recovering", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
 | 
			
		||||
| 
						 | 
				
			
			@ -55,14 +55,14 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.RemoveAllCums();
 | 
			
		||||
            Messages.Message($"All cum removed from {p}'s womb", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"All cum removed from {p}'s womb", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
        [DebugAction("RJW Menstruation", "Add egg to pawn's next ovulation", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
 | 
			
		||||
        private static void AddEgg(Pawn p)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.eggstack++;
 | 
			
		||||
            Messages.Message($"1 egg added to {p}'s next ovulation ({p.GetFirstMenstruationComp().eggstack})", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"1 egg added to {p}'s next ovulation ({p.GetFirstMenstruationComp().eggstack})", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [DebugAction("RJW Menstruation", "Recalculate pawn's ovary power", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in p.GetMenstruationComps())
 | 
			
		||||
                comp.ovarypower = comp.GetOvaryPowerByAge();
 | 
			
		||||
            Messages.Message($"{p}'s ovarypower recalculated ({p.GetFirstMenstruationComp().ovarypower})", MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
            Messages.Message($"{p}'s ovarypower recalculated ({p.GetFirstMenstruationComp().ovarypower})", p, MessageTypeDefOf.NeutralEvent, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
using System.Linq;
 | 
			
		||||
using AlienRace;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Menstruation
 | 
			
		||||
| 
						 | 
				
			
			@ -8,24 +10,38 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
        public static bool IsHAR(this Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            return pawn.def.GetType().ToString().StartsWith("AlienRace");
 | 
			
		||||
            if (!Configurations.HARActivated) return false;
 | 
			
		||||
            return pawn?.def is ThingDef_AlienRace;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static ThingComp GetHARComp(this Pawn pawn)
 | 
			
		||||
        public static AlienPartGenerator.AlienComp GetHARComp(this Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            return pawn?.GetComps<ThingComp>()?.First(x => x.GetType().Namespace.EqualsIgnoreCase("AlienRace") && x.GetType().Name.EndsWith("AlienComp"));
 | 
			
		||||
            return pawn?.TryGetComp<AlienPartGenerator.AlienComp>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static string GetHARCrown(this Pawn pawn)
 | 
			
		||||
        public static void CopyHARProperties(Pawn baby, Pawn original)
 | 
			
		||||
        {
 | 
			
		||||
            return (string)pawn.GetHARComp().GetMemberValue("crownType");
 | 
			
		||||
            AlienPartGenerator.AlienComp babyHARComp = baby.GetHARComp();
 | 
			
		||||
            AlienPartGenerator.AlienComp originalHARComp = original.GetHARComp();
 | 
			
		||||
            if (babyHARComp == null || originalHARComp == null) return;
 | 
			
		||||
            babyHARComp.crownType = originalHARComp.crownType;
 | 
			
		||||
 | 
			
		||||
            foreach(KeyValuePair<string, AlienPartGenerator.ExposableValueTuple<Color, Color>> channel in originalHARComp.ColorChannels)
 | 
			
		||||
            {
 | 
			
		||||
                babyHARComp.OverwriteColorChannel(channel.Key, channel.Value.first, channel.Value.second);
 | 
			
		||||
            }
 | 
			
		||||
            babyHARComp.headMaskVariant = originalHARComp.headMaskVariant;
 | 
			
		||||
            babyHARComp.bodyMaskVariant = originalHARComp.bodyMaskVariant;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void SetHARCrown(this Pawn pawn, string crown)
 | 
			
		||||
        // HAR doesn't populate variants until the graphics are called for, so this has to happen late
 | 
			
		||||
        public static void CopyHARPropertiesPostBirth(Pawn baby, Pawn original)
 | 
			
		||||
        {
 | 
			
		||||
            pawn.GetHARComp().SetMemberValue("crownType", crown);
 | 
			
		||||
            AlienPartGenerator.AlienComp babyHARComp = baby.GetHARComp();
 | 
			
		||||
            AlienPartGenerator.AlienComp originalHARComp = original.GetHARComp();
 | 
			
		||||
            if (babyHARComp == null || originalHARComp == null) return;
 | 
			
		||||
            if (originalHARComp.addonVariants != null)  // Testing has shown that the addons are valid by this point, but it's better to be safe
 | 
			
		||||
                babyHARComp.addonVariants = new List<int>(originalHARComp.addonVariants);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
using HugsLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ namespace RJW_Menstruation
 | 
			
		|||
{
 | 
			
		||||
    public class CompProperties_Breast : HediffCompProperties
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly ColorInt DefaultBlacknippleColor = new ColorInt(55, 20, 0);
 | 
			
		||||
        public string BreastTex = "Breasts/Breast";
 | 
			
		||||
        public ColorInt BlacknippleColor = new ColorInt(55, 20, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,117 +32,98 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
    public class HediffComp_Breast : HediffComp
 | 
			
		||||
    {
 | 
			
		||||
        public const float DEFAULTALPHA = -1;
 | 
			
		||||
        public const float DEFAULTAREOLA = -1;
 | 
			
		||||
        public const float DEFAULTNIPPLE = -1;
 | 
			
		||||
        public const float VARIANT = 0.2f;
 | 
			
		||||
        public const int TICKINTERVAL = 3750;
 | 
			
		||||
        public const float MAX_BREAST_INCREMENT = 0.10f;
 | 
			
		||||
        public const float BREAST_GROWTH_START = 1f / 6f;
 | 
			
		||||
        public const float BREAST_GROWTH_END = 1f / 3f;
 | 
			
		||||
        public const int tickInterval = GenDate.TicksPerHour * 3 / 2;
 | 
			
		||||
        public const float breastGrowthStart = 1f / 6f;
 | 
			
		||||
        public const float breastGrowthEnd = 1f / 3f;
 | 
			
		||||
        public static readonly SimpleCurve nippleTransitions = new SimpleCurve()
 | 
			
		||||
        {
 | 
			
		||||
            new CurvePoint(0f,0f),
 | 
			
		||||
            new CurvePoint(0.1f,0f),
 | 
			
		||||
            new CurvePoint(0.333f,0.167f),
 | 
			
		||||
            new CurvePoint(0.667f,0.833f),
 | 
			
		||||
            new CurvePoint(1.0f,1.0f)
 | 
			
		||||
        };
 | 
			
		||||
        public const float nippleChange = 0.2f;
 | 
			
		||||
 | 
			
		||||
        public CompProperties_Breast Props;
 | 
			
		||||
 | 
			
		||||
        protected float alphaPermanent = -1;
 | 
			
		||||
        protected float alphaCurrent = -1;
 | 
			
		||||
        protected float alpha = -1;
 | 
			
		||||
        protected float areolaSizePermanent = -1f;
 | 
			
		||||
        protected float areolaSizeCurrent = -1f;
 | 
			
		||||
        protected float areolaSize = -1f;
 | 
			
		||||
        protected float nippleSizePermanent = -1f;
 | 
			
		||||
        protected float nippleSizeCurrent = -1f;
 | 
			
		||||
        protected float nippleSize = -1f;
 | 
			
		||||
        protected long ageOfLastBirth = 0;
 | 
			
		||||
        protected float maxBreastIncrement = -1f;
 | 
			
		||||
        protected float breastSizeIncreased = 0f;
 | 
			
		||||
        protected string debugGrowthStatus = "(Growth/shrink not yet calculated; run for 1.5h to update)";
 | 
			
		||||
        protected float originalpha = -1f;
 | 
			
		||||
        protected float originareola = -1f;
 | 
			
		||||
        protected float originnipple = -1f;
 | 
			
		||||
        protected Color cachedcolor;
 | 
			
		||||
        protected bool loaded = false;
 | 
			
		||||
        protected bool pregnant = false;
 | 
			
		||||
        public Action action;
 | 
			
		||||
        protected float nippleProgress = 0f;
 | 
			
		||||
        protected float baseAlpha = -1f;    // Will grow in response to pregnancy
 | 
			
		||||
        protected float baseAreola = -1f;
 | 
			
		||||
        protected float baseNipple = -1f;
 | 
			
		||||
        protected float cachedAlpha = -1f;  // Calculated dynamically instead of saved
 | 
			
		||||
        protected float cachedAreola = -1f; // Actual size = these * breast size
 | 
			
		||||
        protected float cachedNipple = -1f;
 | 
			
		||||
        protected float babyHalfAge = -1f;
 | 
			
		||||
 | 
			
		||||
        protected Color cachedColor;
 | 
			
		||||
        protected bool loaded = false;
 | 
			
		||||
                
 | 
			
		||||
        protected float BabyHalfAge
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                float res = 0;
 | 
			
		||||
                List<LifeStageAge> ages = parent.pawn.RaceProps.lifeStageAges;
 | 
			
		||||
                if (babyHalfAge > 0f) return babyHalfAge;
 | 
			
		||||
                List<LifeStageAge> ages = parent.pawn.def.race.lifeStageAges;
 | 
			
		||||
                if (ages?.Count > 1)
 | 
			
		||||
                    res = ages[1].minAge / 2;
 | 
			
		||||
                    babyHalfAge = ages[1].minAge / 2;
 | 
			
		||||
 | 
			
		||||
                if (res <= 0) res = 1.2f / 2; // Default to human
 | 
			
		||||
                if (babyHalfAge <= 0) babyHalfAge = 1.2f / 2; // Default to human
 | 
			
		||||
 | 
			
		||||
                if (RJWPregnancySettings.phantasy_pregnancy)
 | 
			
		||||
                    res /= GenDate.DaysPerYear;
 | 
			
		||||
                    babyHalfAge /= GenDate.DaysPerYear;
 | 
			
		||||
 | 
			
		||||
                return res;
 | 
			
		||||
                return babyHalfAge;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected void ShrinkBreasts()
 | 
			
		||||
        {
 | 
			
		||||
            // The natural rate will take them from full to empty during the second half of their child's babyhood
 | 
			
		||||
            float shrinkRate = TICKINTERVAL * MAX_BREAST_INCREMENT / (BabyHalfAge * GenDate.TicksPerYear);
 | 
			
		||||
            float shrinkRate = tickInterval * MaxBreastIncrement / (BabyHalfAge * GenDate.TicksPerYear);
 | 
			
		||||
            float shrinkAmount = Mathf.Min(shrinkRate, breastSizeIncreased);
 | 
			
		||||
            breastSizeIncreased -= shrinkAmount;
 | 
			
		||||
            parent.Severity -= shrinkAmount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public float MaxAlpha
 | 
			
		||||
        protected float MaxBreastIncrement
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return originalpha + Configurations.NippleMaximumTransition;
 | 
			
		||||
                return maxBreastIncrement * Configurations.MaxBreastIncrementFactor;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public float MaxAreola
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return originareola + Configurations.NippleMaximumTransition;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public float MaxNipple
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return originnipple + Configurations.NippleMaximumTransition;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public float OriginAlpha => originalpha;
 | 
			
		||||
        public float OriginNipple => originnipple;
 | 
			
		||||
        public float OriginAreola => originareola;
 | 
			
		||||
        public Color OriginColor => Colors.CMYKLerp(parent?.pawn?.story?.SkinColor ?? Color.white, Props.BlackNippleColor, originalpha);
 | 
			
		||||
 | 
			
		||||
        public Color NippleColor
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return cachedcolor;
 | 
			
		||||
                return cachedColor;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public float Alpha
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return alphaCurrent;
 | 
			
		||||
                return cachedAlpha;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public float NippleSize
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return nippleSizeCurrent;
 | 
			
		||||
                return cachedNipple * parent.Severity;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public float AreolaSize
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return areolaSizeCurrent;
 | 
			
		||||
                return cachedAreola * parent.Severity;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -156,25 +138,50 @@ namespace RJW_Menstruation
 | 
			
		|||
        public override void CompExposeData()
 | 
			
		||||
        {
 | 
			
		||||
            base.CompExposeData();
 | 
			
		||||
            Scribe_Values.Look(ref alphaPermanent, "alphaPermanent", DEFAULTALPHA, true);
 | 
			
		||||
            Scribe_Values.Look(ref alphaCurrent, "alphaCurrent", DEFAULTALPHA, true);
 | 
			
		||||
            Scribe_Values.Look(ref alpha, "alpha", DEFAULTALPHA, true);
 | 
			
		||||
            Scribe_Values.Look(ref areolaSizePermanent, "areolaSizePermanent", DEFAULTAREOLA, true);
 | 
			
		||||
            Scribe_Values.Look(ref areolaSizeCurrent, "areolaSizeCurrent", DEFAULTAREOLA, true);
 | 
			
		||||
            Scribe_Values.Look(ref areolaSize, "areolaSize", DEFAULTAREOLA, true);
 | 
			
		||||
            Scribe_Values.Look(ref nippleSizePermanent, "nippleSizePermanent", DEFAULTNIPPLE, true);
 | 
			
		||||
            Scribe_Values.Look(ref nippleSizeCurrent, "nippleSizeCurrent", DEFAULTNIPPLE, true);
 | 
			
		||||
            Scribe_Values.Look(ref nippleSize, "nippleSize", DEFAULTNIPPLE, true);
 | 
			
		||||
            Scribe_Values.Look(ref ageOfLastBirth, "ageOfLastBirth", ageOfLastBirth, true);
 | 
			
		||||
            Scribe_Values.Look(ref breastSizeIncreased, "breastSizeIncreased", breastSizeIncreased, true);
 | 
			
		||||
            Scribe_Values.Look(ref originalpha, "originalpha", originalpha, true);
 | 
			
		||||
            Scribe_Values.Look(ref originareola, "originareola", originareola, true);
 | 
			
		||||
            Scribe_Values.Look(ref originnipple, "originnipple", originnipple, true);
 | 
			
		||||
            Scribe_Values.Look(ref pregnant, "pregnant", pregnant, true);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (Scribe.mode == LoadSaveMode.LoadingVars)
 | 
			
		||||
            {   // For compatibility
 | 
			
		||||
                Scribe_Values.Look(ref baseAlpha, "alphaPermanent", baseAlpha / 2, false);
 | 
			
		||||
                Scribe_Values.Look(ref baseAreola, "areolaSizePermanent", baseAreola / 2, false);
 | 
			
		||||
                Scribe_Values.Look(ref baseNipple, "nippleSizePermanent", baseNipple / 2, false);
 | 
			
		||||
                baseAlpha *= 2;
 | 
			
		||||
                baseAreola *= 2;
 | 
			
		||||
                baseNipple *= 2;
 | 
			
		||||
            }
 | 
			
		||||
            Scribe_Values.Look(ref ageOfLastBirth, "ageOfLastBirth", ageOfLastBirth, true);
 | 
			
		||||
            Scribe_Values.Look(ref maxBreastIncrement, "maxBreastIncrement", maxBreastIncrement, true);
 | 
			
		||||
            Scribe_Values.Look(ref breastSizeIncreased, "breastSizeIncreased", breastSizeIncreased, true);
 | 
			
		||||
            Scribe_Values.Look(ref nippleProgress, "nippleProgress", nippleProgress, true);
 | 
			
		||||
            Scribe_Values.Look(ref baseAlpha, "baseAlpha", baseAlpha, true);
 | 
			
		||||
            Scribe_Values.Look(ref baseAreola, "baseAreola", baseAreola, true);
 | 
			
		||||
            Scribe_Values.Look(ref baseNipple, "baseNipple", baseNipple, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void CompPostTick(ref float severityAdjustment) { }
 | 
			
		||||
        public override void CompPostTick(ref float severityAdjustment)
 | 
			
		||||
        {
 | 
			
		||||
            base.CompPostTick(ref severityAdjustment);
 | 
			
		||||
            // If an exception makes it out, RW will remove the hediff, so catch it here
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (
 | 
			
		||||
                    !parent.pawn.IsHashIntervalTick(tickInterval) ||
 | 
			
		||||
                    !parent.pawn.Spawned ||  // TODO: Add option to simulate off-map pawns
 | 
			
		||||
                    parent.pawn.health.Dead
 | 
			
		||||
                    )
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                CalculateBreastSize();
 | 
			
		||||
                CalculateNipples();
 | 
			
		||||
                UpdateNipples();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Error($"Error processing breasts of {parent.pawn}: {ex}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void CompPostPostAdd(DamageInfo? dinfo)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -189,8 +196,6 @@ namespace RJW_Menstruation
 | 
			
		|||
                Log.Warning($"Attempted to remove breast comp from wrong pawn ({parent.pawn}).");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(action);
 | 
			
		||||
            if (Configurations.Debug) Log.Message(parent.pawn.Label + " breast tick scheduler removed");
 | 
			
		||||
            base.CompPostPostRemoved();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -202,15 +207,12 @@ namespace RJW_Menstruation
 | 
			
		|||
                foreach (Pawn child in parent.pawn.relations.Children)
 | 
			
		||||
                {
 | 
			
		||||
                    bool isFetus = false;
 | 
			
		||||
                    foreach (Hediff_BasePregnancy preg in parent.pawn.health.hediffSet.GetHediffs<Hediff_BasePregnancy>())
 | 
			
		||||
                    if (parent.pawn.health.hediffSet.GetHediffs<Hediff_BasePregnancy>().Any(preg => preg.babies.Contains(child)))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (preg.babies.Contains(child))
 | 
			
		||||
                        {
 | 
			
		||||
                            isFetus = true;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                        isFetus = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    
 | 
			
		||||
                    if (
 | 
			
		||||
                        parent.pawn.ageTracker.BirthAbsTicks - child.ageTracker.BirthAbsTicks > ageOfLastBirth &&
 | 
			
		||||
                        !isFetus &&
 | 
			
		||||
| 
						 | 
				
			
			@ -225,70 +227,54 @@ namespace RJW_Menstruation
 | 
			
		|||
        public void Initialize()
 | 
			
		||||
        {
 | 
			
		||||
            Props = (CompProperties_Breast)props;
 | 
			
		||||
            action = Transition;
 | 
			
		||||
 | 
			
		||||
            if (maxBreastIncrement <= 0f)
 | 
			
		||||
            {
 | 
			
		||||
                maxBreastIncrement = Utility.RandGaussianLike(0.088f, 0.202f);
 | 
			
		||||
            }
 | 
			
		||||
            if (ageOfLastBirth == 0)
 | 
			
		||||
            {
 | 
			
		||||
                ageOfLastBirth = CalculateLastBirth();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (alphaPermanent < 0f)
 | 
			
		||||
            if (baseAlpha <= 0f)
 | 
			
		||||
            {
 | 
			
		||||
                alphaPermanent = (Utility.RandGaussianLike(0.0f, 0.3f) + Rand.Range(0.0f, 0.5f)) / 2;
 | 
			
		||||
                originalpha = alphaPermanent;
 | 
			
		||||
                alpha = alphaPermanent;
 | 
			
		||||
                alphaCurrent = alphaPermanent;
 | 
			
		||||
                baseAlpha = Utility.RandGaussianLike(0.0f, 0.3f) + Rand.Range(0.0f, 0.5f);
 | 
			
		||||
            }
 | 
			
		||||
            if (areolaSizePermanent < 0f)
 | 
			
		||||
            if (baseAreola <= 0f)
 | 
			
		||||
            {
 | 
			
		||||
                areolaSizePermanent = Utility.RandGaussianLike(0f, parent.Severity);
 | 
			
		||||
                originareola = areolaSizePermanent;
 | 
			
		||||
                areolaSize = areolaSizePermanent;
 | 
			
		||||
                areolaSizeCurrent = areolaSizePermanent;
 | 
			
		||||
                baseAreola = Utility.RandGaussianLike(0.0f, 1.0f);
 | 
			
		||||
            }
 | 
			
		||||
            if (nippleSizePermanent < 0f)
 | 
			
		||||
            if (baseNipple <= 0f)
 | 
			
		||||
            {
 | 
			
		||||
                nippleSizePermanent = Utility.RandGaussianLike(0f, parent.Severity);
 | 
			
		||||
                originnipple = nippleSizePermanent;
 | 
			
		||||
                nippleSize = nippleSizePermanent;
 | 
			
		||||
                nippleSizeCurrent = nippleSizePermanent;
 | 
			
		||||
                baseNipple = Utility.RandGaussianLike(0.0f, 1.0f);
 | 
			
		||||
            }
 | 
			
		||||
            UpdateColor();
 | 
			
		||||
            UpdateNipples();
 | 
			
		||||
            loaded = true;
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(action, TICKINTERVAL, parent.pawn);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void Transition()
 | 
			
		||||
        protected void CalculateBreastSize()
 | 
			
		||||
        {
 | 
			
		||||
            alphaCurrent = Mathf.Lerp(alphaCurrent, alpha, Configurations.NippleTransitionRatio);
 | 
			
		||||
            areolaSizeCurrent = Mathf.Lerp(areolaSizeCurrent, areolaSize, Configurations.NippleTransitionRatio);
 | 
			
		||||
            nippleSizeCurrent = Mathf.Lerp(nippleSizeCurrent, nippleSize, Configurations.NippleTransitionRatio);
 | 
			
		||||
            UpdateColor();
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(action, TICKINTERVAL, parent.pawn);
 | 
			
		||||
 | 
			
		||||
            // Scenario A: the youngest child is less than halfway into babyhood: Full size
 | 
			
		||||
            if (ageOfLastBirth + BabyHalfAge * GenDate.TicksPerYear > parent.pawn.ageTracker.AgeBiologicalTicks)
 | 
			
		||||
            {
 | 
			
		||||
                debugGrowthStatus = "Full size due to young child";
 | 
			
		||||
                if (breastSizeIncreased < MAX_BREAST_INCREMENT)
 | 
			
		||||
                if (breastSizeIncreased < MaxBreastIncrement)
 | 
			
		||||
                {
 | 
			
		||||
                    parent.Severity += (MAX_BREAST_INCREMENT - breastSizeIncreased);
 | 
			
		||||
                    breastSizeIncreased = MAX_BREAST_INCREMENT;
 | 
			
		||||
                    parent.Severity += (MaxBreastIncrement - breastSizeIncreased);
 | 
			
		||||
                    breastSizeIncreased = MaxBreastIncrement;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Scenario B: Pregnant, grow in the second half of first trimester
 | 
			
		||||
            else if (parent.pawn.IsPregnant())
 | 
			
		||||
            {
 | 
			
		||||
                float pregnancySize = Mathf.InverseLerp(BREAST_GROWTH_START, BREAST_GROWTH_END, parent.pawn.GetFarthestPregnancyProgress()) * MAX_BREAST_INCREMENT;
 | 
			
		||||
                float pregnancySize = Mathf.InverseLerp(breastGrowthStart, breastGrowthEnd, parent.pawn.GetFarthestPregnancyProgress()) * MaxBreastIncrement;
 | 
			
		||||
                if (breastSizeIncreased > pregnancySize)
 | 
			
		||||
                {
 | 
			
		||||
                    debugGrowthStatus = "Shrinking due to being oversize for pregnancy";
 | 
			
		||||
                    // Breasts still large from the last kid
 | 
			
		||||
                    ShrinkBreasts();
 | 
			
		||||
                }
 | 
			
		||||
                else if (breastSizeIncreased < MAX_BREAST_INCREMENT)
 | 
			
		||||
                else if (breastSizeIncreased < MaxBreastIncrement)
 | 
			
		||||
                {
 | 
			
		||||
                    // Time to grow
 | 
			
		||||
                    float growAmount = pregnancySize - breastSizeIncreased;
 | 
			
		||||
| 
						 | 
				
			
			@ -310,106 +296,88 @@ namespace RJW_Menstruation
 | 
			
		|||
            else debugGrowthStatus = "Base size";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ChangeColorFermanant(float alpha)
 | 
			
		||||
        protected void CalculateNipples()
 | 
			
		||||
        {
 | 
			
		||||
            alphaPermanent = alpha;
 | 
			
		||||
            float newNippleProgress;
 | 
			
		||||
            if (ageOfLastBirth + BabyHalfAge * GenDate.TicksPerYear > parent.pawn.ageTracker.AgeBiologicalTicks)
 | 
			
		||||
                newNippleProgress = 1f;
 | 
			
		||||
            else if (parent.pawn.IsPregnant())
 | 
			
		||||
                newNippleProgress = nippleTransitions.Evaluate(parent.pawn.GetFarthestPregnancyProgress());
 | 
			
		||||
            else
 | 
			
		||||
                newNippleProgress = 0f;
 | 
			
		||||
 | 
			
		||||
            if (newNippleProgress == nippleProgress) return;    // Nothing to change
 | 
			
		||||
            else if (newNippleProgress > nippleProgress)
 | 
			
		||||
            {
 | 
			
		||||
                float progressDifference = newNippleProgress - nippleProgress;
 | 
			
		||||
                // All nipple growth has a slight effect on the base
 | 
			
		||||
                // Not mathematically precise in hitting the goal at the end of the term, but close enough
 | 
			
		||||
                baseAlpha *= 1.0f + progressDifference * Configurations.PermanentNippleChange;
 | 
			
		||||
                if (baseAlpha > 1.0f) baseAlpha = 1.0f;
 | 
			
		||||
                baseAreola *= 1.0f + progressDifference * Configurations.PermanentNippleChange;
 | 
			
		||||
                if (baseAreola > 1.0f) baseAreola = 1.0f;
 | 
			
		||||
                baseNipple *= 1.0f + progressDifference * Configurations.PermanentNippleChange;
 | 
			
		||||
                if (baseNipple > 1.0f) baseNipple = 1.0f;
 | 
			
		||||
                nippleProgress = newNippleProgress;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                nippleProgress -= tickInterval / (BabyHalfAge * GenDate.TicksPerYear);                
 | 
			
		||||
                if (nippleProgress < newNippleProgress) nippleProgress = newNippleProgress;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ChangeColor(float alpha)
 | 
			
		||||
        public void AdjustNippleProgress(float amount)
 | 
			
		||||
        {
 | 
			
		||||
            this.alpha = alpha;
 | 
			
		||||
            nippleProgress = Mathf.Clamp01(nippleProgress + amount);
 | 
			
		||||
            UpdateNipples();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void PregnancyTransition()
 | 
			
		||||
        public void AdjustNippleSizeImmediately(float amount)
 | 
			
		||||
        {
 | 
			
		||||
            alphaPermanent = Math.Min(MaxAlpha, alphaPermanent + Configurations.NipplePermanentTransitionVariance.VariationRange(VARIANT));
 | 
			
		||||
            areolaSizePermanent = Math.Min(MaxAreola, areolaSizePermanent + Configurations.NipplePermanentTransitionVariance.VariationRange(VARIANT));
 | 
			
		||||
            nippleSizePermanent = Math.Min(MaxNipple, nippleSizePermanent + Configurations.NipplePermanentTransitionVariance.VariationRange(VARIANT));
 | 
			
		||||
            alpha = Math.Min(MaxAlpha, alpha + Configurations.NippleTransitionVariance.VariationRange(VARIANT));
 | 
			
		||||
            areolaSize = Math.Min(MaxAreola, areolaSize + Configurations.NippleTransitionVariance.VariationRange(VARIANT));
 | 
			
		||||
            nippleSize = Math.Min(MaxNipple, nippleSize + Configurations.NippleTransitionVariance.VariationRange(VARIANT));
 | 
			
		||||
            pregnant = true;
 | 
			
		||||
            baseNipple = Mathf.Clamp01(baseNipple + amount);
 | 
			
		||||
            UpdateNipples();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void BirthTransition()
 | 
			
		||||
        public void AdjustAreolaSizeImmediately(float amount)
 | 
			
		||||
        {
 | 
			
		||||
            alpha = alphaPermanent;
 | 
			
		||||
            areolaSize = areolaSizePermanent;
 | 
			
		||||
            nippleSize = nippleSizePermanent;
 | 
			
		||||
            pregnant = false;
 | 
			
		||||
            ageOfLastBirth = parent.pawn.ageTracker.AgeBiologicalTicks;
 | 
			
		||||
            baseAreola = Mathf.Clamp01(baseAreola + amount);
 | 
			
		||||
            UpdateNipples();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void AdjustBreastSize(float amount)
 | 
			
		||||
        public void UpdateNipples()
 | 
			
		||||
        {
 | 
			
		||||
            parent.Severity += amount;
 | 
			
		||||
            breastSizeIncreased += amount;
 | 
			
		||||
            cachedAlpha = baseAlpha + nippleProgress * nippleChange;
 | 
			
		||||
            cachedAreola = baseAreola + nippleProgress * nippleChange;
 | 
			
		||||
            cachedNipple = baseNipple + nippleProgress * nippleChange;
 | 
			
		||||
 | 
			
		||||
            // For some reason, Props can go null when RJW relocates the chest (e.g. some animals), so catch that
 | 
			
		||||
            cachedColor = Colors.CMYKLerp(parent.pawn.story?.SkinColor ?? Color.white, (Props?.BlackNippleColor ?? CompProperties_Breast.DefaultBlacknippleColor.ToColor), Alpha);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustNippleSize(float amount)
 | 
			
		||||
        public void CopyBreastProperties(HediffComp_Breast original)
 | 
			
		||||
        {
 | 
			
		||||
            nippleSizePermanent = Math.Min(MaxNipple, nippleSizePermanent + amount);
 | 
			
		||||
            nippleSize = Math.Min(MaxNipple, nippleSize + amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustAreolaSize(float amount)
 | 
			
		||||
        {
 | 
			
		||||
            areolaSizePermanent = Math.Min(MaxAreola, areolaSizePermanent + amount);
 | 
			
		||||
            areolaSize = Math.Min(MaxAreola, areolaSize + amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RestoreBreastSize(float ratio)
 | 
			
		||||
        {
 | 
			
		||||
            float variance = breastSizeIncreased * Math.Min(ratio, 1.0f);
 | 
			
		||||
            breastSizeIncreased -= variance;
 | 
			
		||||
            parent.Severity -= variance;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustNippleSizeImmidiately(float amount)
 | 
			
		||||
        {
 | 
			
		||||
            originnipple = Math.Max(0, originnipple + amount);
 | 
			
		||||
            nippleSizePermanent = Math.Min(MaxNipple, nippleSizePermanent + amount);
 | 
			
		||||
            nippleSize = Math.Min(MaxNipple, nippleSize + amount);
 | 
			
		||||
            nippleSizeCurrent = nippleSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustAreolaSizeImmidiately(float amount)
 | 
			
		||||
        {
 | 
			
		||||
            originareola = Math.Max(0, originareola + amount);
 | 
			
		||||
            areolaSizePermanent = Math.Min(MaxAreola, areolaSizePermanent + amount);
 | 
			
		||||
            areolaSize = Math.Min(MaxAreola, areolaSize + amount);
 | 
			
		||||
            areolaSizeCurrent = areolaSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void UpdateColor()
 | 
			
		||||
        {
 | 
			
		||||
            cachedcolor = Colors.CMYKLerp(parent?.pawn?.story?.SkinColor ?? Color.white, Props.BlackNippleColor, Alpha);
 | 
			
		||||
            maxBreastIncrement = original.maxBreastIncrement;
 | 
			
		||||
            baseAlpha = original.baseAlpha;
 | 
			
		||||
            baseAreola = original.baseAreola;
 | 
			
		||||
            baseNipple = original.baseNipple;
 | 
			
		||||
            UpdateNipples();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string DebugInfo()
 | 
			
		||||
        {
 | 
			
		||||
            return "Increase: " + breastSizeIncreased +
 | 
			
		||||
            return "Size: " + parent.Severity +
 | 
			
		||||
                "\nIncrease: " + breastSizeIncreased +
 | 
			
		||||
                "\n" + debugGrowthStatus +
 | 
			
		||||
                "\nAlpha: " + alpha +
 | 
			
		||||
                "\nNippleSize: " + nippleSize +
 | 
			
		||||
                "\nAreolaSize: " + areolaSize +
 | 
			
		||||
                "\nAlphaCurrent: " + alphaCurrent +
 | 
			
		||||
                "\nNippleSizeCurrent: " + nippleSizeCurrent +
 | 
			
		||||
                "\nAreolaSizeCurrent: " + areolaSizeCurrent +
 | 
			
		||||
                "\nAlphaOrigin: " + originalpha +
 | 
			
		||||
                "\nNippleSizeOrigin: " + originnipple +
 | 
			
		||||
                "\nAreolaSizeOrigin: " + originareola +
 | 
			
		||||
                "\nAlphaMax: " + MaxAlpha +
 | 
			
		||||
                "\nNippleSizeMax: " + MaxNipple +
 | 
			
		||||
                "\nAreolaSizeMax: " + MaxAreola +
 | 
			
		||||
                "\nPermanentAlpha:" + alphaPermanent +
 | 
			
		||||
                "\nPermanentNipple:" + nippleSizePermanent +
 | 
			
		||||
                "\nPermanentAreola:" + areolaSizePermanent;
 | 
			
		||||
                "\nNipple progress: " + nippleProgress +
 | 
			
		||||
                "\nBase alpha: " + baseAlpha +
 | 
			
		||||
                "\nAlpha: " + cachedAlpha +
 | 
			
		||||
                "\nBase areola: " + baseAreola +
 | 
			
		||||
                "\nAreola: " + cachedAreola +
 | 
			
		||||
                "\nDisplayed areola: " + AreolaSize +
 | 
			
		||||
                "\nBase nipple: " + baseNipple +
 | 
			
		||||
                "\nNipple: " + cachedNipple +
 | 
			
		||||
                "\nDisplayed nipple: " + NippleSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
using HugsLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +69,6 @@ namespace RJW_Menstruation
 | 
			
		|||
        public CompProperties_Menstruation Props;
 | 
			
		||||
        public Stage curStage = Stage.Follicular;
 | 
			
		||||
        public int curStageHrs = 0;
 | 
			
		||||
        public Action actionref;
 | 
			
		||||
        public bool loaded = false;
 | 
			
		||||
        public int ovarypower = -100000;
 | 
			
		||||
        public int eggstack = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +137,22 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                if (opcache < 0) opcache = (int)(72f * parent.pawn.def.race.lifeExpectancy / ThingDefOf.Human.race.lifeExpectancy);
 | 
			
		||||
                if (opcache >= 0) return opcache;
 | 
			
		||||
                // Climacteric will set in 6 (human) years before egg exhaustion
 | 
			
		||||
                float avglittersize;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    avglittersize = Mathf.Max(Rand.ByCurveAverage(parent.pawn.def.race.litterSizeCurve), 1.0f);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    // Any exceptions in that will have been reported elsewhere in the code by now
 | 
			
		||||
                    avglittersize = 1.0f;
 | 
			
		||||
                };
 | 
			
		||||
                opcache = (int)(RaceCyclesPerYear() *
 | 
			
		||||
                    avglittersize *
 | 
			
		||||
                    6f *
 | 
			
		||||
                    (parent.pawn.def.race.lifeExpectancy / ThingDefOf.Human.race.lifeExpectancy));
 | 
			
		||||
                return opcache;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -487,7 +500,17 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return Mathf.Clamp01(curStageHrs / CurStageIntervalHours);
 | 
			
		||||
                if (pregnancy == null) return Mathf.Clamp01(curStageHrs / CurStageIntervalHours);
 | 
			
		||||
                if (pregnancy.is_discovered || Configurations.infoDetail == Configurations.DetailLevel.All) return pregnancy.Severity;
 | 
			
		||||
 | 
			
		||||
                // Luteal will appear to progress, hitting the end of the phase when the pregnancy is discovered
 | 
			
		||||
                float discoveryTime = 0.5f;
 | 
			
		||||
                if (parent.pawn.story?.bodyType == BodyTypeDefOf.Thin) discoveryTime = 0.25f;
 | 
			
		||||
                else if (parent.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));
 | 
			
		||||
                
 | 
			
		||||
                return GenMath.LerpDouble(0, discoveryTime, lutealProgressWhenImplanted, 1.0f, pregnancy.Severity);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -530,11 +553,69 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
        public override void CompPostTick(ref float severityAdjustment)
 | 
			
		||||
        {
 | 
			
		||||
            //initializer moved to SpawnSetup
 | 
			
		||||
            //if (!loaded)
 | 
			
		||||
            //{
 | 
			
		||||
            //    Initialize();
 | 
			
		||||
            //}
 | 
			
		||||
            base.CompPostTick(ref severityAdjustment);
 | 
			
		||||
            // If an exception makes it out, RW will remove the hediff, so catch it here
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (
 | 
			
		||||
                    !parent.pawn.IsHashIntervalTick(tickInterval) ||
 | 
			
		||||
                    !parent.pawn.Spawned || // TODO: Add option to simulate off-map pawns
 | 
			
		||||
                    parent.pawn.health.Dead ||
 | 
			
		||||
                    (parent.pawn.IsAnimal() && !Configurations.EnableAnimalCycle)
 | 
			
		||||
                    )
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                CumOut();
 | 
			
		||||
                if (pregnancy == null && parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young;
 | 
			
		||||
                switch (curStage)
 | 
			
		||||
                {
 | 
			
		||||
                    case Stage.Follicular:
 | 
			
		||||
                        FollicularAction(false);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Ovulatory:
 | 
			
		||||
                        OvulatoryAction();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Luteal:
 | 
			
		||||
                        LutealAction(false);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Bleeding:
 | 
			
		||||
                        BleedingAction(false);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Pregnant:
 | 
			
		||||
                        PregnantAction();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Recover:
 | 
			
		||||
                        RecoverAction();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.None:
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Young:
 | 
			
		||||
                        YoungAction();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.ClimactericFollicular:
 | 
			
		||||
                        FollicularAction(true);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.ClimactericLuteal:
 | 
			
		||||
                        LutealAction(true);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.ClimactericBleeding:
 | 
			
		||||
                        BleedingAction(true);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case Stage.Anestrus:
 | 
			
		||||
                        AnestrusAction();
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                        GoNextStage(Stage.Follicular);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
                AfterSimulator();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Error($"Error processing womb of {parent.pawn}: {ex}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void CompPostPostRemoved()
 | 
			
		||||
| 
						 | 
				
			
			@ -546,8 +627,6 @@ namespace RJW_Menstruation
 | 
			
		|||
                Log.Warning($"Attempted to remove menstruation comp from wrong pawn ({parent.pawn}).");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(actionref);
 | 
			
		||||
            if (Configurations.Debug) Log.Message(parent.pawn.Label + " menstruation tick scheduler removed");
 | 
			
		||||
            pregnancy?.Miscarry();
 | 
			
		||||
            base.CompPostPostRemoved();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -871,7 +950,6 @@ namespace RJW_Menstruation
 | 
			
		|||
            {
 | 
			
		||||
                if (cums == null) cums = new List<Cum>();
 | 
			
		||||
                curStage = Stage.None;
 | 
			
		||||
                HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
                loaded = true;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -912,18 +990,6 @@ namespace RJW_Menstruation
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (parent.pawn.IsAnimal())
 | 
			
		||||
            {
 | 
			
		||||
                if (Configurations.EnableAnimalCycle)
 | 
			
		||||
                {
 | 
			
		||||
                    HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (pregnancy == null && parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Young), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
                else HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
            }
 | 
			
		||||
            //Log.Message(parent.pawn.Label + " - Initialized menstruation comp");
 | 
			
		||||
            loaded = true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -995,7 +1061,7 @@ namespace RJW_Menstruation
 | 
			
		|||
                else if (ovarypower < OvaryPowerThreshold)
 | 
			
		||||
                {
 | 
			
		||||
                    Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn);
 | 
			
		||||
                    hediff.Severity = 0.008f * (OvaryPowerThreshold - ovarypower);
 | 
			
		||||
                    hediff.Severity = Mathf.InverseLerp(OvaryPowerThreshold, 0, ovarypower);
 | 
			
		||||
                    parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1146,14 +1212,12 @@ namespace RJW_Menstruation
 | 
			
		|||
                            PregnancyHelper.PregnancyDecider(parent.pawn, egg.fertilizer);
 | 
			
		||||
                            // I hate having to do this, but it gets the newest pregnancy
 | 
			
		||||
                            pregnancy = parent.pawn.health.hediffSet.GetHediffs<Hediff_BasePregnancy>().MaxBy(hediff => hediff.loadID);
 | 
			
		||||
                            currentIntervalHours = (int)pregnancy?.GestationHours();
 | 
			
		||||
                            pregnant = true;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            pregnancy = Hediff_BasePregnancy.Create<Hediff_MultiplePregnancy>(parent.pawn, egg.fertilizer);
 | 
			
		||||
                            currentIntervalHours = (int)pregnancy?.GestationHours();
 | 
			
		||||
                            pregnant = true;
 | 
			
		||||
                            deadeggs.Add(egg);
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1317,7 +1381,7 @@ namespace RJW_Menstruation
 | 
			
		|||
            float eggnum;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                eggnum = Rand.ByCurve(parent.pawn.RaceProps.litterSizeCurve);
 | 
			
		||||
                eggnum = Rand.ByCurve(parent.pawn.def.race.litterSizeCurve);
 | 
			
		||||
            }
 | 
			
		||||
            catch (NullReferenceException)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -1325,7 +1389,7 @@ namespace RJW_Menstruation
 | 
			
		|||
            }
 | 
			
		||||
            catch (ArgumentException e)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning($"Invalid litterSizeCurve for {parent.pawn.RaceProps}: {e}");
 | 
			
		||||
                Log.Warning($"Invalid litterSizeCurve for {parent.pawn.def}: {e}");
 | 
			
		||||
                eggnum = 1;
 | 
			
		||||
            }
 | 
			
		||||
            eggnum += eggstack;
 | 
			
		||||
| 
						 | 
				
			
			@ -1351,7 +1415,7 @@ namespace RJW_Menstruation
 | 
			
		|||
            else if (Configurations.EnableMenopause && ovarypower < OvaryPowerThreshold)
 | 
			
		||||
            {
 | 
			
		||||
                Hediff hediff = HediffMaker.MakeHediff(VariousDefOf.Hediff_Climacteric, parent.pawn);
 | 
			
		||||
                hediff.Severity = 0.008f * i;
 | 
			
		||||
                hediff.Severity = Mathf.InverseLerp(OvaryPowerThreshold, 0, ovarypower);
 | 
			
		||||
                parent.pawn.health.AddHediff(hediff, Genital_Helper.get_genitalsBPR(parent.pawn));
 | 
			
		||||
                GoNextStage(Stage.ClimactericLuteal);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1394,10 +1458,6 @@ namespace RJW_Menstruation
 | 
			
		|||
                EggDecay();
 | 
			
		||||
                if (Implant())
 | 
			
		||||
                {
 | 
			
		||||
                    if (Breast != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        Breast.PregnancyTransition();
 | 
			
		||||
                    }
 | 
			
		||||
                    GoNextStage(Stage.Pregnant);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
| 
						 | 
				
			
			@ -1459,10 +1519,6 @@ namespace RJW_Menstruation
 | 
			
		|||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (pregnancy != null) pregnancy = null;
 | 
			
		||||
                if (Breast != null)
 | 
			
		||||
                {
 | 
			
		||||
                    Breast.BirthTransition();
 | 
			
		||||
                }
 | 
			
		||||
                GoNextStage(Stage.Recover);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1584,108 +1640,12 @@ namespace RJW_Menstruation
 | 
			
		|||
            TaleRecorder.RecordTale(VariousDefOf.TaleCameInside, new object[] { cummer, parent.pawn });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Action PeriodSimulator(Stage targetstage)
 | 
			
		||||
        {
 | 
			
		||||
            Action action = null;
 | 
			
		||||
            switch (targetstage)
 | 
			
		||||
            {
 | 
			
		||||
                case Stage.Follicular:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        FollicularAction(false);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Ovulatory:
 | 
			
		||||
                    action = OvulatoryAction;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Luteal:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        LutealAction(false);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Bleeding:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        BleedingAction(false);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Pregnant:
 | 
			
		||||
                    action = PregnantAction;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Recover:
 | 
			
		||||
                    action = RecoverAction;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.None:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        StayCurrentStageConst(Stage.None);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Young:
 | 
			
		||||
                    action = YoungAction;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.ClimactericFollicular:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        FollicularAction(true);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.ClimactericLuteal:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        LutealAction(true);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.ClimactericBleeding:
 | 
			
		||||
                    action = delegate
 | 
			
		||||
                    {
 | 
			
		||||
                        BleedingAction(true);
 | 
			
		||||
                    };
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Anestrus:
 | 
			
		||||
                    action = AnestrusAction;
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    curStage = Stage.Follicular;
 | 
			
		||||
                    curStageHrs = 0;
 | 
			
		||||
                    if (currentIntervalHours < 0) currentIntervalHours = PeriodRandomizer(curStage);
 | 
			
		||||
                    HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(Stage.Follicular), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            action += delegate
 | 
			
		||||
            {
 | 
			
		||||
                if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young;
 | 
			
		||||
                //CumOut();
 | 
			
		||||
                AfterSimulator();
 | 
			
		||||
            };
 | 
			
		||||
            action = CumOut + action;
 | 
			
		||||
 | 
			
		||||
            actionref = action;
 | 
			
		||||
            return actionref;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected int GetNextUpdate()
 | 
			
		||||
        {
 | 
			
		||||
            // Ticks past the hour. Will be equal except for game start or load
 | 
			
		||||
            int currentOffset = Find.TickManager.TicksGame % tickInterval;
 | 
			
		||||
            int nextOffset = (parent.pawn.HashOffset() % tickInterval + tickInterval) % tickInterval;  // Messy, but HashOffset is negative a lot
 | 
			
		||||
 | 
			
		||||
            // The -1/+1 to ensure that equality works out to 1 hour and not 0 ticks
 | 
			
		||||
            return ((nextOffset - currentOffset + tickInterval - 1) % tickInterval) + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected void GoNextStage(Stage nextstage, bool calculateHours = true)
 | 
			
		||||
        {
 | 
			
		||||
            curStageHrs = 0;
 | 
			
		||||
            float variabilityFactor = nextstage == Stage.ClimactericFollicular || nextstage == Stage.ClimactericLuteal || nextstage == Stage.ClimactericBleeding ? 6.0f : 1.0f;
 | 
			
		||||
            if (calculateHours) currentIntervalHours = PeriodRandomizer(nextstage, variabilityFactor);
 | 
			
		||||
            curStage = nextstage;
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(nextstage), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected virtual void GoOvulatoryStage(bool climacteric)
 | 
			
		||||
| 
						 | 
				
			
			@ -1696,13 +1656,11 @@ namespace RJW_Menstruation
 | 
			
		|||
        //stage can be interrupted in other reasons
 | 
			
		||||
        protected void StayCurrentStage()
 | 
			
		||||
        {
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curStage), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //stage never changes
 | 
			
		||||
        protected void StayCurrentStageConst(Stage curstage)
 | 
			
		||||
        {
 | 
			
		||||
            HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(PeriodSimulator(curstage), GetNextUpdate(), parent.pawn, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected void GoFollicularOrBleeding()
 | 
			
		||||
| 
						 | 
				
			
			@ -1745,6 +1703,8 @@ namespace RJW_Menstruation
 | 
			
		|||
                    return (int)(Props.bleedingIntervalDays * 24 * (1 + Rand.Range(-cycleVariability, cycleVariability) * 0.5f * variabilityFactor) / (1 + (cycleSpeed - 1) * 0.5f));
 | 
			
		||||
                case Stage.Recover:
 | 
			
		||||
                    return (int)(Props.recoveryIntervalDays * 24 * Rand.Range(-0.05f, 0.05f));
 | 
			
		||||
                case Stage.Pregnant:
 | 
			
		||||
                    return (int)MenstruationUtility.GestationHours(pregnancy);
 | 
			
		||||
                default:    // Often unused
 | 
			
		||||
                    return 1;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1772,24 +1732,32 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
        protected Stage RandomStage()
 | 
			
		||||
        {
 | 
			
		||||
            int rand = Rand.ElementByWeight(
 | 
			
		||||
                0, Props.follicularIntervalDays - Props.bleedingIntervalDays,
 | 
			
		||||
                1, Props.lutealIntervalDays,
 | 
			
		||||
                2, Props.bleedingIntervalDays);
 | 
			
		||||
            Stage stage = Rand.ElementByWeight(
 | 
			
		||||
                Stage.Follicular, Props.follicularIntervalDays - Props.bleedingIntervalDays,
 | 
			
		||||
                Stage.Luteal, Props.lutealIntervalDays,
 | 
			
		||||
                Stage.Bleeding, Props.bleedingIntervalDays);
 | 
			
		||||
 | 
			
		||||
            switch (rand)
 | 
			
		||||
            switch (stage)
 | 
			
		||||
            {
 | 
			
		||||
                case 0:
 | 
			
		||||
                case Stage.Follicular:
 | 
			
		||||
                    curStageHrs = Rand.Range(0, (Props.follicularIntervalDays - Props.bleedingIntervalDays) * 24);
 | 
			
		||||
                    return Stage.Follicular;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Luteal:
 | 
			
		||||
                    curStageHrs = Rand.Range(0, Props.lutealIntervalDays * 24);
 | 
			
		||||
                    return Stage.Luteal;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    break;
 | 
			
		||||
                case Stage.Bleeding:
 | 
			
		||||
                    curStageHrs = Rand.Range(0, Props.bleedingIntervalDays * 24);
 | 
			
		||||
                    return Stage.Bleeding;
 | 
			
		||||
                default: return Stage.Follicular;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            return stage;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void CopyCycleProperties(HediffComp_Menstruation original)
 | 
			
		||||
        {
 | 
			
		||||
            cycleSpeed = original.cycleSpeed;
 | 
			
		||||
            cycleVariability = original.cycleVariability;
 | 
			
		||||
            ovarypower = original.ovarypower;
 | 
			
		||||
            crampPain = original.crampPain;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class Egg : IExposable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,8 @@ namespace RJW_Menstruation
 | 
			
		|||
{
 | 
			
		||||
    public class Hediff_MultiplePregnancy : Hediff_BasePregnancy
 | 
			
		||||
    {
 | 
			
		||||
        protected Dictionary<Pawn, Pawn> enzygoticSiblings;  // Each pawn and who they split from
 | 
			
		||||
 | 
			
		||||
        public override void DiscoverPregnancy()
 | 
			
		||||
        {
 | 
			
		||||
            PregnancyThought();
 | 
			
		||||
| 
						 | 
				
			
			@ -185,6 +187,68 @@ namespace RJW_Menstruation
 | 
			
		|||
            //baby.story.birthLastName = last_name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
         protected void CopyBodyPartProperties(Hediff part, Hediff originalPart)
 | 
			
		||||
        {
 | 
			
		||||
            CompHediffBodyPart comp = part.TryGetComp<CompHediffBodyPart>();
 | 
			
		||||
            CompHediffBodyPart originalComp = originalPart.TryGetComp<CompHediffBodyPart>();
 | 
			
		||||
 | 
			
		||||
            if (comp != null && originalComp != null)
 | 
			
		||||
            {
 | 
			
		||||
                // the string properties should be the same between both pawns anyways, besides the name of the owner
 | 
			
		||||
                part.Severity = originalPart.Severity;
 | 
			
		||||
                comp.SizeBase = originalComp.SizeBase;
 | 
			
		||||
                comp.SizeOwner = originalComp.SizeOwner;
 | 
			
		||||
                comp.EffSize = originalComp.EffSize;
 | 
			
		||||
                comp.FluidAmmount = originalComp.FluidAmmount;
 | 
			
		||||
                comp.FluidModifier = originalComp.FluidModifier;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            HediffComp_Menstruation originalMenstruationComp = originalPart.GetMenstruationComp();
 | 
			
		||||
            if (originalMenstruationComp != null)
 | 
			
		||||
            {
 | 
			
		||||
                part.GetMenstruationComp()?.CopyCycleProperties(originalMenstruationComp);
 | 
			
		||||
            }
 | 
			
		||||
            HediffComp_Breast originalBreastComp = originalPart.GetBreastComp();
 | 
			
		||||
            if (originalBreastComp != null)
 | 
			
		||||
            {
 | 
			
		||||
                part.GetBreastComp()?.CopyBreastProperties(originalBreastComp);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected void CopyBodyPartRecord(Pawn baby, Pawn original, BodyPartRecord babyBPR, BodyPartRecord originalBPR)
 | 
			
		||||
        {
 | 
			
		||||
            if (babyBPR == null || originalBPR == null) return;
 | 
			
		||||
 | 
			
		||||
            RemoveBabyParts(baby, Genital_Helper.get_PartsHediffList(baby, babyBPR));
 | 
			
		||||
            foreach (Hediff originalPart in Genital_Helper.get_PartsHediffList(original, originalBPR))
 | 
			
		||||
            {
 | 
			
		||||
                Hediff part = SexPartAdder.MakePart(originalPart.def, baby, babyBPR);
 | 
			
		||||
                CopyBodyPartProperties(part, originalPart);
 | 
			
		||||
                baby.health.AddHediff(part, babyBPR);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Baby is the sibling to be changed, original is the first of the set and the one to copy to the rest.
 | 
			
		||||
        public virtual void ProcessIdenticalSibling(Pawn baby, Pawn original)
 | 
			
		||||
        {
 | 
			
		||||
            // They'll be the same pawnkind, which lets us make a lot of useful assumptions
 | 
			
		||||
            // However, some RNG might still be involved in genital generation (e.g. futas), so the easiest method is to clear out and re-generate
 | 
			
		||||
            // A bit wasteful since Hediff_BasePregnancy.PostBirth already redid the genitals
 | 
			
		||||
            CopyBodyPartRecord(baby, original, Genital_Helper.get_genitalsBPR(baby), Genital_Helper.get_genitalsBPR(original));
 | 
			
		||||
            CopyBodyPartRecord(baby, original, Genital_Helper.get_breastsBPR(baby), Genital_Helper.get_breastsBPR(original));
 | 
			
		||||
            CopyBodyPartRecord(baby, original, Genital_Helper.get_anusBPR(baby), Genital_Helper.get_anusBPR(original));
 | 
			
		||||
            if (baby.IsHAR())
 | 
			
		||||
                HARCompatibility.CopyHARPropertiesPostBirth(baby, original);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void PostBirth(Pawn mother, Pawn father, Pawn baby)
 | 
			
		||||
        {
 | 
			
		||||
            base.PostBirth(mother, father, baby);
 | 
			
		||||
            // Has to happen on birth since RJW redoes the genitals at birth
 | 
			
		||||
            if (!enzygoticSiblings.NullOrEmpty() && enzygoticSiblings.TryGetValue(baby, out Pawn original) && baby != original)
 | 
			
		||||
                ProcessIdenticalSibling(baby, original);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // From RJW's trait code
 | 
			
		||||
        protected List<Trait> GetInheritableTraits(Pawn mother, Pawn father)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -279,13 +343,17 @@ namespace RJW_Menstruation
 | 
			
		|||
            return traitpool;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void ExposeData()
 | 
			
		||||
        {
 | 
			
		||||
            base.ExposeData();
 | 
			
		||||
            Scribe_Collections.Look(ref enzygoticSiblings, "enzygoticSiblings", keyLookMode: LookMode.Reference, valueLookMode: LookMode.Reference);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void GenerateBabies()
 | 
			
		||||
        {
 | 
			
		||||
            AddNewBaby(pawn, father);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        protected void Train(Pawn baby, Pawn mother)
 | 
			
		||||
        {
 | 
			
		||||
            if (xxx.is_human(baby) || baby.Faction != Faction.OfPlayer) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -348,27 +416,25 @@ namespace RJW_Menstruation
 | 
			
		|||
                );
 | 
			
		||||
 | 
			
		||||
            int division = 1;
 | 
			
		||||
            HairDef firsthair = null;
 | 
			
		||||
            Color firsthaircolor = Color.white;
 | 
			
		||||
            BodyTypeDef firstbody = null;
 | 
			
		||||
            CrownType firstcrown = CrownType.Undefined;
 | 
			
		||||
            Pawn firstbaby = null;
 | 
			
		||||
            string firstheadpath = null;
 | 
			
		||||
            string firstHARcrown = null;
 | 
			
		||||
            int traitSeed = Rand.Int;
 | 
			
		||||
            List<Trait> parentTraits = GetInheritableTraits(mother, father);
 | 
			
		||||
            while (Rand.Chance(Configurations.EnzygoticTwinsChance) && division < Configurations.MaxEnzygoticTwins) division++;
 | 
			
		||||
            for (int i = 0; i < division; i++)
 | 
			
		||||
            {
 | 
			
		||||
                Pawn baby = GenerateBaby(request, mother, father, parentTraits, traitSeed);
 | 
			
		||||
                if (baby == null) break;
 | 
			
		||||
                if (division > 1)
 | 
			
		||||
                {
 | 
			
		||||
                    if (i == 0 && baby.story != null)
 | 
			
		||||
                    if (i == 0) firstbaby = baby;
 | 
			
		||||
                    else enzygoticSiblings?.Add(baby, firstbaby);
 | 
			
		||||
 | 
			
		||||
                    if (baby.story == null) continue;
 | 
			
		||||
 | 
			
		||||
                    if (i == 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        firsthair = baby.story.hairDef;
 | 
			
		||||
                        firsthaircolor = baby.story.hairColor;
 | 
			
		||||
                        request.FixedGender = baby.gender;
 | 
			
		||||
                        firstbody = baby.story.bodyType;
 | 
			
		||||
                        firstcrown = baby.story.crownType;
 | 
			
		||||
                        firstheadpath = (string)baby.story.GetMemberValue("headGraphicPath");
 | 
			
		||||
                        if (firstheadpath == null)
 | 
			
		||||
                        {
 | 
			
		||||
| 
						 | 
				
			
			@ -376,36 +442,25 @@ namespace RJW_Menstruation
 | 
			
		|||
                            if (head != null) baby.story.SetMemberValue("headGraphicPath", head.GraphicPath);
 | 
			
		||||
                            firstheadpath = (string)baby.story.GetMemberValue("headGraphicPath");
 | 
			
		||||
                        }
 | 
			
		||||
                        if (Configurations.HARActivated && baby.IsHAR())
 | 
			
		||||
                        {
 | 
			
		||||
                            firstHARcrown = baby.GetHARCrown();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        if (baby.story != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            baby.story.hairDef = firsthair;
 | 
			
		||||
                            baby.story.hairColor = firsthaircolor;
 | 
			
		||||
                            baby.story.bodyType = firstbody;
 | 
			
		||||
                            baby.story.crownType = firstcrown;
 | 
			
		||||
                            baby.story.SetMemberValue("headGraphicPath", firstheadpath);
 | 
			
		||||
                        baby.story.hairDef = firstbaby.story.hairDef;
 | 
			
		||||
                        baby.story.hairColor = firstbaby.story.hairColor;
 | 
			
		||||
                        baby.story.bodyType = firstbaby.story.bodyType;
 | 
			
		||||
                        baby.story.crownType = firstbaby.story.crownType;
 | 
			
		||||
                        baby.story.SetMemberValue("headGraphicPath", firstheadpath);
 | 
			
		||||
 | 
			
		||||
                            if (Configurations.HARActivated && baby.IsHAR())
 | 
			
		||||
                            {
 | 
			
		||||
                                baby.SetHARCrown(firstHARcrown);
 | 
			
		||||
                            }
 | 
			
		||||
                        if (baby.IsHAR())
 | 
			
		||||
                        {
 | 
			
		||||
                            HARCompatibility.CopyHARProperties(baby, firstbaby);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (baby != null) babies.Add(baby);
 | 
			
		||||
                babies.Add(baby);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -665,8 +720,17 @@ namespace RJW_Menstruation
 | 
			
		|||
            pawn.story.traits.allTraits = selectedTraits;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Initialize(Pawn mother, Pawn dad)
 | 
			
		||||
        {
 | 
			
		||||
            enzygoticSiblings = new Dictionary<Pawn, Pawn>();
 | 
			
		||||
            base.Initialize(mother, dad);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public string DueDate()
 | 
			
		||||
        {
 | 
			
		||||
            if (pawn.Map == null) return "";
 | 
			
		||||
            return GenDate.DateFullStringWithHourAt(GenDate.TickGameToAbs((int)p_end_tick), Find.WorldGrid.LongLatOf(pawn.Map.Tile));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,12 +43,18 @@ namespace RJW_Menstruation
 | 
			
		|||
        {
 | 
			
		||||
            Texture2D icon, icon_overay;
 | 
			
		||||
            string description = "";
 | 
			
		||||
            if (Configurations.Debug) description += comp.curStage + ": " + comp.curStageHrs + "\n" + "fertcums: " + comp.TotalFertCum + "\n" + "ovarypower: " + comp.ovarypower + "\n" + "eggs: " + comp.GetNumofEggs + "\n";
 | 
			
		||||
            if (Configurations.Debug) {
 | 
			
		||||
                description += comp.curStage + ": " + comp.curStageHrs + "\n" +
 | 
			
		||||
                (comp.Pregnancy is Hediff_MultiplePregnancy preg ? "due: " + preg.DueDate() + "\n" : "") +
 | 
			
		||||
                "fertcums: " + comp.TotalFertCum + "\n" +
 | 
			
		||||
                "ovarypower: " + comp.ovarypower + "\n" +
 | 
			
		||||
                "eggs: " + comp.GetNumofEggs + "\n";
 | 
			
		||||
            }
 | 
			
		||||
            else description += comp.GetCurStageLabel + "\n";
 | 
			
		||||
            if (pawn.IsPregnant())
 | 
			
		||||
            {
 | 
			
		||||
                Hediff_BasePregnancy hediff = comp.Pregnancy;
 | 
			
		||||
                if (Utility.ShowFetusImage(hediff))
 | 
			
		||||
                if (hediff != null && Utility.ShowFetusImage(hediff))
 | 
			
		||||
                {
 | 
			
		||||
                    icon = comp.GetPregnancyIcon(hediff);
 | 
			
		||||
                    if (hediff is Hediff_BasePregnancy h)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using HugsLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
| 
						 | 
				
			
			@ -16,14 +15,12 @@ namespace RJW_Menstruation
 | 
			
		|||
            //Log.Message("Initialize on spawnsetup");
 | 
			
		||||
            foreach (HediffComp_Menstruation comp in __instance.GetMenstruationComps())
 | 
			
		||||
            {
 | 
			
		||||
                HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(comp.actionref);
 | 
			
		||||
                comp.Initialize();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            HediffComp_Breast bcomp = __instance.GetBreastComp();
 | 
			
		||||
            if (bcomp != null)
 | 
			
		||||
            {
 | 
			
		||||
                HugsLibController.Instance.TickDelayScheduler.TryUnscheduleCallback(bcomp.action);
 | 
			
		||||
                bcomp.Initialize();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,12 +89,12 @@
 | 
			
		|||
    <Compile Include="VariousDefOf.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Reference Include="Assembly-CSharp">
 | 
			
		||||
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
 | 
			
		||||
    <Reference Include="AlienRace">
 | 
			
		||||
      <HintPath>..\..\..\..\..\..\..\..\workshop\content\294100\839005762\1.3\Assemblies\AlienRace.dll</HintPath>
 | 
			
		||||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="HugsLib">
 | 
			
		||||
      <HintPath>..\..\..\..\..\..\..\..\workshop\content\294100\818773962\v1.3\Assemblies\HugsLib.dll</HintPath>
 | 
			
		||||
    <Reference Include="Assembly-CSharp">
 | 
			
		||||
      <HintPath>..\..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
 | 
			
		||||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="RJW">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ namespace RJW_Menstruation
 | 
			
		|||
    {
 | 
			
		||||
        protected override void SurgeryResult(HediffComp_Breast breast)
 | 
			
		||||
        {
 | 
			
		||||
            breast.AdjustAreolaSizeImmidiately(0.1f);
 | 
			
		||||
            breast.AdjustAreolaSizeImmediately(0.2f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ namespace RJW_Menstruation
 | 
			
		|||
    {
 | 
			
		||||
        protected override void SurgeryResult(HediffComp_Breast breast)
 | 
			
		||||
        {
 | 
			
		||||
            breast.AdjustAreolaSizeImmidiately(-0.1f);
 | 
			
		||||
            breast.AdjustAreolaSizeImmediately(-0.2f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +64,7 @@ namespace RJW_Menstruation
 | 
			
		|||
    {
 | 
			
		||||
        protected override void SurgeryResult(HediffComp_Breast breast)
 | 
			
		||||
        {
 | 
			
		||||
            breast.AdjustNippleSizeImmidiately(0.1f);
 | 
			
		||||
            breast.AdjustNippleSizeImmediately(0.2f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ namespace RJW_Menstruation
 | 
			
		|||
    {
 | 
			
		||||
        protected override void SurgeryResult(HediffComp_Breast breast)
 | 
			
		||||
        {
 | 
			
		||||
            breast.AdjustNippleSizeImmidiately(-0.1f);
 | 
			
		||||
            breast.AdjustNippleSizeImmediately(-0.2f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,14 +98,6 @@ namespace RJW_Menstruation
 | 
			
		|||
        public static readonly string Option23_Label = "Option23_Label".Translate();
 | 
			
		||||
        public static readonly string Option23_Label_1 = "Option23_Label_1".Translate();
 | 
			
		||||
        public static readonly string Option23_Label_2 = "Option23_Label_2".Translate();
 | 
			
		||||
        public static readonly string Option24_Label = "Option24_Label".Translate();
 | 
			
		||||
        public static readonly string Option24_Desc = "Option24_Desc".Translate();
 | 
			
		||||
        public static readonly string Option25_Label = "Option25_Label".Translate();
 | 
			
		||||
        public static readonly string Option25_Desc = "Option25_Desc".Translate();
 | 
			
		||||
        public static readonly string Option26_Label = "Option26_Label".Translate();
 | 
			
		||||
        public static readonly string Option26_Desc = "Option26_Desc".Translate();
 | 
			
		||||
        public static readonly string Option27_Label = "Option27_Label".Translate();
 | 
			
		||||
        public static readonly string Option27_Desc = "Option27_Desc".Translate();
 | 
			
		||||
        public static readonly string Option28_Label = "Option28_Label".Translate();
 | 
			
		||||
        public static readonly string Option28_Tooltip = "Option28_Tooltip".Translate();
 | 
			
		||||
        public static readonly string Option29_Label = "Option29_Label".Translate();
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +108,12 @@ namespace RJW_Menstruation
 | 
			
		|||
        public static readonly string Option31_Desc = "Option31_Desc".Translate();
 | 
			
		||||
        public static readonly string Option32_Label = "Option32_Label".Translate();
 | 
			
		||||
        public static readonly string Option32_Desc = "Option32_Desc".Translate();
 | 
			
		||||
        public static readonly string Option_MaxBreastIncrementFactor_Label = "Option_MaxBreastIncrementFactor_Label".Translate();
 | 
			
		||||
        public static readonly string Option_MaxBreastIncrementFactor_Desc = "Option_MaxBreastIncrementFactor_Desc".Translate();
 | 
			
		||||
        public static readonly string Option_MaxNippleIncrementFactor_Label = "Option_MaxNippleIncrementFactor_Label".Translate();
 | 
			
		||||
        public static readonly string Option_MaxNippleIncrementFactor_Desc = "Option_MaxNippleIncrementFactor_Desc".Translate();
 | 
			
		||||
        public static readonly string Option_PermanentNippleChange_Label = "Option_PermanentNippleChange_Label".Translate();
 | 
			
		||||
        public static readonly string Option_PermanentNippleChange_Desc = "Option_PermanentNippleChange_Desc".Translate();
 | 
			
		||||
        public static readonly string Option_EnableGatherCumGizmo_Label = "Option_EnableGatherCumGizmo_Label".Translate();
 | 
			
		||||
        public static readonly string Option_EstrusOverride_Label = "Option_EstrusOverride_Label".Translate();
 | 
			
		||||
        public static readonly string Option_EstrusOverride_Desc = "Option_EstrusOverride_Desc".Translate();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,11 +32,11 @@ namespace RJW_Menstruation
 | 
			
		|||
        private Texture2D anal;
 | 
			
		||||
        private Color cumcolor;
 | 
			
		||||
 | 
			
		||||
        private readonly GUIStyle fontstylecenter = new GUIStyle() { alignment = TextAnchor.MiddleCenter };
 | 
			
		||||
        private readonly GUIStyle fontstyleright = new GUIStyle() { alignment = TextAnchor.MiddleRight };
 | 
			
		||||
        private readonly GUIStyle fontstyleleft = new GUIStyle() { alignment = TextAnchor.MiddleLeft };
 | 
			
		||||
        private readonly GUIStyle boxstyle = new GUIStyle(GUI.skin.textArea);
 | 
			
		||||
        private readonly GUIStyle buttonstyle = new GUIStyle(GUI.skin.button);
 | 
			
		||||
        private static GUIStyle fontstylecenter = null;
 | 
			
		||||
        private static GUIStyle fontstyleright = null;
 | 
			
		||||
        private static GUIStyle fontstyleleft = null;
 | 
			
		||||
        private static GUIStyle boxstyle = null;
 | 
			
		||||
        private static GUIStyle buttonstyle = null;
 | 
			
		||||
 | 
			
		||||
        public Pawn Pawn
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -137,6 +137,16 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void PreOpen()
 | 
			
		||||
        {
 | 
			
		||||
            base.PreOpen();
 | 
			
		||||
            if (fontstylecenter == null) fontstylecenter = new GUIStyle() { alignment = TextAnchor.MiddleCenter };
 | 
			
		||||
            if (fontstyleright == null) fontstyleright = new GUIStyle() { alignment = TextAnchor.MiddleRight };
 | 
			
		||||
            if (fontstyleleft == null) fontstyleleft = new GUIStyle() { alignment = TextAnchor.MiddleLeft };
 | 
			
		||||
            if (boxstyle == null) boxstyle = new GUIStyle(GUI.skin.textArea);
 | 
			
		||||
            if (buttonstyle == null) buttonstyle = new GUIStyle(GUI.skin.button);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void MainContents(Rect mainRect)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -370,7 +380,7 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            pawn.DrawBreastIcon(BreastIconRect, Mouse.IsOver(BreastIconRect) && Input.GetMouseButton(0));
 | 
			
		||||
            pawn.DrawBreastIcon(BreastIconRect);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            GUI.color = Color.white;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,7 +159,7 @@ namespace RJW_Menstruation
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void DrawBreastIcon(this Pawn pawn, Rect rect, bool drawOrigin = false)
 | 
			
		||||
        public static void DrawBreastIcon(this Pawn pawn, Rect rect)
 | 
			
		||||
        {
 | 
			
		||||
            Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("breast"));
 | 
			
		||||
            Texture2D breast, nipple, areola;
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +167,7 @@ namespace RJW_Menstruation
 | 
			
		|||
            {
 | 
			
		||||
                HediffComp_Breast comp = hediff.TryGetComp<HediffComp_Breast>();
 | 
			
		||||
                string icon;
 | 
			
		||||
                if (comp != null) icon = comp.Props.BreastTex ?? "Breasts/Breast_Breast";
 | 
			
		||||
                if (comp != null) icon = comp.Props?.BreastTex ?? "Breasts/Breast_Breast";
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    breast = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00", false);
 | 
			
		||||
| 
						 | 
				
			
			@ -191,16 +191,8 @@ namespace RJW_Menstruation
 | 
			
		|||
 | 
			
		||||
                string nippleicon, areolaicon;
 | 
			
		||||
                float nipplesize, areolasize;
 | 
			
		||||
                if (drawOrigin)
 | 
			
		||||
                {
 | 
			
		||||
                    nipplesize = comp.OriginNipple;
 | 
			
		||||
                    areolasize = comp.OriginAreola;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    nipplesize = comp.NippleSize;
 | 
			
		||||
                    areolasize = comp.AreolaSize;
 | 
			
		||||
                }
 | 
			
		||||
                nipplesize = comp.NippleSize;
 | 
			
		||||
                areolasize = comp.AreolaSize;
 | 
			
		||||
 | 
			
		||||
                nippleicon = icon + "_Nipple0" + GetNippleIndex(nipplesize);
 | 
			
		||||
                areolaicon = icon + "_Areola0" + GetAreolaIndex(areolasize);
 | 
			
		||||
| 
						 | 
				
			
			@ -212,14 +204,8 @@ namespace RJW_Menstruation
 | 
			
		|||
                GUI.color = pawn.story.SkinColor;
 | 
			
		||||
                GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
 | 
			
		||||
 | 
			
		||||
                if (drawOrigin)
 | 
			
		||||
                {
 | 
			
		||||
                    GUI.color = comp.OriginColor;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    GUI.color = comp.NippleColor;
 | 
			
		||||
                }
 | 
			
		||||
                GUI.color = comp.NippleColor;
 | 
			
		||||
                
 | 
			
		||||
                GUI.DrawTexture(rect, areola, ScaleMode.ScaleToFit);
 | 
			
		||||
 | 
			
		||||
                GUI.DrawTexture(rect, nipple, ScaleMode.ScaleToFit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,12 +13,6 @@
 | 
			
		|||
			<steamWorkshopUrl>steam://url/CommunityFilePage/2009463077</steamWorkshopUrl>
 | 
			
		||||
			<downloadUrl>https://github.com/pardeike/HarmonyRimWorld/releases/latest</downloadUrl>
 | 
			
		||||
		</li>
 | 
			
		||||
		<li>
 | 
			
		||||
			<packageId>UnlimitedHugs.HugsLib</packageId>
 | 
			
		||||
			<displayName>HugsLib</displayName>
 | 
			
		||||
			<downloadUrl>https://github.com/UnlimitedHugs/RimworldHugsLib/releases/latest</downloadUrl>
 | 
			
		||||
			<steamWorkshopUrl>steam://url/CommunityFilePage/818773962</steamWorkshopUrl>
 | 
			
		||||
		</li>
 | 
			
		||||
		<li>
 | 
			
		||||
			<packageId>rim.job.world</packageId>
 | 
			
		||||
			<displayName>RimJobWorld</displayName>
 | 
			
		||||
| 
						 | 
				
			
			@ -26,12 +20,13 @@
 | 
			
		|||
		</li>
 | 
			
		||||
	</modDependencies>
 | 
			
		||||
	<loadAfter>
 | 
			
		||||
		<li>UnlimitedHugs.HugsLib</li>
 | 
			
		||||
		<li>brrainz.harmony</li>
 | 
			
		||||
		<li>erdelf.HumanoidAlienRaces</li>
 | 
			
		||||
		<li>rim.job.world</li>
 | 
			
		||||
		<li>Abraxas.RJW.RaceSupport</li>
 | 
			
		||||
		<li>rjw.milk.humanoid</li>
 | 
			
		||||
		<li>rjw.sexperience</li>
 | 
			
		||||
		<li>rjw.cum</li>
 | 
			
		||||
	</loadAfter>
 | 
			
		||||
	<packageId>rjw.menstruation</packageId>
 | 
			
		||||
	<description>Adds menstruation mechanics to vaginas
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
			
		||||
<Manifest>
 | 
			
		||||
	<identifier>RJW Menstruation</identifier>
 | 
			
		||||
	<version>1.0.7.0</version>
 | 
			
		||||
	<version>1.0.7.1</version>
 | 
			
		||||
	<dependencies>
 | 
			
		||||
	</dependencies>
 | 
			
		||||
	<incompatibleWith />
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +12,7 @@
 | 
			
		|||
		<li>Abraxas.RJW.RaceSupport</li>
 | 
			
		||||
		<li>rjw.milk.humanoid</li>
 | 
			
		||||
		<li>rjw.sexperience</li>
 | 
			
		||||
		<li>rjw.cum</li>
 | 
			
		||||
	</loadAfter>
 | 
			
		||||
	<suggests>
 | 
			
		||||
	</suggests>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,15 @@
 | 
			
		|||
Version 1.0.7.1
 | 
			
		||||
 - Null reference error fix for multiple wombs when one is pregnant.
 | 
			
		||||
 - Fix the progress bar on pregnancy again. Also make undiscovered pregnancies a little more subtle.
 | 
			
		||||
 - Nipple size/transition system rewritten to be simpler under the hood. Should work with existing saves, but you might find sizes to be different, especially for very large or very small breasts.
 | 
			
		||||
 - Replaced HugsLib-based scheduler with normal ticking. This should reduce some 'phantom cycle' bugs.
 | 
			
		||||
 - Redone calculation to determine low eggs remaining. This should cause climacteric to be applied at a more appropriate time in the pawn's life, especially for those with very long cycles.
 | 
			
		||||
 - Identical twins conceived after this update will have identical sex part sizes, properties, etc. upon being born.
 | 
			
		||||
 - Identical twins of HAR races will have identical coloration, part variations, and masking.
 | 
			
		||||
 - For modders:
 | 
			
		||||
 - The function Hediff_MultiplePregnancy.ProcessIdenticalSibling is called on every identical sibling when born except the first. Any race-specfic genetic properties can be patched in there.
 | 
			
		||||
 - Any mods that add comps to RJW parts should copy what they need to on a postfix to Hediff_MultiplePregnancy.CopyBodyPartProperties, e.g. how menstruation itself does in that function.
 | 
			
		||||
 | 
			
		||||
Version 1.0.7.0
 | 
			
		||||
 - Not save compatible with previous versions. Expect glitches and many red errors if you try. However, things should stabilize eventually.
 | 
			
		||||
 - Designed for RJW 5.0.0, but should work with previous versions.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue