From 045e9548f6fd0e79fe0657c1dc81867eabf5a141 Mon Sep 17 00:00:00 2001
From: lutepickle <28810-lutepickle@users.noreply.gitgud.io>
Date: Sat, 7 Jan 2023 20:18:17 -0800
Subject: [PATCH] Framework for pregenerated babies
---
1.4/Patches/Pregenerated_Babies.xml | 16 +
.../HediffComp_PregeneratedBabies.cs | 138 ++++++++
.../Hediff_MultiplePregnancy.cs | 291 +----------------
.../RJW_Menstruation/PregnancyCommon.cs | 300 ++++++++++++++++++
.../RJW_Menstruation/RJW_Menstruation.csproj | 2 +
.../RJW_Menstruation/UI/Dialog_WombStatus.cs | 4 +-
6 files changed, 462 insertions(+), 289 deletions(-)
create mode 100644 1.4/Patches/Pregenerated_Babies.xml
create mode 100644 1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
create mode 100644 1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
diff --git a/1.4/Patches/Pregenerated_Babies.xml b/1.4/Patches/Pregenerated_Babies.xml
new file mode 100644
index 0000000..07d05b3
--- /dev/null
+++ b/1.4/Patches/Pregenerated_Babies.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Biotech
+
+
+ /Defs/HediffDef[defName="PregnantHuman" or defName="PregnancyLabor" or defName="PregnancyLaborPushing"]/comps
+
+
+ RJW_Menstruation.HediffComp_PregeneratedBabies
+
+
+
+
+
\ No newline at end of file
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
new file mode 100644
index 0000000..ef0e8ad
--- /dev/null
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
@@ -0,0 +1,138 @@
+using RimWorld;
+using RimWorld.BaseGen;
+using rjw;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Verse;
+
+namespace RJW_Menstruation
+{
+ public class HediffComp_PregeneratedBabies : HediffComp
+ {
+ public List babies;
+ // Unused, but can't hurt to track
+ protected Dictionary enzygoticSiblings;
+
+ protected static readonly MethodInfo RandomLastName = typeof(PregnancyUtility).GetMethod("RandomLastName", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn), typeof(Pawn) }, null);
+
+ public bool HasBaby
+ {
+ get => !babies.NullOrEmpty();
+ }
+
+ public Pawn PopBaby()
+ {
+ if (babies.NullOrEmpty()) return null;
+
+ Pawn firstBaby = babies.First();
+ babies.Remove(firstBaby);
+ return firstBaby;
+ }
+
+ public override void CompPostPostRemoved()
+ {
+ // At this point in the hediff removal process, the new hediff is already on the pawn
+ // But it is possible that there is no new hediff (be it a birth, miscarrage, or dev edit)
+ base.CompPostPostRemoved();
+
+ switch (parent)
+ {
+ case Hediff_Pregnant hediff_Pregnant:
+ Hediff_Labor labor = (Hediff_Labor)Pawn.health.hediffSet.hediffs.Where(hediff => hediff is Hediff_Labor).MaxByWithFallback(hediff => hediff.loadID);
+ HediffComp_PregeneratedBabies laborcomp = labor?.TryGetComp();
+ if (laborcomp == null) return;
+ laborcomp.babies = this.babies;
+ laborcomp.enzygoticSiblings = this.enzygoticSiblings;
+ break;
+ case Hediff_Labor hediff_Labor:
+ Hediff_LaborPushing pushing = (Hediff_LaborPushing)Pawn.health.hediffSet.hediffs.Where(hediff => hediff is Hediff_LaborPushing).MaxByWithFallback(hediff => hediff.loadID);
+ HediffComp_PregeneratedBabies pushingcomp = pushing?.TryGetComp();
+ if (pushingcomp == null) return;
+ pushingcomp.babies = this.babies;
+ pushingcomp.enzygoticSiblings = this.enzygoticSiblings;
+ break;
+ case Hediff_LaborPushing hediff_LaborPushing:
+ // Nothing to do, the laborpushing transpiler will pick it up
+ break;
+ }
+ }
+
+ public override void CompExposeData()
+ {
+ base.CompExposeData();
+ Scribe_Collections.Look(ref babies, "babies", LookMode.Deep);
+ Scribe_Collections.Look(ref enzygoticSiblings, "enzygoticSiblings", keyLookMode: LookMode.Reference, valueLookMode: LookMode.Reference);
+ }
+
+
+ public void AddNewBaby(Pawn mother, Pawn father)
+ {
+ if (babies == null) babies = new List();
+ PawnKindDef babyPawnKind = PregnancyCommon.BabyPawnKindDecider(mother, father);
+ PawnGenerationRequest request = new PawnGenerationRequest
+ (
+ kind: babyPawnKind,
+ faction: mother.Faction,
+ allowDowned: true,
+ fixedLastName: (string)RandomLastName.Invoke(null, new object[] { mother, mother, xxx.is_human(father) ? father : null }),
+ forceNoIdeo: true,
+ // Kill on bad positivity in the post-birth
+ // forceDead: positivityIndex == -1
+ forcedEndogenes: PregnancyUtility.GetInheritedGenes(father, mother),
+ forcedXenotype: XenotypeDefOf.Baseliner,
+ developmentalStages: DevelopmentalStage.Newborn
+ );
+ int division = 1;
+ Pawn firstbaby = null;
+ while (Rand.Chance(Configurations.EnzygoticTwinsChance) && division < Configurations.MaxEnzygoticTwins) division++;
+ if (division > 1 && enzygoticSiblings == null) enzygoticSiblings = new Dictionary();
+ for (int i = 0; i < division; i++)
+ {
+ Pawn baby = PawnGenerator.GeneratePawn(request);
+ if (baby == null) break;
+ PregnancyCommon.SetupBabyXenotype(mother, father, baby);
+ if (division > 1)
+ {
+ if (i == 0)
+ {
+ if (baby.IsHAR())
+ baby.Drawer.renderer.graphics.ResolveAllGraphics();
+ firstbaby = baby;
+ request.FixedGender = baby.gender;
+ request.ForcedEndogenes = baby.genes?.Endogenes.Select(gene => gene.def).ToList();
+ }
+ else
+ {
+ enzygoticSiblings.Add(baby, firstbaby);
+
+ if (baby.story != null)
+ {
+ baby.story.headType = firstbaby.story.headType;
+ baby.story.hairDef = firstbaby.story.hairDef;
+ baby.story.bodyType = firstbaby.story.bodyType;
+ baby.story.furDef = firstbaby.story.furDef;
+ }
+
+ if (baby.genes != null && ModsConfig.BiotechActive)
+ {
+ baby.genes.SetXenotypeDirect(firstbaby.genes.Xenotype);
+ baby.genes.xenotypeName = firstbaby.genes.xenotypeName;
+ baby.genes.iconDef = firstbaby.genes.iconDef;
+ baby.genes.hybrid = firstbaby.genes.hybrid;
+ }
+
+ if (baby.IsHAR())
+ HARCompatibility.CopyHARProperties(baby, firstbaby);
+
+ // MultiplePregnancy calls this post-birth because RJW resets private parts
+ // So xenotype things shouldn't be shared
+ PregnancyCommon.ProcessIdenticalSibling(baby, firstbaby);
+ }
+ }
+ babies.Add(baby);
+ }
+ }
+ }
+}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
index 1af1ea2..67b4820 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
@@ -13,9 +13,6 @@ namespace RJW_Menstruation
{
protected Dictionary enzygoticSiblings = new Dictionary(); // Each pawn and who they split from
- protected static readonly MethodInfo TryGetInheritedXenotype = typeof(PregnancyUtility).GetMethod("TryGetInheritedXenotype", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn), typeof(XenotypeDef).MakeByRefType() }, null );
- protected static readonly MethodInfo ShouldByHybrid = typeof(PregnancyUtility).GetMethod("ShouldByHybrid", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn) }, null);
-
public override void DiscoverPregnancy()
{
PregnancyThought();
@@ -82,48 +79,6 @@ namespace RJW_Menstruation
breastcomp?.GaveBirth();
}
- public string GetBabyInfo()
- {
- if (babies.NullOrEmpty())
- return "Null";
-
- StringBuilder res = new StringBuilder();
-
- IEnumerable babiesdistinct = babies.Distinct(new RaceComparer());
- int iteration = 0;
- foreach (Pawn baby in babiesdistinct)
- {
- int num = babies.Where(x => x.def.Equals(baby.def)).Count();
- if (iteration > 0) res.Append(", ");
- res.AppendFormat("{0} {1}", num, baby.def.label);
- iteration++;
- }
- res.AppendFormat(" {0}", Translations.Dialog_WombInfo02);
- return res.ToString();
- }
-
- public string GetFatherInfo()
- {
- if (babies.NullOrEmpty())
- return "Null";
-
- StringBuilder res = new StringBuilder();
- res.AppendFormat("{0}: ", Translations.Dialog_WombInfo03);
-
- if (!is_parent_known && Configurations.InfoDetail != Configurations.DetailLevel.All)
- return res.Append(Translations.Dialog_FatherUnknown).ToString();
-
- IEnumerable babiesdistinct = babies.Distinct(new FatherComparer(pawn));
- int iteration = 0;
- foreach (Pawn baby in babiesdistinct)
- {
- if (iteration > 0) res.Append(", ");
- res.Append(Utility.GetFather(baby, pawn)?.LabelShort ?? Translations.Dialog_FatherUnknown);
- iteration++;
- }
- return res.ToString();
- }
-
private void HumanlikeBirth(Pawn baby)
{
Pawn mother = pawn; Pawn father = Utility.GetFather(baby, pawn);
@@ -212,65 +167,12 @@ namespace RJW_Menstruation
//baby.story.birthLastName = last_name;
}
- protected void CopyBodyPartProperties(Hediff part, Hediff originalPart)
- {
- CompHediffBodyPart comp = part.TryGetComp();
- CompHediffBodyPart originalComp = originalPart.TryGetComp();
-
- 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.GetMenstruationCompFromVagina();
- if (originalMenstruationComp != null)
- {
- part.GetMenstruationCompFromVagina()?.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_uddersBPR(baby), Genital_Helper.get_uddersBPR(original));
- CopyBodyPartRecord(baby, original, Genital_Helper.get_anusBPR(baby), Genital_Helper.get_anusBPR(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);
+ PregnancyCommon.ProcessIdenticalSibling(baby, original);
}
// From RJW's trait code
@@ -411,7 +313,7 @@ namespace RJW_Menstruation
allowAddictions: false,
relationWithExtraPawnChanceFactor: 0,
fixedLastName: lastname,
- kind: BabyPawnKindDecider(mother, father),
+ kind: PregnancyCommon.BabyPawnKindDecider(mother, father),
//fixedIdeo: mother.Ideo,
forbidAnyTitle: true,
forceNoBackstory: true,
@@ -428,25 +330,7 @@ namespace RJW_Menstruation
{
Pawn baby = GenerateBaby(request, mother, father, parentTraits, traitSeed);
if (baby == null) break;
- if (baby.genes != null && ModsConfig.BiotechActive)
- {
- if (GeneUtility.SameHeritableXenotype(mother, father) && mother.genes.UniqueXenotype)
- {
- baby.genes.xenotypeName = mother.genes.xenotypeName;
- baby.genes.iconDef = mother.genes.iconDef;
- }
-
- object[] args = new object[] { mother, father, null };
- if ((bool)TryGetInheritedXenotype.Invoke(null, args))
- {
- baby.genes.SetXenotypeDirect((XenotypeDef)args[2]);
- }
- else if((bool)ShouldByHybrid.Invoke(null, new object[] { mother, father }))
- {
- baby.genes.hybrid = true;
- baby.genes.xenotypeName = "Hybrid".Translate();
- }
- }
+ PregnancyCommon.SetupBabyXenotype(mother, father, baby);
if (division > 1)
{
if (i == 0)
@@ -466,6 +350,7 @@ namespace RJW_Menstruation
baby.story.headType = firstbaby.story.headType;
baby.story.hairDef = firstbaby.story.hairDef;
baby.story.bodyType = firstbaby.story.bodyType;
+ baby.story.furDef = firstbaby.story.furDef;
}
if (baby.genes != null && ModsConfig.BiotechActive)
@@ -519,174 +404,6 @@ namespace RJW_Menstruation
return baby;
}
- ///
- /// Decide pawnkind from mother and father
- /// Come from RJW
- ///
- ///
- ///
- ///
- public PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father)
- {
- PawnKindDef motherKindDef = Utility.GetRacesPawnKind(mother);
- PawnKindDef fatherKindDef = Utility.GetRacesPawnKind(father);
-
- PawnKindDef spawn_kind_def = motherKindDef;
-
- int flag = 0;
- if (xxx.is_human(mother)) flag += 2;
- if (xxx.is_human(father)) flag += 1;
- //Mother - Father = Flag
- //Human - Human = 3
- //Human - Animal = 2
- //Animal - Human = 1
- //Animal - Animal = 0
-
- switch (flag)
- {
- case 3:
- if (!Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- case 2:
- if (RJWPregnancySettings.bestiality_DNA_inheritance == 0f) spawn_kind_def = fatherKindDef;
- else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- case 1:
- if (RJWPregnancySettings.bestiality_DNA_inheritance == 1f) spawn_kind_def = fatherKindDef;
- else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- case 0:
- if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- }
-
- bool IsAndroidmother = AndroidsCompatibility.IsAndroid(mother);
- bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father);
- if (IsAndroidmother && !IsAndroidfather)
- {
- spawn_kind_def = fatherKindDef;
- }
- else if (!IsAndroidmother && IsAndroidfather)
- {
- spawn_kind_def = motherKindDef;
- }
-
- string MotherRaceName = "";
- string FatherRaceName = "";
- MotherRaceName = motherKindDef?.race?.defName;
- PawnKindDef non_hybrid_kind_def = spawn_kind_def;
- if (father != null)
- FatherRaceName = fatherKindDef?.race?.defName;
-
-
- if (FatherRaceName != "" && Configurations.UseHybridExtention)
- {
- spawn_kind_def = GetHybrid(father, mother);
- //Log.Message("pawnkind: " + spawn_kind_def?.defName);
- }
-
- if (MotherRaceName != FatherRaceName && FatherRaceName != "")
- {
- if (!Configurations.UseHybridExtention || spawn_kind_def == null)
- {
- spawn_kind_def = non_hybrid_kind_def;
- IEnumerable groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty()));
-
-
- //ModLog.Message(" found custom RaceGroupDefs " + groups.Count());
- foreach (RaceGroupDef t in groups)
- {
- if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName))
- || (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName))))
- {
- //ModLog.Message(" has hybridRaceParents");
- if (t.hybridChildKindDef.Contains("MotherKindDef"))
- spawn_kind_def = motherKindDef;
- else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null)
- spawn_kind_def = fatherKindDef;
- else
- {
- //ModLog.Message(" trying hybridChildKindDef " + t.defName);
- List child_kind_def_list = new List();
- child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName)));
-
- //ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count);
- if (!child_kind_def_list.NullOrEmpty())
- spawn_kind_def = child_kind_def_list.RandomElement();
- }
- }
- }
- }
-
- }
- else if (!Configurations.UseHybridExtention || spawn_kind_def == null)
- {
- spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? motherKindDef;
- }
-
- if (spawn_kind_def.defName.Contains("Nymph"))
- {
- //child is nymph, try to find other PawnKindDef
- List spawn_kind_def_list = new List();
- spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph")));
- //no other PawnKindDef found try mother
- if (spawn_kind_def_list.NullOrEmpty())
- spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == motherKindDef.race && !x.defName.Contains("Nymph")));
- //no other PawnKindDef found try father
- if (spawn_kind_def_list.NullOrEmpty() && father != null)
- spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == fatherKindDef.race && !x.defName.Contains("Nymph")));
- //no other PawnKindDef found fallback to generic colonist
- if (spawn_kind_def_list.NullOrEmpty())
- spawn_kind_def = PawnKindDefOf.Colonist;
-
- if (!spawn_kind_def_list.NullOrEmpty()) spawn_kind_def = spawn_kind_def_list.RandomElement();
- }
-
- return spawn_kind_def;
-
- }
-
- public PawnKindDef GetHybrid(Pawn first, Pawn second)
- {
- PawnKindDef res = null;
- Pawn opposite = second;
- HybridInformations info = null;
-
-
- if (!Configurations.HybridOverride.NullOrEmpty())
- {
- info = Configurations.HybridOverride.FirstOrDefault(x => x.DefName == first.def?.defName && (x.hybridExtension?.Exists(y => y.DefName == second.def?.defName) ?? false));
- if (info == null)
- {
- info = Configurations.HybridOverride.FirstOrDefault(x => x.DefName == second.def?.defName && (x.hybridExtension?.Exists(y => y.DefName == first.def?.defName) ?? false));
- opposite = first;
- }
- }
-
- if (info != null)
- {
- res = info.GetHybridWith(opposite.def.defName) ?? null;
- }
- if (res != null) return res;
-
-
- PawnDNAModExtension dna;
- dna = first.def.GetModExtension();
- if (dna != null)
- {
- res = dna.GetHybridWith(second.def.defName) ?? null;
- }
- else
- {
- dna = second.def.GetModExtension();
- if (dna != null)
- {
- res = dna.GetHybridWith(first.def.defName) ?? null;
- }
- }
- return res;
- }
-
///
/// Copy from RJW
///
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
new file mode 100644
index 0000000..b642947
--- /dev/null
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
@@ -0,0 +1,300 @@
+using RimWorld;
+using rjw;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Verse;
+
+namespace RJW_Menstruation
+{
+ public static class PregnancyCommon
+ {
+ private static readonly MethodInfo TryGetInheritedXenotype = typeof(PregnancyUtility).GetMethod("TryGetInheritedXenotype", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn), typeof(XenotypeDef).MakeByRefType() }, null);
+ private static readonly MethodInfo ShouldByHybrid = typeof(PregnancyUtility).GetMethod("ShouldByHybrid", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn) }, null);
+
+ public static string GetBabyInfo(IEnumerable babies)
+ {
+ if (babies == null || !babies.Any()) return "Null";
+
+ StringBuilder res = new StringBuilder();
+
+ IEnumerable babiesdistinct = babies.Distinct(new RaceComparer());
+ int iteration = 0;
+ foreach (Pawn baby in babiesdistinct)
+ {
+ int num = babies.Where(x => x.def.Equals(baby.def)).Count();
+ if (iteration > 0) res.Append(", ");
+ res.AppendFormat("{0} {1}", num, baby.def.label);
+ iteration++;
+ }
+ res.AppendFormat(" {0}", Translations.Dialog_WombInfo02);
+ return res.ToString();
+ }
+
+ public static string GetFatherInfo(IEnumerable babies, Pawn mother, bool is_parent_known)
+ {
+ if (babies == null || !babies.Any()) return "Null";
+
+ StringBuilder res = new StringBuilder();
+ res.AppendFormat("{0}: ", Translations.Dialog_WombInfo03);
+
+ if (!is_parent_known && Configurations.InfoDetail != Configurations.DetailLevel.All)
+ return res.Append(Translations.Dialog_FatherUnknown).ToString();
+
+ IEnumerable babiesdistinct = babies.Distinct(new FatherComparer(mother));
+ int iteration = 0;
+ foreach (Pawn baby in babiesdistinct)
+ {
+ if (iteration > 0) res.Append(", ");
+ res.Append(Utility.GetFather(baby, mother)?.LabelShort ?? Translations.Dialog_FatherUnknown);
+ iteration++;
+ }
+ return res.ToString();
+ }
+
+ ///
+ /// Decide pawnkind from mother and father
+ /// Come from RJW
+ ///
+ ///
+ ///
+ ///
+
+ public static PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father)
+ {
+ PawnKindDef motherKindDef = Utility.GetRacesPawnKind(mother);
+ PawnKindDef fatherKindDef = Utility.GetRacesPawnKind(father);
+
+ PawnKindDef spawn_kind_def = motherKindDef;
+
+ int flag = 0;
+ if (xxx.is_human(mother)) flag += 2;
+ if (xxx.is_human(father)) flag += 1;
+ //Mother - Father = Flag
+ //Human - Human = 3
+ //Human - Animal = 2
+ //Animal - Human = 1
+ //Animal - Animal = 0
+
+ switch (flag)
+ {
+ case 3:
+ if (!Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother)) spawn_kind_def = fatherKindDef;
+ break;
+ case 2:
+ if (RJWPregnancySettings.bestiality_DNA_inheritance == 0f) spawn_kind_def = fatherKindDef;
+ else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
+ break;
+ case 1:
+ if (RJWPregnancySettings.bestiality_DNA_inheritance == 1f) spawn_kind_def = fatherKindDef;
+ else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
+ break;
+ case 0:
+ if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
+ break;
+ }
+
+ bool IsAndroidmother = AndroidsCompatibility.IsAndroid(mother);
+ bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father);
+ if (IsAndroidmother && !IsAndroidfather)
+ {
+ spawn_kind_def = fatherKindDef;
+ }
+ else if (!IsAndroidmother && IsAndroidfather)
+ {
+ spawn_kind_def = motherKindDef;
+ }
+
+ string MotherRaceName = "";
+ string FatherRaceName = "";
+ MotherRaceName = motherKindDef?.race?.defName;
+ PawnKindDef non_hybrid_kind_def = spawn_kind_def;
+ if (father != null)
+ FatherRaceName = fatherKindDef?.race?.defName;
+
+
+ if (FatherRaceName != "" && Configurations.UseHybridExtention)
+ {
+ spawn_kind_def = GetHybrid(father, mother);
+ //Log.Message("pawnkind: " + spawn_kind_def?.defName);
+ }
+
+ if (MotherRaceName != FatherRaceName && FatherRaceName != "")
+ {
+ if (!Configurations.UseHybridExtention || spawn_kind_def == null)
+ {
+ spawn_kind_def = non_hybrid_kind_def;
+ IEnumerable groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty()));
+
+
+ //ModLog.Message(" found custom RaceGroupDefs " + groups.Count());
+ foreach (RaceGroupDef t in groups)
+ {
+ if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName))
+ || (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName))))
+ {
+ //ModLog.Message(" has hybridRaceParents");
+ if (t.hybridChildKindDef.Contains("MotherKindDef"))
+ spawn_kind_def = motherKindDef;
+ else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null)
+ spawn_kind_def = fatherKindDef;
+ else
+ {
+ //ModLog.Message(" trying hybridChildKindDef " + t.defName);
+ List child_kind_def_list = new List();
+ child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName)));
+
+ //ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count);
+ if (!child_kind_def_list.NullOrEmpty())
+ spawn_kind_def = child_kind_def_list.RandomElement();
+ }
+ }
+ }
+ }
+
+ }
+ else if (!Configurations.UseHybridExtention || spawn_kind_def == null)
+ {
+ spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? motherKindDef;
+ }
+
+ if (spawn_kind_def.defName.Contains("Nymph"))
+ {
+ //child is nymph, try to find other PawnKindDef
+ List spawn_kind_def_list = new List();
+ spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph")));
+ //no other PawnKindDef found try mother
+ if (spawn_kind_def_list.NullOrEmpty())
+ spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == motherKindDef.race && !x.defName.Contains("Nymph")));
+ //no other PawnKindDef found try father
+ if (spawn_kind_def_list.NullOrEmpty() && father != null)
+ spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == fatherKindDef.race && !x.defName.Contains("Nymph")));
+ //no other PawnKindDef found fallback to generic colonist
+ if (spawn_kind_def_list.NullOrEmpty())
+ spawn_kind_def = PawnKindDefOf.Colonist;
+
+ if (!spawn_kind_def_list.NullOrEmpty()) spawn_kind_def = spawn_kind_def_list.RandomElement();
+ }
+
+ return spawn_kind_def;
+
+ }
+
+ public static void SetupBabyXenotype(Pawn mother, Pawn father, Pawn baby)
+ {
+ if (baby.genes == null || !ModsConfig.BiotechActive) return;
+
+ if (GeneUtility.SameHeritableXenotype(mother, father) && mother.genes.UniqueXenotype)
+ {
+ baby.genes.xenotypeName = mother.genes.xenotypeName;
+ baby.genes.iconDef = mother.genes.iconDef;
+ }
+
+ object[] args = new object[] { mother, father, null };
+ if ((bool)TryGetInheritedXenotype.Invoke(null, args))
+ {
+ baby.genes.SetXenotypeDirect((XenotypeDef)args[2]);
+ }
+ else if ((bool)ShouldByHybrid.Invoke(null, new object[] { mother, father }))
+ {
+ baby.genes.hybrid = true;
+ baby.genes.xenotypeName = "Hybrid".Translate();
+ }
+ }
+
+ public static PawnKindDef GetHybrid(Pawn first, Pawn second)
+ {
+ PawnKindDef res = null;
+ Pawn opposite = second;
+ HybridInformations info = null;
+
+
+ if (!Configurations.HybridOverride.NullOrEmpty())
+ {
+ info = Configurations.HybridOverride.FirstOrDefault(x => x.DefName == first.def?.defName && (x.hybridExtension?.Exists(y => y.DefName == second.def?.defName) ?? false));
+ if (info == null)
+ {
+ info = Configurations.HybridOverride.FirstOrDefault(x => x.DefName == second.def?.defName && (x.hybridExtension?.Exists(y => y.DefName == first.def?.defName) ?? false));
+ opposite = first;
+ }
+ }
+
+ if (info != null)
+ {
+ res = info.GetHybridWith(opposite.def.defName) ?? null;
+ }
+ if (res != null) return res;
+
+
+ PawnDNAModExtension dna;
+ dna = first.def.GetModExtension();
+ if (dna != null)
+ {
+ res = dna.GetHybridWith(second.def.defName) ?? null;
+ }
+ else
+ {
+ dna = second.def.GetModExtension();
+ if (dna != null)
+ {
+ res = dna.GetHybridWith(first.def.defName) ?? null;
+ }
+ }
+ return res;
+ }
+
+ private static void CopyBodyPartProperties(Hediff part, Hediff originalPart)
+ {
+ CompHediffBodyPart comp = part.TryGetComp();
+ CompHediffBodyPart originalComp = originalPart.TryGetComp();
+
+ 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.GetMenstruationCompFromVagina();
+ if (originalMenstruationComp != null)
+ {
+ part.GetMenstruationCompFromVagina()?.CopyCycleProperties(originalMenstruationComp);
+ }
+ HediffComp_Breast originalBreastComp = originalPart.GetBreastComp();
+ if (originalBreastComp != null)
+ {
+ part.GetBreastComp()?.CopyBreastProperties(originalBreastComp);
+ }
+ }
+
+ private static void CopyBodyPartRecord(Pawn baby, Pawn original, BodyPartRecord babyBPR, BodyPartRecord originalBPR)
+ {
+ if (babyBPR == null || originalBPR == null) return;
+
+ Hediff_BasePregnancy.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 static 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_uddersBPR(baby), Genital_Helper.get_uddersBPR(original));
+ CopyBodyPartRecord(baby, original, Genital_Helper.get_anusBPR(baby), Genital_Helper.get_anusBPR(original));
+ }
+ }
+}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj b/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
index 1a35c67..0266ab8 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
@@ -69,12 +69,14 @@
+
+
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs
index 8a8e380..36e026b 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs
@@ -172,8 +172,8 @@ namespace RJW_Menstruation
Pawn fetus = comp.GetFetus();
if (fetus != null && Utility.ShowFetusInfo())
{
- string feinfo = m.GetBabyInfo();
- string fainfo = m.GetFatherInfo() + " ";
+ string feinfo = PregnancyCommon.GetBabyInfo(m.babies);
+ string fainfo = PregnancyCommon.GetFatherInfo(m.babies, m.pawn, m.is_parent_known) + " ";
if (feinfo.Length + fainfo.Length > 45)
{
preginfoheight = fontheight + 2;