rjw_menstruation/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs

462 lines
19 KiB
C#

using RimWorld;
using rjw;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace RJW_Menstruation
{
public static class Colors
{
public static Color blood = new Color(0.78f, 0, 0);
//public static Color nippleblack = new Color(0.215f, 0.078f, 0); // 81,20,0
public static ColorInt white = new ColorInt(255, 255, 255, 255);
public static Color CMYKLerp(Color a, Color b, float t)
{
RGBtoCMYK(a, out float ac, out float am, out float ay, out float ak);
RGBtoCMYK(b, out float bc, out float bm, out float by, out float bk);
return CMYKtoRGB(Mathf.Lerp(ac, bc, t), Mathf.Lerp(am, bm, t), Mathf.Lerp(ay, by, t), Mathf.Lerp(ak, bk, t));
}
public static void RGBtoCMYK(Color rgb, out float c, out float m, out float y, out float k)
{
k = 1 - Math.Max(rgb.r, Math.Max(rgb.g, rgb.b));
c = (1 - rgb.r - k) / (1 - k);
m = (1 - rgb.g - k) / (1 - k);
y = (1 - rgb.b - k) / (1 - k);
}
public static Color CMYKtoRGB(float c, float m, float y, float k)
{
return new Color((1 - c) * (1 - k), (1 - m) * (1 - k), (1 - y) * (1 - k));
}
}
public static class Utility
{
public static PawnKindDef GetRacesPawnKind(Pawn pawn)
{
if (pawn == null) return null;
if (pawn.kindDef?.race == pawn.def) return pawn.kindDef;
return VariousDefOf.AllKinds.Find(kind => kind.race == pawn.def && kind.defName.Contains("Colonist")) ??
VariousDefOf.AllKinds.Find(kind => kind.race == pawn.def) ??
pawn.RaceProps?.AnyPawnKind ??
pawn.kindDef;
}
public static float GetCumVolume(this Pawn pawn)
{
List<Hediff> hediffs = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn));
if (hediffs.NullOrEmpty()) return 0;
else return pawn.GetCumVolume(hediffs);
}
public static float GetCumVolume(this Pawn pawn, List<Hediff> hediffs)
{
CompHediffBodyPart part = (((hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("penis")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>()) ??
(hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorf")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>())) ??
(hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorm")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>())) ??
(hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("tentacle")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>());
return pawn.GetCumVolume(part);
}
public static float GetCumVolume(this Pawn pawn, CompHediffBodyPart part)
{
float res;
try
{
res = VariationRange(part.FluidAmmount * part.FluidModifier * pawn.BodySize / pawn.RaceProps.baseBodySize, 0.2f);
}
catch (NullReferenceException)
{
res = 0.0f;
}
if (pawn.IsMessy()) res *= Rand.Range(4.0f, 8.0f);
return res;
}
public static HediffComp_Breast GetBreastComp(this Pawn pawn)
{
return pawn.health.hediffSet.hediffs.FirstOrDefault((Hediff h) => VariousDefOf.AllBreasts.Contains(h.def))?.TryGetComp<HediffComp_Breast>();
}
public static HediffComp_Breast GetBreastComp(this Hediff hediff)
{
if (hediff is Hediff_PartBaseNatural)
{
return hediff.TryGetComp<HediffComp_Breast>();
}
return null;
}
public static List<ThingComp> GetMilkComps(this Pawn pawn)
{
List<ThingComp> milkcomp = pawn.AllComps.FindAll(x => x is CompMilkable || x.GetType().ToString().ToLower().Contains("milkable"));
return milkcomp;
}
public static bool HasMenstruationComp(this Pawn pawn)
{
return pawn.GetMenstruationComps().Any();
}
public static bool HasMenstruationComp(this Hediff hediff)
{
if ((hediff is Hediff_PartBaseNatural || hediff is Hediff_PartBaseArtifical) && hediff.TryGetComp<HediffComp_Menstruation>() != null)
return true;
else return false;
}
public static bool IsRJWPregnant(this Pawn pawn)
{
return pawn.health.hediffSet.GetFirstHediff<Hediff_BasePregnancy>() != null;
}
public static bool IsBiotechPregnant(this Pawn pawn)
{
if (!ModsConfig.BiotechActive) return false;
foreach (HediffDef def in pawn.health.hediffSet.hediffs.Select(hediff => hediff.def))
{
if (def == HediffDefOf.PregnantHuman || def == HediffDefOf.PregnancyLabor || def == HediffDefOf.PregnancyLaborPushing)
return true;
}
return false;
}
public static float GetFarthestPregnancyProgress(this Pawn pawn)
{
if (ModsConfig.BiotechActive)
{
foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
{
if (hediff.def == HediffDefOf.PregnancyLabor || hediff.def == HediffDefOf.PregnancyLaborPushing)
return 1.0f;
if (hediff.def == HediffDefOf.PregnantHuman)
return hediff.Severity;
}
}
List<Hediff_BasePregnancy> pregnancies = new List<Hediff_BasePregnancy>();
pawn.health.hediffSet.GetHediffs(ref pregnancies);
return pregnancies.MaxByWithFallback(hediff => hediff.GestationProgress)?.GestationProgress ?? 0;
}
public static float GetPregnancyProgress(this HediffComp_Menstruation comp)
{
if (comp.Pregnancy == null) return 0;
else return comp.StageProgress;
}
public static Pawn GetFetus(this HediffComp_Menstruation comp)
{
if (comp.Pregnancy == null) return null;
if (comp.Pregnancy is Hediff_BasePregnancy rjw_preg)
{
if (!rjw_preg.babies.NullOrEmpty()) return rjw_preg.babies.First();
else
{
Log.Error("Baby not exist: baby was not created or removed. Remove pregnancy.");
rjw_preg.Miscarry();
return null;
}
}
HediffComp_PregeneratedBabies babiescomp = comp.Pregnancy.TryGetComp<HediffComp_PregeneratedBabies>();
return babiescomp?.babies?.FirstOrDefault();
}
public static void DrawBreastIcon(this Pawn pawn, Rect rect)
{
Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def));
Texture2D breast, nipple, areola;
if (hediff != null)
{
HediffComp_Breast comp = hediff.TryGetComp<HediffComp_Breast>();
string icon;
if (comp != null) icon = comp.Props?.BreastTex ?? "Breasts/Breast_Breast";
else
{
breast = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00", false);
nipple = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Nipple00", false);
areola = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Areola00", false);
GUI.color = SafeSkinColor(pawn);
GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
GUI.color = Color.white;
GUI.DrawTexture(rect, areola, ScaleMode.ScaleToFit);
GUI.DrawTexture(rect, nipple, ScaleMode.ScaleToFit);
return;
}
if (hediff.Severity < 0.20f) icon += "_Breast00";
else if (hediff.Severity < 0.40f) icon += "_Breast01";
else if (hediff.Severity < 0.60f) icon += "_Breast02";
else if (hediff.Severity < 0.80f) icon += "_Breast03";
else if (hediff.Severity < 1.00f) icon += "_Breast04";
else icon += "_Breast05";
string nippleicon, areolaicon;
float nipplesize, areolasize;
nipplesize = comp.NippleSize;
areolasize = comp.AreolaSize;
nippleicon = icon + "_Nipple0" + GetNippleIndex(nipplesize);
areolaicon = icon + "_Areola0" + GetAreolaIndex(areolasize);
breast = ContentFinder<Texture2D>.Get(icon, false);
areola = ContentFinder<Texture2D>.Get(areolaicon, false);
nipple = ContentFinder<Texture2D>.Get(nippleicon, false);
GUI.color = SafeSkinColor(pawn);
GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
GUI.color = comp.NippleColor;
GUI.DrawTexture(rect, areola, ScaleMode.ScaleToFit);
GUI.DrawTexture(rect, nipple, ScaleMode.ScaleToFit);
if (Configurations.Debug) TooltipHandler.TipRegion(rect, comp.DebugInfo());
}
else
{
breast = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00", false);
nipple = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Nipple00", false);
areola = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Areola00", false);
GUI.color = SafeSkinColor(pawn);
GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
GUI.color = Color.white;
GUI.DrawTexture(rect, areola, ScaleMode.ScaleToFit);
GUI.DrawTexture(rect, nipple, ScaleMode.ScaleToFit);
}
}
public static int GetNippleIndex(float nipplesize)
{
if (nipplesize < 0.25f) return 0;
else if (nipplesize < 0.50f) return 1;
else if (nipplesize < 0.75f) return 2;
else return 3;
}
public static int GetAreolaIndex(float nipplesize)
{
if (nipplesize < 0.15f) return 0;
else if (nipplesize < 0.30f) return 1;
else if (nipplesize < 0.45f) return 2;
else if (nipplesize < 0.70f) return 3;
else return 4;
}
public static void DrawMilkBars(this Pawn pawn, Rect rect)
{
//List<ThingComp> milkcomp = pawn.AllComps.FindAll(x => x is CompMilkable || x.GetType().ToString().ToLower().Contains("milkable"));
ThingComp milkcomp = null;
float res = 0;
if (VariousDefOf.Hediff_Heavy_Lactating_Permanent != null)
{
if (pawn.health.hediffSet.HasHediff(VariousDefOf.Hediff_Heavy_Lactating_Permanent)) milkcomp = pawn.AllComps.FirstOrDefault(x => x.GetType().ToString().ToLower().Contains("hypermilkable"));
else milkcomp = pawn.AllComps.FirstOrDefault(x => x.GetType().ToString().ToLower().Contains("milkable"));
}
else
{
milkcomp = pawn.GetComp<CompMilkable>();
}
if (milkcomp == null) return;
if (milkcomp is CompMilkable milkable)
{
bool active = (bool)milkcomp.GetPropertyValue("Active");
if (active)
{
CompMilkable m = milkable;
res = Math.Max(m.Fullness, res);
Widgets.FillableBar(rect, Math.Min(res, 1.0f), TextureCache.MilkTexture, Texture2D.blackTexture, true);
DrawMilkBottle(rect, pawn, VariousDefOf.Job_LactateSelf, m.Fullness);
}
}
else
{
bool active = (bool)milkcomp.GetPropertyValue("Active");
if (active)
{
float fullness = (float)milkcomp.GetMemberValue("fullness");
res = Math.Max(fullness, res);
Widgets.FillableBar(rect, Math.Min(res, 1.0f), TextureCache.MilkTexture, Texture2D.blackTexture, true);
DrawMilkBottle(rect, pawn, VariousDefOf.Job_LactateSelf_MC, fullness);
}
}
}
public static void DrawMilkBottle(Rect rect, Pawn pawn, JobDef milkjob, float fullness)
{
Texture2D texture;
Rect buttonrect = new Rect(rect.x, rect.y, rect.height, rect.height);
if (fullness <= 0.0f) return;
if (fullness < 0.3f) texture = ContentFinder<Texture2D>.Get("Milk/Milkbottle_Small", false);
else if (fullness < 0.7f) texture = ContentFinder<Texture2D>.Get("Milk/Milkbottle_Medium", false);
else texture = ContentFinder<Texture2D>.Get("Milk/Milkbottle_Large", false);
GUIContent icon = new GUIContent(texture);
GUIStyle style = GUIStyle.none;
style.normal.background = texture;
string tooltip = Translations.Button_MilkTooltip;
TooltipHandler.TipRegion(buttonrect, tooltip);
if (GUI.Button(buttonrect, icon, style))
{
if (fullness < 0.1f
|| !pawn.IsColonistPlayerControlled
|| pawn.Downed) SoundDefOf.ClickReject.PlayOneShotOnCamera();
else
{
SoundDefOf.Click.PlayOneShotOnCamera();
pawn.jobs.TryTakeOrderedJob(new Verse.AI.Job(milkjob, pawn));
}
}
Widgets.DrawHighlightIfMouseover(buttonrect);
}
public static string GetVaginaLabel(this Pawn pawn)
{
Hediff hediff = pawn.health.hediffSet.hediffs.Find(h => VariousDefOf.AllVaginas.Contains(h.def));
return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")" + "\n" + xxx.CountOfSex.LabelCap.CapitalizeFirst() + ": " + pawn.records.GetAsInt(xxx.CountOfSex);
}
public static string GetAnusLabel(this Pawn pawn)
{
Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ??
Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault(h => h.def.defName.ToLower().Contains("anus"));
if (hediff != null) return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")";
else return "";
}
public static string GetBreastLabel(this Pawn pawn)
{
Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def));
if (hediff != null) return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")";
else return "";
}
public static bool ShowFetusImage(this Hediff hediff)
{
if (Configurations.InfoDetail == Configurations.DetailLevel.All) return true;
else if (Configurations.InfoDetail == Configurations.DetailLevel.Hide) return false;
else if (hediff.Visible) return true;
else return false;
}
public static bool ShowFetusInfo()
{
if (Configurations.InfoDetail == Configurations.DetailLevel.All || Configurations.InfoDetail == Configurations.DetailLevel.OnReveal) return true;
else return false;
}
public static bool ShowStatus(this Pawn pawn)
{
if (pawn.Faction != null && Configurations.ShowFlag != Configurations.PawnFlags.None)
{
if (pawn.Faction.IsPlayer)
{
if ((Configurations.ShowFlag & Configurations.PawnFlags.Colonist) != 0) return true;
}
else if (pawn.IsPrisonerOfColony)
{
if ((Configurations.ShowFlag & Configurations.PawnFlags.Prisoner) != 0) return true;
}
else if (pawn.Faction.PlayerRelationKind == FactionRelationKind.Ally)
{
if ((Configurations.ShowFlag & Configurations.PawnFlags.Ally) != 0) return true;
}
else if (pawn.Faction.PlayerRelationKind == FactionRelationKind.Hostile)
{
if ((Configurations.ShowFlag & Configurations.PawnFlags.Hostile) != 0) return true;
}
else if ((Configurations.ShowFlag & Configurations.PawnFlags.Neutral) != 0) return true;
else return false;
}
else if ((Configurations.ShowFlag & Configurations.PawnFlags.Neutral) != 0) return true;
return false;
}
public static Pawn GetFather(Pawn pawn, Pawn mother)
{
Pawn res = pawn.GetFather();
if (res != null) return res;
else res = pawn.relations?.GetFirstDirectRelationPawn(PawnRelationDefOf.Parent, x => x != mother);
return res;
}
public static float RandGaussianLike(float min, float max, int iterations = 3)
{
float res = 0;
for (int i = 0; i < iterations; i++)
{
res += Rand.Value;
}
res /= iterations;
return res * (max - min) + min;
}
public static float LerpMultiple(this float a, float b, float t, float num)
{
float tmult = Mathf.Pow(1 - t, num);
return tmult * a + (1 - tmult) * b;
}
public static float VariationRange(this float num, float variant)
{
return num * Rand.Range(1.0f - variant, 1.0f + variant);
}
public static bool ShouldShowWombGizmo(this Pawn pawn)
{
if (!Configurations.EnableWombIcon) return false;
if (pawn.Drafted && !Configurations.EnableDraftedIcon) return false;
if (!pawn.ShouldCycle()) return false;
return true;
}
// Apparently with some mods, even doing pawn.story?.SkinColor can throw a null reference, so we're stuck doing this
public static Color SafeSkinColor(Pawn pawn)
{
try
{
return pawn.story?.SkinColor ?? Color.white;
}
catch (NullReferenceException)
{
return Color.white;
}
catch (InvalidOperationException) // And sometimes it can try to pull the value of a Nullable without checking, too
{
return Color.white;
}
}
}
}