rjw_menstruation/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs

416 lines
16 KiB
C#
Raw Normal View History

using HugsLib;
using RimWorld;
using rjw;
using System;
using System.Collections.Generic;
using UnityEngine;
using Verse;
namespace RJW_Menstruation
{
public class CompProperties_Breast : HediffCompProperties
{
public string BreastTex = "Breasts/Breast";
public ColorInt BlacknippleColor = new ColorInt(55, 20, 0);
public Color BlackNippleColor
{
get
{
return BlacknippleColor.ToColor;
}
}
public CompProperties_Breast()
{
compClass = typeof(HediffComp_Breast);
}
}
public class HediffComp_Breast : HediffComp
{
2021-06-30 16:02:42 +00:00
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 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 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;
2021-06-16 12:53:52 +00:00
protected bool loaded = false;
2021-06-30 16:02:42 +00:00
protected bool pregnant = false;
public Action action;
protected float BabyHalfAge
{
get
{
float res = 0;
List<LifeStageAge> ages = parent.pawn.RaceProps.lifeStageAges;
if (ages?.Count > 1)
res = ages[1].minAge / 2;
if (res <= 0) res = 1.2f / 2; // Default to human
if (RJWPregnancySettings.phantasy_pregnancy)
res /= GenDate.DaysPerYear;
return res;
}
}
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 shrinkAmount = Mathf.Min(shrinkRate, breastSizeIncreased);
breastSizeIncreased -= shrinkAmount;
parent.Severity -= shrinkAmount;
}
public float MaxAlpha
{
get
{
return originalpha + Configurations.NippleMaximumTransition;
}
}
public float MaxAreola
{
get
{
return originareola + Configurations.NippleMaximumTransition;
}
}
public float MaxNipple
{
get
{
return originnipple + Configurations.NippleMaximumTransition;
}
}
2021-08-13 15:29:43 +00:00
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;
}
}
public float Alpha
{
get
{
return alphaCurrent;
}
}
public float NippleSize
{
get
{
return nippleSizeCurrent;
}
}
public float AreolaSize
{
get
{
return areolaSizeCurrent;
}
}
public float BreastSizeIncreased
{
get
{
return breastSizeIncreased;
}
}
public override void CompExposeData()
{
base.CompExposeData();
2021-06-30 16:02:42 +00:00
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);
2021-06-30 16:02:42 +00:00
Scribe_Values.Look(ref pregnant, "pregnant", pregnant, true);
}
public override void CompPostTick(ref float severityAdjustment) { }
2021-06-16 12:53:52 +00:00
public override void CompPostPostAdd(DamageInfo? dinfo)
{
if (!loaded) Initialize();
if (ageOfLastBirth > parent.pawn.ageTracker.AgeChronologicalTicks) ageOfLastBirth = CalculateLastBirth(); // catch transplant issues
2021-06-16 12:53:52 +00:00
}
public override void CompPostPostRemoved()
{
if (parent.pawn.health.hediffSet.hediffs.Contains(parent))
{
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();
2021-06-16 12:53:52 +00:00
}
protected long CalculateLastBirth()
{
long youngestAge = (long)(BabyHalfAge * GenDate.TicksPerYear) * -2; // So a newborn isn't considered a new mother, either
if ((parent.pawn.relations?.ChildrenCount ?? 0) > 0)
{
foreach (Pawn child in parent.pawn.relations.Children)
{
bool isFetus = false;
foreach (Hediff_BasePregnancy preg in parent.pawn.health.hediffSet.GetHediffs<Hediff_BasePregnancy>())
{
if (preg.babies.Contains(child))
{
isFetus = true;
break;
}
}
if (
parent.pawn.ageTracker.BirthAbsTicks - child.ageTracker.BirthAbsTicks > ageOfLastBirth &&
!isFetus &&
child.GetMother() == parent.pawn // Don't do Dad's boobs
)
youngestAge = parent.pawn.ageTracker.BirthAbsTicks - child.ageTracker.BirthAbsTicks;
}
}
return youngestAge;
}
public void Initialize()
{
Props = (CompProperties_Breast)props;
action = Transition;
if (ageOfLastBirth == 0)
{
ageOfLastBirth = CalculateLastBirth();
}
if (alphaPermanent < 0f)
{
alphaPermanent = (Utility.RandGaussianLike(0.0f, 0.3f) + Rand.Range(0.0f, 0.5f)) / 2;
originalpha = alphaPermanent;
alpha = alphaPermanent;
alphaCurrent = alphaPermanent;
}
if (areolaSizePermanent < 0f)
{
areolaSizePermanent = Utility.RandGaussianLike(0f, parent.Severity);
originareola = areolaSizePermanent;
areolaSize = areolaSizePermanent;
areolaSizeCurrent = areolaSizePermanent;
}
if (nippleSizePermanent < 0f)
{
nippleSizePermanent = Utility.RandGaussianLike(0f, parent.Severity);
originnipple = nippleSizePermanent;
nippleSize = nippleSizePermanent;
nippleSizeCurrent = nippleSizePermanent;
}
UpdateColor();
2021-06-16 12:53:52 +00:00
loaded = true;
2021-06-30 16:02:42 +00:00
HugsLibController.Instance.TickDelayScheduler.ScheduleCallback(action, TICKINTERVAL, parent.pawn);
}
2021-06-16 12:53:52 +00:00
public void Transition()
{
alphaCurrent = Mathf.Lerp(alphaCurrent, alpha, Configurations.NippleTransitionRatio);
areolaSizeCurrent = Mathf.Lerp(areolaSizeCurrent, areolaSize, Configurations.NippleTransitionRatio);
2021-06-11 14:16:09 +00:00
nippleSizeCurrent = Mathf.Lerp(nippleSizeCurrent, nippleSize, Configurations.NippleTransitionRatio);
UpdateColor();
2021-06-30 16:02:42 +00:00
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)
2021-06-30 16:02:42 +00:00
{
debugGrowthStatus = "Full size due to young child";
if (breastSizeIncreased < MAX_BREAST_INCREMENT)
2021-06-30 16:02:42 +00:00
{
parent.Severity += (MAX_BREAST_INCREMENT - breastSizeIncreased);
breastSizeIncreased = MAX_BREAST_INCREMENT;
2021-06-30 16:02:42 +00:00
}
}
// 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;
if (breastSizeIncreased > pregnancySize)
2021-06-30 16:02:42 +00:00
{
debugGrowthStatus = "Shrinking due to being oversize for pregnancy";
// Breasts still large from the last kid
ShrinkBreasts();
}
else if (breastSizeIncreased < MAX_BREAST_INCREMENT)
{
// Time to grow
float growAmount = pregnancySize - breastSizeIncreased;
if (growAmount != 0)
debugGrowthStatus = "Growing due to pregnancy";
else
debugGrowthStatus = "Pregnant, but not time to grow";
breastSizeIncreased += growAmount;
parent.Severity += growAmount;
2021-06-30 16:02:42 +00:00
}
else debugGrowthStatus = "Pregnant and full size";
2021-06-30 16:02:42 +00:00
}
// Scenario C: Not (or very early) pregnant and youngest child nonexistent or more than halfway into babyhood, time to shrink
else if (breastSizeIncreased > 0)
{
debugGrowthStatus = "Shrinking due to no pregnancy nor young child";
ShrinkBreasts();
}
else debugGrowthStatus = "Base size";
}
public void ChangeColorFermanant(float alpha)
{
alphaPermanent = alpha;
}
public void ChangeColor(float alpha)
{
this.alpha = alpha;
}
public void PregnancyTransition()
{
2021-06-30 16:02:42 +00:00
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;
}
public void BirthTransition()
{
alpha = alphaPermanent;
areolaSize = areolaSizePermanent;
nippleSize = nippleSizePermanent;
2021-06-30 16:02:42 +00:00
pregnant = false;
ageOfLastBirth = parent.pawn.ageTracker.AgeBiologicalTicks;
}
public void AdjustBreastSize(float amount)
{
parent.Severity += amount;
breastSizeIncreased += amount;
}
public void AdjustNippleSize(float amount)
{
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;
}
2021-07-10 14:51:56 +00:00
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()
{
2021-06-30 16:02:42 +00:00
cachedcolor = Colors.CMYKLerp(parent?.pawn?.story?.SkinColor ?? Color.white, Props.BlackNippleColor, Alpha);
}
public string DebugInfo()
{
return "Increase: " + 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;
}
}
}