diff --git a/About/Manifest.xml b/About/Manifest.xml index 1a077cf..b0be86c 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,7 +1,7 @@ RJW Menstruation - 1.0.0.8 + 1.0.1.0 diff --git a/Assemblies/RJW_Menstruation.dll b/Assemblies/RJW_Menstruation.dll index ebe0c66..d4ee69a 100644 Binary files a/Assemblies/RJW_Menstruation.dll and b/Assemblies/RJW_Menstruation.dll differ diff --git a/Languages/English/Keyed/RJW_Menstruation.xml b/Languages/English/Keyed/RJW_Menstruation.xml index 6c1bb91..52c29f9 100644 --- a/Languages/English/Keyed/RJW_Menstruation.xml +++ b/Languages/English/Keyed/RJW_Menstruation.xml @@ -50,7 +50,15 @@ Do not show fetus image and informations enable menopause enable menopause effect that makes pawn infertile in time progress if you have problems with long life races, turn off this option. this option will apply after save loaded - - + use multiple pregnancy + use multiple pregnancy instead RJW's default pregnancy + enable hetero ovular twins + enable multiple eggs can get pregnant + enable enzygotic twins + enable single egg to result multiple offsprings + enzygotic twins chance + set chance of twins + max enzygotic twins + set max number of twins \ No newline at end of file diff --git a/Languages/Korean/Keyed/RJW_Menstruation.xml b/Languages/Korean/Keyed/RJW_Menstruation.xml index b136765..19a655a 100644 --- a/Languages/Korean/Keyed/RJW_Menstruation.xml +++ b/Languages/Korean/Keyed/RJW_Menstruation.xml @@ -50,8 +50,16 @@ 태아에 대한 어떠한 정보도 표시하지 않습니다. 폐경기 활성화 시간이 지남에따라 불임상태로 만드는 폐경기를 활성화합니다. 수명이 긴 종족을 사용할때 문제가 있으면 이 옵션을 끄세요. 변경한후에 세이브로드가 필요합니다. - - + 다중임신 + RJW의 기본임신 대신 다중임신을 사용합니다. + 이란성 쌍둥이 활성화 + 다수의 난자가 임신으로 이어지게 합니다. + 일란성 쌍둥이 활성화 + 하나의 난자가 다수의 태아로 나뉘게 합니다. + 일란성 쌍둥이 확률 + 일란성 쌍둥이가 발생할 확률을 설정합니다. + 최대 일란성 쌍둥이 수 + 일란성 쌍둥이의 수를 제한합니다. \ No newline at end of file diff --git a/Patches/Hediffs.xml b/Patches/Hediffs.xml deleted file mode 100644 index cbef992..0000000 --- a/Patches/Hediffs.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Defs/HediffDef[defName="RJW_IUD"]/stages - - -
  • - -
  • - RJW_Fertility - 1.0 -
  • - - -
    -
    -
    -
    \ No newline at end of file diff --git a/Patches/Hediffs_PrivateParts.xml b/Patches/Hediffs_PrivateParts.xml index 6860f64..7c0595c 100644 --- a/Patches/Hediffs_PrivateParts.xml +++ b/Patches/Hediffs_PrivateParts.xml @@ -12,7 +12,7 @@
  • - 500 + 15 1.0 1.0 0.05 @@ -34,7 +34,7 @@
  • - 500 + 50 0.5 0.2 0.05 @@ -55,7 +55,7 @@
  • - 500 + 15 1.0 1.0 0.05 @@ -76,7 +76,7 @@
  • - 500 + 15 Womb/Womb Genitals/BionicVagina true @@ -90,7 +90,7 @@
  • - 500 + 15 Womb/Womb Genitals/BionicVagina true @@ -104,7 +104,7 @@
  • - 500 + 15 1.0 1.0 0.05 diff --git a/changelogs.txt b/changelogs.txt index 4b39ce1..274469b 100644 --- a/changelogs.txt +++ b/changelogs.txt @@ -1,3 +1,20 @@ +Version 1.0.1.0 + - requires RJW 4.6.1 or later + - added multiple pregnancy + - added options for twins + - if you turn off both twin options, you will get only one baby on every pregnancy. + - male's litter curve size does not affect to number of offspring + - female can get multiple offsprings with multiple races. + +Version 1.0.0.10 + - fixed cycle acceleration option was not saved. + - cum capacity decreased greatly. + - blood amount during in period decreased. + +Version 1.0.0.9 + - update for RJW 4.6.0 (if you didn't update RJW, you don't need to update this mod) + - removed patch file for IUD. + Version 1.0.0.8 - added option for disable menopause. diff --git a/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs b/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs index 6a98751..842e017 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs +++ b/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs @@ -10,16 +10,18 @@ namespace RJW_Menstruation { public class Configurations : ModSettings { - public static readonly float ImplantationChanceDefault = 0.25f; - public static readonly int ImplantationChanceAdjustDefault = 25; - public static readonly float FertilizeChanceDefault = 0.05f; - public static readonly int FertilizeChanceAdjustDefault = 50; - public static readonly float CumDecayRatioDefault = 0.05f; - public static readonly int CumDecayRatioAdjustDefault = 50; - public static readonly float CumFertilityDecayRatioDefault = 0.2f; - public static readonly int CumFertilityDecayRatioAdjustDefault = 200; - public static readonly int CycleAccelerationDefault = 6; - + public const float ImplantationChanceDefault = 0.25f; + public const int ImplantationChanceAdjustDefault = 25; + public const float FertilizeChanceDefault = 0.05f; + public const int FertilizeChanceAdjustDefault = 50; + public const float CumDecayRatioDefault = 0.05f; + public const int CumDecayRatioAdjustDefault = 50; + public const float CumFertilityDecayRatioDefault = 0.2f; + public const int CumFertilityDecayRatioAdjustDefault = 200; + public const int CycleAccelerationDefault = 6; + public const float EnzygoticTwinsChanceDefault = 0.002f; + public const int EnzygoticTwinsChanceAdjustDefault = 2; + public const int MaxEnzygoticTwinsDefault = 9; public static float ImplantationChance = ImplantationChanceDefault; public static int ImplantationChanceAdjust = ImplantationChanceAdjustDefault; @@ -37,6 +39,12 @@ namespace RJW_Menstruation public static bool Debug = false; public static bool EnableMenopause = true; public static DetailLevel InfoDetail = DetailLevel.All; + public static bool UseMultiplePregnancy = true; + public static bool EnableHeteroOvularTwins = true; + public static bool EnableEnzygoticTwins = true; + public static float EnzygoticTwinsChance = EnzygoticTwinsChanceDefault; + public static int EnzygoticTwinsChanceAdjust = EnzygoticTwinsChanceAdjustDefault; + public static int MaxEnzygoticTwins = MaxEnzygoticTwinsDefault; public enum DetailLevel @@ -77,13 +85,19 @@ namespace RJW_Menstruation Scribe_Values.Look(ref CumDecayRatio, "CumDecayRatio", CumDecayRatio, true); Scribe_Values.Look(ref CumFertilityDecayRatioAdjust, "CumFertilityDecayRatioAdjust", CumFertilityDecayRatioAdjust, true); Scribe_Values.Look(ref CumFertilityDecayRatio, "CumFertilityDecayRatio", CumFertilityDecayRatio, true); + Scribe_Values.Look(ref CycleAcceleration, "CycleAcceleration", CycleAcceleration, true); Scribe_Values.Look(ref EnableWombIcon, "EnableWombIcon", EnableWombIcon, true); Scribe_Values.Look(ref EnableAnimalCycle, "EnableAnimalCycle", EnableAnimalCycle, true); Scribe_Values.Look(ref DrawWombStatus, "DrawWombStatus", DrawWombStatus, true); Scribe_Values.Look(ref DrawVaginaStatus, "DrawVaginaStatus", DrawVaginaStatus, true); Scribe_Values.Look(ref Debug, "Debug", Debug, true); Scribe_Values.Look(ref InfoDetail, "InfoDetail", InfoDetail, true); - Scribe_Values.Look(ref EnableMenopause, "EnableMenopause", EnableMenopause, true); + Scribe_Values.Look(ref UseMultiplePregnancy, "UseMultiplePregnancy", UseMultiplePregnancy, true); + Scribe_Values.Look(ref EnableHeteroOvularTwins, "EnableHeteroOvularTwins", EnableHeteroOvularTwins, true); + Scribe_Values.Look(ref EnableEnzygoticTwins, "EnableEnzygoticTwins", EnableEnzygoticTwins, true); + Scribe_Values.Look(ref EnzygoticTwinsChance, "EnzygoticTwinsChance", EnzygoticTwinsChance, true); + Scribe_Values.Look(ref EnzygoticTwinsChanceAdjust, "EnzygoticTwinsChanceAdjust", EnzygoticTwinsChanceAdjust, true); + Scribe_Values.Look(ref MaxEnzygoticTwins, "MaxEnzygoticTwins", MaxEnzygoticTwins, true); base.ExposeData(); } @@ -95,12 +109,16 @@ namespace RJW_Menstruation { private readonly Configurations config; + private static Vector2 scroll; + public RJW_Menstruation(ModContentPack content) : base(content) { config = GetSettings(); } + + public override string SettingsCategory() { return Translations.Mod_Title; @@ -108,10 +126,13 @@ namespace RJW_Menstruation public override void DoSettingsWindowContents(Rect inRect) { - Rect mainRect = inRect.ContractedBy(20f); + Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f); + Rect mainRect = new Rect(0f, 0f, inRect.width - 30f, inRect.height + 300f); Listing_Standard listmain = new Listing_Standard(); + listmain.maxOneColumn = true; + listmain.BeginScrollView(outRect, ref scroll, ref mainRect); listmain.Begin(mainRect); - + listmain.Gap(20f); listmain.CheckboxLabeled(Translations.Option1_Label, ref Configurations.EnableWombIcon, Translations.Option1_Desc); if (Configurations.EnableWombIcon) { @@ -164,6 +185,28 @@ namespace RJW_Menstruation listmain.Label(Translations.Option7_Label + " x" + Configurations.CycleAcceleration, -1, Translations.Option7_Desc); Configurations.CycleAcceleration = (int)listmain.Slider(Configurations.CycleAcceleration,1,50); + listmain.CheckboxLabeled(Translations.Option13_Label, ref Configurations.UseMultiplePregnancy, Translations.Option13_Desc); + if (Configurations.UseMultiplePregnancy) + { + float sectionheight = 50f; + if (Configurations.EnableEnzygoticTwins) sectionheight += 100; + Listing_Standard twinsection = listmain.BeginSection_NewTemp(sectionheight); + twinsection.CheckboxLabeled(Translations.Option14_Label, ref Configurations.EnableHeteroOvularTwins, Translations.Option14_Desc); + twinsection.CheckboxLabeled(Translations.Option15_Label, ref Configurations.EnableEnzygoticTwins, Translations.Option15_Desc); + if (Configurations.EnableEnzygoticTwins) + { + twinsection.Label(Translations.Option16_Label + " " + Configurations.EnzygoticTwinsChance*100 + "%", -1, Translations.Option16_Desc); + Configurations.EnzygoticTwinsChanceAdjust = (int)twinsection.Slider(Configurations.EnzygoticTwinsChanceAdjust, 0, 1000); + Configurations.EnzygoticTwinsChance = (float)Configurations.EnzygoticTwinsChanceAdjust / 1000; + + twinsection.Label(Translations.Option17_Label + " " + Configurations.MaxEnzygoticTwins, -1, Translations.Option17_Desc); + Configurations.MaxEnzygoticTwins = (int)twinsection.Slider(Configurations.MaxEnzygoticTwins, 2, 100); + } + + + listmain.EndSection(twinsection); + } + listmain.EndScrollView(ref mainRect); listmain.CheckboxLabeled(Translations.Option8_Label, ref Configurations.Debug, Translations.Option8_Desc); if (listmain.ButtonText("reset to default")) @@ -175,9 +218,13 @@ namespace RJW_Menstruation Configurations.EnableWombIcon = true; Configurations.EnableAnimalCycle = false; Configurations.CycleAcceleration = Configurations.CycleAccelerationDefault; + Configurations.EnzygoticTwinsChanceAdjust = Configurations.EnzygoticTwinsChanceAdjustDefault; + Configurations.EnableEnzygoticTwins = true; + Configurations.EnableHeteroOvularTwins = true; + Configurations.UseMultiplePregnancy = true; + Configurations.MaxEnzygoticTwins = Configurations.MaxEnzygoticTwinsDefault; } - listmain.End(); diff --git a/source/RJW_Menstruation/RJW_Menstruation/Dialog_WombStatus.cs b/source/RJW_Menstruation/RJW_Menstruation/Dialog_WombStatus.cs index c60f947..f8bc12d 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/Dialog_WombStatus.cs +++ b/source/RJW_Menstruation/RJW_Menstruation/Dialog_WombStatus.cs @@ -44,7 +44,7 @@ namespace RJW_Menstruation get { float width = 300f + 2 * windowMargin; - float height = 800f; + float height = 820f; if (!Configurations.DrawWombStatus) height -= wombRectHeight; if (!Configurations.DrawVaginaStatus) height -= genitalRectHeight; return new Vector2(width,height); @@ -76,7 +76,7 @@ namespace RJW_Menstruation } Rect windowRect = inRect.ContractedBy(windowMargin); - Rect mainRect = new Rect(windowRect.x, windowRect.y, windowRect.width, windowRect.height - 20f); + Rect mainRect = new Rect(windowRect.x, windowRect.y, windowRect.width, windowRect.height); Rect closeRect = new Rect(windowRect.xMax, 0f, 20f, 20f); MainContents(mainRect); if (Widgets.CloseButtonFor(closeRect)) @@ -101,7 +101,36 @@ namespace RJW_Menstruation if (pawn.IsPregnant() && Utility.ShowFetusImage((Hediff_BasePregnancy)hediff)) { womb = Utility.GetPregnancyIcon(comp, hediff); - if (hediff is Hediff_BasePregnancy) + if (hediff is Hediff_MultiplePregnancy) + { + Hediff_MultiplePregnancy h = (Hediff_MultiplePregnancy)hediff; + if (h.GestationProgress < 0.2f) cum = Utility.GetCumIcon(comp); + else cum = ContentFinder.Get(("Womb/Empty"), true); + Pawn fetus = Utility.GetFetus(pawn); + if (fetus != null && Utility.ShowFetusInfo()) + { + string feinfo = h.GetBabyInfo(); + string fainfo = h.GetFatherInfo() + " "; + if (feinfo.Length + fainfo.Length > 45) + { + preginfoheight = fontheight + 2; + buttonstyle.alignment = TextAnchor.UpperLeft; + fontstyleright.alignment = TextAnchor.LowerRight; + } + else + { + preginfoheight = fontheight; + buttonstyle.alignment = TextAnchor.MiddleLeft; + + } + Rect preginfo = new Rect(0f, mainRect.yMax - wombRectHeight - 2, wombRectWidth, preginfoheight); + fontstyleright.normal.textColor = Color.white; + GUI.Box(preginfo, feinfo, buttonstyle); + GUI.Label(preginfo, fainfo, fontstyleright); + } + + } + else if (hediff is Hediff_BasePregnancy) { Hediff_BasePregnancy h = (Hediff_BasePregnancy)hediff; if (h.GestationProgress < 0.2f) cum = Utility.GetCumIcon(comp); @@ -109,10 +138,13 @@ namespace RJW_Menstruation Pawn fetus = Utility.GetFetus(pawn); if (fetus != null && Utility.ShowFetusInfo()) { + preginfoheight = fontheight; Rect preginfo = new Rect(0f, mainRect.yMax - wombRectHeight - 2, wombRectWidth, preginfoheight); fontstyleright.normal.textColor = Color.white; + fontstyleright.alignment = TextAnchor.MiddleRight; buttonstyle.alignment = TextAnchor.MiddleLeft; + GUI.Box(preginfo, h.babies.Count + " " + fetus.def.label + " " + Translations.Dialog_WombInfo02, buttonstyle); GUI.Label(preginfo, Translations.Dialog_WombInfo03 + ": " + h.father.LabelShort + " ", fontstyleright); } @@ -156,9 +188,12 @@ namespace RJW_Menstruation fontstyleright.normal.textColor = Color.red; - if (comp.GetFertilization) GUI.Label(wombInfoRect, Translations.Dialog_WombInfo05 + " ", fontstyleright); - else if (comp.GetEggFertilizing) GUI.Label(wombInfoRect, Translations.Dialog_WombInfo06 + " ", fontstyleright); - else if (comp.GetEgg) GUI.Label(wombInfoRect, Translations.Dialog_WombInfo07 + " ", fontstyleright); + fontstyleright.alignment = TextAnchor.MiddleRight; + //if (comp.GetFertilization) GUI.Label(wombInfoRect, Translations.Dialog_WombInfo05 + " ", fontstyleright); + //else if (comp.GetEggFertilizing) GUI.Label(wombInfoRect, Translations.Dialog_WombInfo06 + " ", fontstyleright); + //else if (comp.GetEgg) GUI.Label(wombInfoRect, Translations.Dialog_WombInfo07 + " ", fontstyleright); + GUI.Label(wombInfoRect, comp.GetFertilizingInfo + " ", fontstyleright); + //Widgets.Label(wombInfoRect,Translations.Dialog_WombInfo01 + ": " + comp.GetCurStageLabel); diff --git a/source/RJW_Menstruation/RJW_Menstruation/HediffComp_Menstruation.cs b/source/RJW_Menstruation/RJW_Menstruation/HediffComp_Menstruation.cs index 4af1068..bb33a1b 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/HediffComp_Menstruation.cs +++ b/source/RJW_Menstruation/RJW_Menstruation/HediffComp_Menstruation.cs @@ -233,6 +233,31 @@ namespace RJW_Menstruation } } + + public string GetFertilizingInfo + { + get + { + string res = ""; + if (!eggs.NullOrEmpty()) + { + if (cums.NullOrEmpty()) return eggs.Count + " " + Translations.Dialog_WombInfo07; + else + { + int fertilized = 0; + foreach (Egg egg in eggs) + { + if (egg.fertilized) fertilized++; + } + if (fertilized != 0) res += fertilized + " " + Translations.Dialog_WombInfo05; + if (fertilized != 0 && eggs.Count - fertilized != 0) res += ", "; + if (eggs.Count - fertilized != 0) res += eggs.Count - fertilized + " " + Translations.Dialog_WombInfo06; + } + } + return res; + } + } + public bool GetEggFertilizing { get @@ -627,6 +652,7 @@ namespace RJW_Menstruation float rand = Rand.Range(0.0f, 1.0f); if (!cum.notcum && rand < cum.fertvolume * cum.fertFactor * Configurations.FertilizeChance * Props.basefertilizationChanceFactor) { + if (!RJWPregnancySettings.bestial_pregnancy_enabled && (xxx.is_animal(parent.pawn) ^ xxx.is_animal(cum.pawn))) continue; return cum.pawn; } } @@ -645,14 +671,48 @@ namespace RJW_Menstruation if (egg.position < 24 || !egg.fertilized) continue; else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * Props.baseImplantationChanceFactor * ImplantFactor * InterspeciesImplantFactor(egg.fertilizer)) { - if (!parent.pawn.IsPregnant()) PregnancyHelper.PregnancyDecider(parent.pawn, egg.fertilizer); - pregnant = true; - break; + if (!parent.pawn.IsPregnant()) + { + if (!Configurations.UseMultiplePregnancy) + { + PregnancyHelper.PregnancyDecider(parent.pawn, egg.fertilizer); + pregnant = true; + break; + } + else + { + Hediff_BasePregnancy.Create(parent.pawn, egg.fertilizer); + Hediff hediff = PregnancyHelper.GetPregnancy(parent.pawn); + if (hediff is Hediff_BasePregnancy) + { + Hediff_BasePregnancy h = (Hediff_BasePregnancy)hediff; + if (h.babies.Count > 1) h.babies.RemoveRange(1, h.babies.Count - 1); + } + pregnant = true; + deadeggs.Add(egg); + } + } + else if (Configurations.UseMultiplePregnancy && Configurations.EnableHeteroOvularTwins) + { + Hediff hediff = PregnancyHelper.GetPregnancy(parent.pawn); + if (hediff is Hediff_MultiplePregnancy) + { + Hediff_MultiplePregnancy h = (Hediff_MultiplePregnancy)hediff; + h.AddNewBaby(parent.pawn, egg.fertilizer); + } + pregnant = true; + deadeggs.Add(egg); + } + else + { + pregnant = true; + break; + } } else deadeggs.Add(egg); } - if (pregnant) + if (pregnant && (!Configurations.UseMultiplePregnancy || !Configurations.EnableHeteroOvularTwins)) { eggs.Clear(); deadeggs.Clear(); @@ -666,6 +726,7 @@ namespace RJW_Menstruation } deadeggs.Clear(); } + if (pregnant) return true; } return false; } @@ -673,7 +734,7 @@ namespace RJW_Menstruation private void BleedOut() { //FilthMaker.TryMakeFilth(parent.pawn.Position, parent.pawn.Map, ThingDefOf.Filth_Blood,parent.pawn.Label); - CumIn(parent.pawn, Rand.Range(0f, 15f), Translations.Menstrual_Blood,-4.0f,ThingDefOf.Filth_Blood); + CumIn(parent.pawn, Rand.Range(0f, 5f), Translations.Menstrual_Blood,-5.0f,ThingDefOf.Filth_Blood); GetNotCum(Translations.Menstrual_Blood).color = Colors.blood; } @@ -812,7 +873,7 @@ namespace RJW_Menstruation } else { - if (curStageHrs < bleedingIntervalhours / 6) for (int i = 0; i < Configurations.CycleAcceleration; i++) BleedOut(); + if (curStageHrs < bleedingIntervalhours / 4) for (int i = 0; i < Configurations.CycleAcceleration; i++) BleedOut(); curStageHrs+=Configurations.CycleAcceleration; StayCurrentStage(); } @@ -842,6 +903,12 @@ namespace RJW_Menstruation case Stage.Pregnant: action = delegate { + if (!eggs.NullOrEmpty()) + { + EggDecay(); + FertilizationCheck(); + Implant(); + } if (parent.pawn.IsPregnant()) StayCurrentStageConst(Stage.Pregnant); else GoNextStage(Stage.Recover); }; @@ -1058,6 +1125,8 @@ namespace RJW_Menstruation } + + public class Egg : IExposable { diff --git a/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs b/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs new file mode 100644 index 0000000..eff1dcb --- /dev/null +++ b/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs @@ -0,0 +1,505 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Reflection; +using rjw; +using Verse; +using RimWorld; + + +namespace RJW_Menstruation +{ + public class Hediff_MultiplePregnancy : Hediff_BasePregnancy + { + + + + + public override void GiveBirth() + { + + if (babies.NullOrEmpty()) + { + ModLog.Warning(" no babies (debug?) " + this.GetType().Name); + if (father == null) + { + father = Trytogetfather(ref pawn); + } + Initialize(pawn, father); + } + + List siblings = new List(); + foreach (Pawn baby in babies) + { + if (xxx.is_animal(baby)) + { + BestialBirth(baby, siblings); + } + else + { + HumanlikeBirth(baby, siblings); + } + + } + + pawn.health.RemoveHediff(this); + } + + public string GetBabyInfo() + { + string res = ""; + if (!babies.NullOrEmpty()) + { + var 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 += ", "; + res += num + " " + baby.def.label; + iteration++; + } + res += " " + Translations.Dialog_WombInfo02; + return res; + } + return "Null"; + } + + public string GetFatherInfo() + { + string res = Translations.Dialog_WombInfo03 + ": "; + if (!babies.NullOrEmpty()) + { + var babiesdistinct = babies.Distinct(new FatherComparer(pawn)); + int iteration = 0; + foreach (Pawn baby in babiesdistinct) + { + if (iteration > 0) res += ", "; + res += Utility.GetFather(baby, pawn)?.LabelShort ?? "Unknown"; + iteration++; + } + return res; + } + return "Null"; + } + + + + + private void HumanlikeBirth(Pawn baby, List siblings) + { + Pawn mother = pawn; Pawn father = Utility.GetFather(baby,pawn); + //backup melanin, LastName for when baby reset by other mod on spawn/backstorychange + //var skin_whiteness = baby.story.melanin; + //var last_name = baby.story.birthLastName; + + PawnUtility.TrySpawnHatchedOrBornPawn(baby, mother); + + var sex_need = mother.needs?.TryGetNeed(); + if (mother.Faction != null && !(mother.Faction?.IsPlayer ?? false) && sex_need != null) + { + sex_need.CurLevel = 1.0f; + } + if (mother.Faction != null) + { + if (mother.Faction != baby.Faction) + baby.SetFaction(mother.Faction); + } + if (mother.IsPrisonerOfColony) + { + baby.guest.CapturedBy(Faction.OfPlayer); + } + + foreach (Pawn sibling in siblings) + { + baby.relations.AddDirectRelation(PawnRelationDefOf.Sibling, sibling); + } + siblings.Add(baby); + + PostBirth(mother, father, baby); + } + + + private void BestialBirth(Pawn baby, List siblings) + { + Pawn mother = pawn; Pawn father = Utility.GetFather(baby,pawn); + //backup melanin, LastName for when baby reset by other mod on spawn/backstorychange + //var skin_whiteness = baby.story.melanin; + //var last_name = baby.story.birthLastName; + + PawnUtility.TrySpawnHatchedOrBornPawn(baby, mother); + + Need_Sex sex_need = mother.needs?.TryGetNeed(); + if (mother.Faction != null && !(mother.Faction?.IsPlayer ?? false) && sex_need != null) + { + sex_need.CurLevel = 1.0f; + } + if (mother.Faction != null) + { + if (mother.Faction != baby.Faction) + baby.SetFaction(mother.Faction); + } + + + foreach (Pawn sibling in siblings) + { + baby.relations.AddDirectRelation(PawnRelationDefOf.Sibling, sibling); + } + siblings.Add(baby); + train(baby, mother, father); + + PostBirth(mother, father, baby); + + //restore melanin, LastName for when baby reset by other mod on spawn/backstorychange + //baby.story.melanin = skin_whiteness; + //baby.story.birthLastName = last_name; + + + + } + + protected override void GenerateBabies() + { + AddNewBaby(pawn, father); + } + + + + protected void train(Pawn baby, Pawn mother, Pawn father) + { + bool _; + if (!xxx.is_human(baby) && baby.Faction == Faction.OfPlayer) + { + if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Obedience, out _).Accepted) + { + baby.training.Train(TrainableDefOf.Obedience, mother); + } + if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Tameness, out _).Accepted) + { + baby.training.Train(TrainableDefOf.Tameness, mother); + } + } + } + + + public bool AddNewBaby(Pawn mother, Pawn father) + { + float melanin; + string lastname; + if (xxx.is_human(mother)) + { + if (xxx.is_human(father)) + { + melanin = (mother.story.melanin + father.story.melanin) / 2; + lastname = NameTriple.FromString(father.Name.ToStringFull).Last; + } + else + { + melanin = mother.story.melanin; + lastname = NameTriple.FromString(mother.Name.ToStringFull).Last; + } + + } + else + { + if (xxx.is_human(father)) + { + melanin = father.story.melanin; + lastname = NameTriple.FromString(father.Name.ToStringFull).Last; + } + else melanin = Rand.Range(0, 1.0f); + } + + PawnGenerationRequest request = new PawnGenerationRequest( + newborn: true, + allowDowned: true, + canGeneratePawnRelations: false, + colonistRelationChanceFactor: 0, + allowFood: false, + allowAddictions: false, + relationWithExtraPawnChanceFactor: 0, + fixedMelanin: melanin, + kind: BabyPawnKindDecider(mother, father) + ); + Pawn baby = PawnGenerator.GeneratePawn(request); + if (baby != null) + { + if (xxx.is_human(baby)) + { + List traitpool = new List(); + baby.SetMother(mother); + if (mother != father) baby.SetFather(father); + + if (xxx.has_traits(pawn) && pawn.RaceProps.Humanlike) + { + foreach (Trait momtrait in pawn.story.traits.allTraits) + { + if (!RJWPregnancySettings.trait_filtering_enabled || !non_genetic_traits.Contains(momtrait.def.defName)) + traitpool.Add(momtrait); + } + } + if (father != null && xxx.has_traits(father) && father.RaceProps.Humanlike) + { + foreach (Trait poptrait in father.story.traits.allTraits) + { + if (!RJWPregnancySettings.trait_filtering_enabled || !non_genetic_traits.Contains(poptrait.def.defName)) + traitpool.Add(poptrait); + } + } + updateTraits(baby, traitpool); + + } + else + { + baby.relations.AddDirectRelation(VariousDefOf.Relation_birthgiver, mother); + mother.relations.AddDirectRelation(VariousDefOf.Relation_spawn, baby); + if (mother != father) + { + baby.relations.AddDirectRelation(VariousDefOf.Relation_birthgiver, father); + father.relations.AddDirectRelation(VariousDefOf.Relation_spawn, baby); + } + } + + int division = 1; + while (Rand.Chance(Configurations.EnzygoticTwinsChance) && division < Configurations.MaxEnzygoticTwins) division++; + for (int i = 0; i < division; i++) babies.Add(baby); + return true; + } + + + return false; + + } + + + + /// + /// Decide pawnkind from mother and father + /// Come from RJW + /// + /// + /// + /// + public PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father) + { + PawnKindDef spawn_kind_def = mother.kindDef; + 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 = father.kindDef; + break; + case 2: + if (RJWPregnancySettings.bestiality_DNA_inheritance == 0f) spawn_kind_def = father.kindDef; + else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = father.kindDef; + break; + case 1: + if (RJWPregnancySettings.bestiality_DNA_inheritance == 1f) spawn_kind_def = father.kindDef; + else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = father.kindDef; + break; + case 0: + if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = father.kindDef; + break; + } + + bool IsAndroidmother = AndroidsCompatibility.IsAndroid(mother); + bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father); + if (IsAndroidmother && !IsAndroidfather) + { + spawn_kind_def = father.kindDef; + } + else if (!IsAndroidmother && IsAndroidfather) + { + spawn_kind_def = mother.kindDef; + } + + + string MotherRaceName = ""; + string FatherRaceName = ""; + MotherRaceName = mother.kindDef.race.defName; + if (father != null) + FatherRaceName = father.kindDef.race.defName; + if (MotherRaceName != FatherRaceName && FatherRaceName != "") + { + var groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty())); + + + //ModLog.Message(" found custom RaceGroupDefs " + groups.Count()); + foreach (var 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 = mother.kindDef; + else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null) + spawn_kind_def = father.kindDef; + else + { + //ModLog.Message(" trying hybridChildKindDef " + t.defName); + var 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 + { + spawn_kind_def = mother.RaceProps.AnyPawnKind; + } + + + if (spawn_kind_def.defName.Contains("Nymph")) + { + //child is nymph, try to find other PawnKindDef + var 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 == mother.kindDef.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 == father.kindDef.race && !x.defName.Contains("Nymph"))); + //no other PawnKindDef found fallback to generic colonist + if (spawn_kind_def_list.NullOrEmpty()) + spawn_kind_def = PawnKindDefOf.Colonist; + + spawn_kind_def = spawn_kind_def_list.RandomElement(); + } + + + + + return spawn_kind_def; + + } + + + /// + /// Copy from RJW + /// + /// + /// + public void updateTraits(Pawn pawn, List parenttraits) + { + if (pawn?.story?.traits == null) return; + + List traitlist = new List(pawn.story.traits.allTraits); + if (!parenttraits.NullOrEmpty()) traitlist.AddRange(parenttraits); + else return; + + + var forcedTraits = traitlist + .Where(x => x.ScenForced) + .Distinct(new TraitComparer(ignoreDegree: true)); + + List res = new List(); + res.AddRange(forcedTraits); + + var comparer = new TraitComparer(); // trait comparision implementation, because without game compares traits *by reference*, makeing them all unique. + + while (res.Count < traitlist.Count && traitlist.Count > 0) + { + int index = Rand.Range(0, traitlist.Count); // getting trait and removing from the pull + var trait = traitlist[index]; + traitlist.RemoveAt(index); + + if (!res.Any(x => comparer.Equals(x, trait) || // skipping traits conflicting with already added + x.def.ConflictsWith(trait))) + { + res.Add(new Trait(trait.def, trait.Degree, false)); + } + } + + + pawn.story.traits.allTraits = res; + } + + + + } + + /// + /// Copy from RJW + /// + public class TraitComparer : IEqualityComparer + { + bool ignoreForced; + bool ignoreDegree; + + public TraitComparer(bool ignoreDegree = false, bool ignoreForced = true) + { + this.ignoreDegree = ignoreDegree; + this.ignoreForced = ignoreForced; + } + + public bool Equals(Trait x, Trait y) + { + return + x.def == y.def && + (ignoreDegree || (x.Degree == y.Degree)) && + (ignoreForced || (x.ScenForced == y.ScenForced)); + } + + public int GetHashCode(Trait obj) + { + return + (obj.def.GetHashCode() << 5) + + (ignoreDegree ? 0 : obj.Degree) + + ((ignoreForced || obj.ScenForced) ? 0 : 0x10); + } + } + + public class RaceComparer : IEqualityComparer + { + public bool Equals(Pawn x, Pawn y) + { + return x.def.Equals(y.def); + } + + public int GetHashCode(Pawn obj) + { + return obj.def.GetHashCode(); + } + } + + public class FatherComparer : IEqualityComparer + { + Pawn mother; + + public FatherComparer(Pawn mother) + { + this.mother = mother; + } + + public bool Equals(Pawn x, Pawn y) + { + if (Utility.GetFather(x, mother) == null && Utility.GetFather(y, mother) == null) return true; + return Utility.GetFather(x,mother)?.Label.Equals(Utility.GetFather(y,mother)?.Label) ?? false; + } + + public int GetHashCode(Pawn obj) + { + return obj.def.GetHashCode(); + } + } + +} diff --git a/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj b/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj index 5312bc7..4e97327 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj +++ b/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj @@ -60,6 +60,7 @@ + @@ -84,7 +85,7 @@ False - ..\..\..\..\RJW\1.1\Assemblies\RJW.dll + ..\..\..\..\RJW\1.2\Assemblies\RJW.dll False diff --git a/source/RJW_Menstruation/RJW_Menstruation/Translations.cs b/source/RJW_Menstruation/RJW_Menstruation/Translations.cs index 4ccf982..89b5e84 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/Translations.cs +++ b/source/RJW_Menstruation/RJW_Menstruation/Translations.cs @@ -58,6 +58,14 @@ namespace RJW_Menstruation public static readonly string Option12_Desc = "Option12_Desc".Translate(); public static readonly string Option13_Label = "Option13_Label".Translate(); public static readonly string Option13_Desc = "Option13_Desc".Translate(); + public static readonly string Option14_Label = "Option14_Label".Translate(); + public static readonly string Option14_Desc = "Option14_Desc".Translate(); + public static readonly string Option15_Label = "Option15_Label".Translate(); + public static readonly string Option15_Desc = "Option15_Desc".Translate(); + public static readonly string Option16_Label = "Option16_Label".Translate(); + public static readonly string Option16_Desc = "Option16_Desc".Translate(); + public static readonly string Option17_Label = "Option17_Label".Translate(); + public static readonly string Option17_Desc = "Option17_Desc".Translate(); diff --git a/source/RJW_Menstruation/RJW_Menstruation/Utility.cs b/source/RJW_Menstruation/RJW_Menstruation/Utility.cs index ce81a77..ba248ee 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/Utility.cs +++ b/source/RJW_Menstruation/RJW_Menstruation/Utility.cs @@ -50,7 +50,7 @@ namespace RJW_Menstruation public static bool HasMenstruationComp(Pawn pawn) { - var hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)).FindAll((Hediff h) => h.def.defName.ToLower().Contains("vagina")); + var hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll((Hediff h) => h.def.defName.ToLower().Contains("vagina")); HediffComp_Menstruation result; if (hedifflist.NullOrEmpty()) return false; else @@ -239,6 +239,22 @@ namespace RJW_Menstruation else return false; } + public static Pawn GetFather(Pawn pawn, Pawn mother) + { + Pawn res = pawn.GetFather(); + if (res != null) return res; + else + { + res = pawn.relations?.GetFirstDirectRelationPawn(VariousDefOf.Relation_birthgiver, x => !x.Equals(mother)) ?? null; + return res; + } + + + + + } + + } } diff --git a/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs b/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs index d33dda5..6e2f8c4 100644 --- a/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs +++ b/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs @@ -24,5 +24,7 @@ namespace RJW_Menstruation public static readonly HediffDef Hediff_Climacteric = DefDatabase.GetNamed("Hediff_Climacteric"); public static readonly HediffDef Hediff_Menopause = DefDatabase.GetNamed("Hediff_Menopause"); + public static readonly PawnRelationDef Relation_birthgiver = DefDatabase.AllDefs.FirstOrDefault(d => d.defName == "RJW_Sire"); + public static readonly PawnRelationDef Relation_spawn = DefDatabase.AllDefs.FirstOrDefault(d => d.defName == "RJW_Pup"); } }