added multiple pregnancy

This commit is contained in:
moreoreganostodump 2021-02-12 13:16:46 +09:00
parent 4e5c02f5f0
commit fb170aacb2
15 changed files with 755 additions and 58 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest>
<identifier>RJW Menstruation</identifier>
<version>1.0.0.8</version>
<version>1.0.1.0</version>
<dependencies>
</dependencies>
<incompatibleWith />

Binary file not shown.

View File

@ -50,7 +50,15 @@
<Option11_Desc_4>Do not show fetus image and informations</Option11_Desc_4>
<Option12_Label>enable menopause</Option12_Label>
<Option12_Desc>enable menopause effect that makes pawn infertile in time progress&#10;if you have problems with long life races, turn off this option.&#10;this option will apply after save loaded</Option12_Desc>
<Option13_Label></Option13_Label>
<Option13_Desc> </Option13_Desc>
<Option13_Label>use multiple pregnancy</Option13_Label>
<Option13_Desc>use multiple pregnancy instead RJW's default pregnancy</Option13_Desc>
<Option14_Label>enable hetero ovular twins</Option14_Label>
<Option14_Desc>enable multiple eggs can get pregnant</Option14_Desc>
<Option15_Label>enable enzygotic twins</Option15_Label>
<Option15_Desc>enable single egg to result multiple offsprings</Option15_Desc>
<Option16_Label>enzygotic twins chance</Option16_Label>
<Option16_Desc>set chance of twins</Option16_Desc>
<Option17_Label>max enzygotic twins</Option17_Label>
<Option17_Desc>set max number of twins</Option17_Desc>
</LanguageData>

View File

@ -50,8 +50,16 @@
<Option11_Desc_4>태아에 대한 어떠한 정보도 표시하지 않습니다.</Option11_Desc_4>
<Option12_Label>폐경기 활성화</Option12_Label>
<Option12_Desc>시간이 지남에따라 불임상태로 만드는 폐경기를 활성화합니다.&#10;수명이 긴 종족을 사용할때 문제가 있으면 이 옵션을 끄세요.&#10;변경한후에 세이브로드가 필요합니다.</Option12_Desc>
<Option13_Label></Option13_Label>
<Option13_Desc> </Option13_Desc>
<Option13_Label>다중임신</Option13_Label>
<Option13_Desc>RJW의 기본임신 대신 다중임신을 사용합니다.</Option13_Desc>
<Option14_Label>이란성 쌍둥이 활성화</Option14_Label>
<Option14_Desc>다수의 난자가 임신으로 이어지게 합니다.</Option14_Desc>
<Option15_Label>일란성 쌍둥이 활성화</Option15_Label>
<Option15_Desc>하나의 난자가 다수의 태아로 나뉘게 합니다.</Option15_Desc>
<Option16_Label>일란성 쌍둥이 확률</Option16_Label>
<Option16_Desc>일란성 쌍둥이가 발생할 확률을 설정합니다.</Option16_Desc>
<Option17_Label>최대 일란성 쌍둥이 수</Option17_Label>
<Option17_Desc>일란성 쌍둥이의 수를 제한합니다.</Option17_Desc>
</LanguageData>

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Patch>
<Operation Class="PatchOperationReplace">
<xpath>Defs/HediffDef[defName="RJW_IUD"]/stages</xpath>
<value>
<stages>
<li>
<capMods>
<li>
<capacity>RJW_Fertility</capacity>
<setMax>1.0</setMax>
</li>
</capMods>
</li>
</stages>
</value>
</Operation>
</Patch>

View File

