rjw_menstruation/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs

321 lines
15 KiB
C#

using RimWorld;
using rjw;
using System;
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<Pawn> babies)
{
if (babies == null || !babies.Any()) return "Null";
StringBuilder res = new StringBuilder();
int iteration = 0;
foreach (Pawn baby in babies.Distinct(new RaceComparer()))
{
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<Pawn> 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();
int iteration = 0;
foreach (Pawn baby in babies.Distinct(new FatherComparer(mother)))
{
if (iteration > 0) res.Append(", ");
res.Append(Utility.GetFather(baby, mother)?.LabelShort ?? Translations.Dialog_FatherUnknown);
iteration++;
}
return res.ToString();
}
/// <summary>
/// Decide pawnkind from mother and father <para/>
/// Come from RJW
/// </summary>
/// <param name="mother"></param>
/// <param name="father"></param>
/// <returns></returns>
/// <param name="noAnimalsFromHumanlikes"></param>
public static PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father, bool noAnimalsFromHumanlikes)
{
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<RaceGroupDef> groups = DefDatabase<RaceGroupDef>.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<PawnKindDef> child_kind_def_list = new List<PawnKindDef>();
child_kind_def_list.AddRange(DefDatabase<PawnKindDef>.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<PawnKindDef> spawn_kind_def_list = new List<PawnKindDef>();
spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.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<PawnKindDef>.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<PawnKindDef>.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();
}
// If both parents are humanlike, Biotech will attempt to assign genes to the child
// Normally not a problem, but with the hybrid system, two humanlikes might produce an animal
// So override it and force the child to be human
if (noAnimalsFromHumanlikes && mother.genes != null && father?.genes != null && !spawn_kind_def.race.race.Humanlike)
spawn_kind_def = Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother) ? motherKindDef : fatherKindDef;
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<PawnDNAModExtension>();
if (dna != null)
{
res = dna.GetHybridWith(second.def.defName) ?? null;
}
else
{
dna = second.def.GetModExtension<PawnDNAModExtension>();
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>();
CompHediffBodyPart originalComp = originalPart.TryGetComp<CompHediffBodyPart>();
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));
}
public static string DueDate(this Hediff_BasePregnancy preg)
{
if (preg.pawn.Tile == -1) return "";
return GenDate.DateFullStringWithHourAt(GenDate.TickGameToAbs((int)preg.p_end_tick), Find.WorldGrid.LongLatOf(preg.pawn.Tile));
}
public static string DueDate(this Hediff_Pregnant preg)
{
if (preg.pawn.Tile == -1) return "";
int ticksRemaining = (int)((1f - preg.GestationProgress) * preg.pawn.RaceProps.gestationPeriodDays * GenDate.TicksPerDay);
int dueTickAbs = GenTicks.TicksAbs + ticksRemaining;
return GenDate.DateFullStringWithHourAt(dueTickAbs, Find.WorldGrid.LongLatOf(preg.pawn.Tile));
}
}
}