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;