@ -12,7 +12,7 @@
<value>
<comps>
<li Class="RJW_Menstruation.CompProperties_Menstruation">
<maxCumCapacity>500</maxCumCapacity>
<maxCumCapacity>15</maxCumCapacity>
<baseImplantationChanceFactor>1.0</baseImplantationChanceFactor>
<basefertilizationChanceFactor>1.0</basefertilizationChanceFactor>
<deviationFactor>0.05</deviationFactor>
@ -34,7 +34,7 @@
<value>
<comps>
<li Class="RJW_Menstruation.CompProperties_Menstruation">
<maxCumCapacity>500</maxCumCapacity>
<maxCumCapacity>50</maxCumCapacity>
<baseImplantationChanceFactor>0.5</baseImplantationChanceFactor>
<basefertilizationChanceFactor>0.2</basefertilizationChanceFactor>
<deviationFactor>0.05</deviationFactor>
@ -55,7 +55,7 @@
<value>
<comps>
<li Class="RJW_Menstruation.CompProperties_Menstruation">
<maxCumCapacity>500</maxCumCapacity>
<maxCumCapacity>15</maxCumCapacity>
<baseImplantationChanceFactor>1.0</baseImplantationChanceFactor>
<basefertilizationChanceFactor>1.0</basefertilizationChanceFactor>
<deviationFactor>0.05</deviationFactor>
@ -76,7 +76,7 @@
<value>
<comps>
<li Class="RJW_Menstruation.CompProperties_Menstruation">
<maxCumCapacity>500</maxCumCapacity>
<maxCumCapacity>15</maxCumCapacity>
<wombTex>Womb/Womb</wombTex>
<vagTex>Genitals/BionicVagina</vagTex>
<infertile>true</infertile>
@ -90,7 +90,7 @@
<value>
<comps>
<li Class="RJW_Menstruation.CompProperties_Menstruation">
<maxCumCapacity>500</maxCumCapacity>
<maxCumCapacity>15</maxCumCapacity>
<wombTex>Womb/Womb</wombTex>
<vagTex>Genitals/BionicVagina</vagTex>
<infertile>true</infertile>
@ -104,7 +104,7 @@
<value>
<comps>
<li Class="RJW_Menstruation.CompProperties_Menstruation">
<maxCumCapacity>500</maxCumCapacity>
<maxCumCapacity>15</maxCumCapacity>
<baseImplantationChanceFactor>1.0</baseImplantationChanceFactor>
<basefertilizationChanceFactor>1.0</basefertilizationChanceFactor>
<deviationFactor>0.05</deviationFactor>

View File

@ -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.

View File

@ -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<Configurations>();
}
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();

View File

@ -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<Texture2D>.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);

View File

@ -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<Hediff_MultiplePregnancy>(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
{

View File

@ -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<Pawn> siblings = new List<Pawn>();
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<Pawn> 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<Need_Sex>();
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<Pawn> 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<Need_Sex>();
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<Trait> traitpool = new List<Trait>();
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;
}
/// <summary>
/// Decide pawnkind from mother and father <para/>
/// Come from RJW
/// </summary>
/// <param name="mother"></param>
/// <param name="father"></param>
/// <returns></returns>
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<RaceGroupDef>.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<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
{
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<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 == 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<PawnKindDef>.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;
}
/// <summary>
/// Copy from RJW
/// </summary>
/// <param name="pawn"></param>
/// <param name="parenttraits"></param>
public void updateTraits(Pawn pawn, List<Trait> parenttraits)
{
if (pawn?.story?.traits == null) return;
List<Trait> traitlist = new List<Trait>(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<Trait> res = new List<Trait>();
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;
}
}
/// <summary>
/// Copy from RJW
/// </summary>
public class TraitComparer : IEqualityComparer<Trait>
{
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<Pawn>
{
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>
{
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();
}
}
}

View File

@ -60,6 +60,7 @@
<Compile Include="Dialog_WombStatus.cs" />
<Compile Include="DNADef.cs" />
<Compile Include="DrugOutcomDoers.cs" />
<Compile Include="Hediff_MultiplePregnancy.cs" />
<Compile Include="Patch\GetGizmos.cs" />
<Compile Include="Gizmo_Womb.cs" />
<Compile Include="Patch\Harmony.cs" />
@ -84,7 +85,7 @@
<Private>False</Private>
</Reference>
<Reference Include="RJW">
<HintPath>..\..\..\..\RJW\1.1\Assemblies\RJW.dll</HintPath>
<HintPath>..\..\..\..\RJW\1.2\Assemblies\RJW.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.TextMeshPro">

View File

@ -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();

View File

@ -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;
}
}
}
}

View File

@ -24,5 +24,7 @@ namespace RJW_Menstruation
public static readonly HediffDef Hediff_Climacteric = DefDatabase<HediffDef>.GetNamed("Hediff_Climacteric");
public static readonly HediffDef Hediff_Menopause = DefDatabase<HediffDef>.GetNamed("Hediff_Menopause");
public static readonly PawnRelationDef Relation_birthgiver = DefDatabase<PawnRelationDef>.AllDefs.FirstOrDefault(d => d.defName == "RJW_Sire");
public static readonly PawnRelationDef Relation_spawn = DefDatabase<PawnRelationDef>.AllDefs.FirstOrDefault(d => d.defName == "RJW_Pup");
}
}