using RimWorld; using System; using System.Collections.Generic; using System.Text; using UnityEngine; using Verse; namespace RJW_Menstruation { public class Cum : IExposable { public Pawn pawn; protected float volume; // ml public float fertility = 1.0f; public bool notcum = false; // for other fluids public string notcumLabel = ""; protected bool useCustomColor = false; protected float notcumthickness = 0; protected float cumthickness = 1.0f; protected Thing internalThing; public float Volume { get { return volume; } } public float FertVolume { get { return volume * fertility; } } public float CumThickness { get { return cumthickness; } } public float DecayResist { get { if (!notcum) return DNA.cumThickness; else return notcumthickness; } set { notcumthickness = value; } } protected Color customColor; public PawnDNAModExtension DNA { get { if (DNAcache != null) return DNAcache; try { DNAcache = pawn.def.GetModExtension(); } catch (NullReferenceException) { DNAcache = ThingDefOf.Human.GetModExtension(); } if (DNAcache == null) { DNAcache = ThingDefOf.Human.GetModExtension(); } return DNAcache; } } protected PawnDNAModExtension DNAcache = null; public ThingDef FilthDef { get { if (filthDef == null) return VariousDefOf.CumFilth; else return filthDef; } set { filthDef = value; } } protected ThingDef filthDef = null; public Color Color { get { if (!useCustomColor) return DNA.CumColor; else return customColor; } set { useCustomColor = true; customColor = value; } } public Thing CumThing { get { if (internalThing == null) { internalThing = ThingMaker.MakeThing(VariousDefOf.CumFilth); internalThing.stackCount = (int)volume; } internalThing.stackCount = (int)volume; return internalThing; } } public Cum() { } public Cum(Pawn pawn) { this.pawn = pawn; volume = 1.0f; fertility = 1.0f; } /// /// Not Cum /// /// /// /// /// /// public Cum(Pawn pawn, float volume, string notcumlabel, float decayresist = 0, ThingDef filthDef = null) { this.pawn = pawn; this.volume = volume; this.fertility = 0f; this.notcum = true; this.notcumLabel = notcumlabel; this.notcumthickness = decayresist; this.filthDef = filthDef; } public Cum(Pawn pawn, float volume, float fertility, ThingDef filthDef = null) { this.pawn = pawn; this.volume = volume; this.fertility = fertility; this.filthDef = filthDef; } public virtual void ExposeData() { Scribe_References.Look(ref pawn, "pawn", true); Scribe_Values.Look(ref volume, "volume", volume, true); Scribe_Values.Look(ref fertility, "fertility", fertility, true); Scribe_Values.Look(ref notcumthickness, "notcumthickness", 0); Scribe_Values.Look(ref notcum, "notcum", false); Scribe_Values.Look(ref notcumLabel, "notcumLabel", ""); Scribe_Values.Look(ref useCustomColor, "useCustomColor", false); Scribe_Values.Look(ref customColor, "customColor", default); Scribe_Defs.Look(ref filthDef, "filthDef"); } public void MakeThinner(float speed) { cumthickness = cumthickness.LerpMultiple(DecayResist, 0.3f, speed); } public void MergeWithCum(float volumein, float fertility, ThingDef updatefilthDef = null) { if (updatefilthDef != null) filthDef = updatefilthDef; volume += volumein; this.fertility = (this.volume * this.fertility + volumein * fertility) / (this.volume + volumein); cumthickness = Mathf.Lerp(cumthickness, 1.0f, volumein / volume); } public void MergeWithFluid(float volumein, float thickness, ThingDef updatefilthDef = null) { if (updatefilthDef != null) filthDef = updatefilthDef; volume += volumein; fertility = volume * fertility / (volume + volumein); notcumthickness = Mathf.Lerp(notcumthickness, thickness, volumein / volume); } public bool ShouldRemove() { if ((notcum || FertVolume < 0.001f) && volume < 0.01f) return true; return false; } public float DismishNatural(float leakfactor, HediffComp_Menstruation comp, float antisperm = 0.0f) { // comp is used for Hydrogen's RJW Muscle Injury float totalleak = volume; float decayPerInterval = 1 - Mathf.Pow(1 - Configurations.CumDecayRatio, comp.HoursBetweenSimulations); float fertilityDecayPerInterval = 1 - Mathf.Pow(1 - Configurations.CumFertilityDecayRatio, comp.HoursBetweenSimulations); antisperm *= comp.HoursBetweenSimulations; volume *= Math.Max(0, 1 - decayPerInterval * (1 - DecayResist) * leakfactor); fertility *= Math.Max(0, 1 - (fertilityDecayPerInterval * (1 - DecayResist) + antisperm)); CutMinor(); totalleak -= volume; return totalleak; } public float DismishForce(float portion, float leakfactor = 1.0f) { float totalleak = volume; volume *= Math.Max(0, 1 - (portion * (1 - DecayResist / 10)) * leakfactor); CutMinor(); totalleak -= volume; return totalleak; } public void CumEffects(Pawn pawn) { if (notcum || DNA?.ingestionOutcomeDoers == null || volume < 1.0f) return; foreach (IngestionOutcomeDoer doer in DNA.ingestionOutcomeDoers) doer.DoIngestionOutcome(pawn, CumThing); } protected void CutMinor() { if (volume < 0.01f) volume = 0f; } } public class CumMixture : Cum { protected List cums; public bool ispurecum = true; public List Getingredients => cums; public CumMixture() { notcum = true; cums = new List(); } public CumMixture(Pawn pawn, float volume, List cums, Color color, ThingDef mixtureDef, bool pure) { this.pawn = pawn; this.volume = volume; this.cums = cums; this.customColor = color; this.useCustomColor = true; ispurecum = pure; } public override void ExposeData() { base.ExposeData(); Scribe_Collections.Look(ref cums, "cumslabel", LookMode.Value, new object[0]); } public string GetIngredients() { StringBuilder res = new StringBuilder(); if (!cums.NullOrEmpty()) for (int i = 0; i < cums.Count; i++) { res.Append(cums[i]); if (i < cums.Count - 1) res.Append(", "); } return res.ToString(); } } }