Compare commits

...

46 commits

Author SHA1 Message Date
Naz
701d7c1901 Merge branch 'main' into 'main'
Korean Translation

See merge request lutepickle/rjw_menstruation!3
2023-03-04 17:46:10 +00:00
lutepickle
db7ca5c77a Remove texture-breaking milk patch 2023-03-03 16:56:07 -08:00
lutepickle
b254273935 Merge branch 'dev' 2023-03-02 21:34:10 -08:00
lutepickle
e4583fe9d7 Add placeholder graphic for genes 2023-03-02 18:55:29 -08:00
lutepickle
5abdf52dbe Use GoNextStage more to properly reset curStageHrs 2023-03-02 14:42:49 -08:00
lutepickle
69934d06f5 Add patch to darken nipples during Biotech lactation, but commented out 2023-03-01 17:00:58 -08:00
lutepickle
09f9438bcc Reset the baby name deadline at birth 2023-03-01 16:29:58 -08:00
lutepickle
91142d640f Copy hair color for identical twins 2023-03-01 10:21:59 -08:00
lutepickle
b28beb8eaa Add some debug logging around the pregnancy to labor transition 2023-03-01 09:55:54 -08:00
lutepickle
ca895ef296 Show the debug due date on the gizmo for Biotech pregnancies 2023-02-28 18:02:20 -08:00
lutepickle
5c27575446 Save the Biotech twins setting 2023-02-27 21:36:31 -08:00
lutepickle
92ace30022 Properly show multiple fetuses with pregenerated babies 2023-02-27 21:33:14 -08:00
lutepickle
672e6f6ecc Remove unneeded milk bottle graphics 2023-02-13 10:22:23 -08:00
lutepickle
2b0d5dd0e6 Some mods break SkinColor to the point that even trying to access it throws a null ref, so go work around that 2023-01-25 07:11:00 -08:00
lutepickle
aba80efe58 Don't allow adding genes to pawns without wombs 2023-01-22 09:44:28 -08:00
lutepickle
9f20f78aab Remove a HarmonyDebug 2023-01-11 07:34:58 -08:00
lutepickle
71575c671e Fix error when trying to terminate a menstruation pregnancy 2023-01-11 07:32:50 -08:00
lutepickle
da7284b909 Make the HAR disabler conditional only on the configuration. There's too many birtherThing/geneticMother edge cases to make puzzling it out practical 2023-01-11 06:24:14 -08:00
lutepickle
3132992aa3 A bunch of type-safety around HAR. 2023-01-10 16:09:37 -08:00
lutepickle
2cb26ea016 HAR transpiles ApplyBirthOutcome to produce multiple children per littersize, but the pregenerated babies already handle that. So patch HAR to only produce one if our system is running 2023-01-10 12:41:11 -08:00
lutepickle
b9bfad10bb Resolve graphics on all newly generated babies, not just the first of a set 2023-01-10 08:20:22 -08:00
lutepickle
7d8228e03a Ensure that Biotech babies are born at zero ticks of age 2023-01-10 07:05:13 -08:00
lutepickle
93566b5fa3 Call ResolveAllGraphics unconditionally for babies. Also copy skinColorOverride for twins 2023-01-10 05:46:16 -08:00
lutepickle
d34c96315a Have the babies track their fathers during pregnancy 2023-01-09 08:50:50 -08:00
lutepickle
638b9f4611 Make the mod options window a bit longer just to make all the buttons appear again 2023-01-08 12:53:26 -08:00
lutepickle
08a50e47c3 Add Biotech twin option to configuration settings, disabled by default 2023-01-08 12:33:06 -08:00
lutepickle
c3176fb0e5 Integration of pregenerated babies into the womb dialog 2023-01-08 12:19:47 -08:00
lutepickle
f5f8eba037 Save option for enabling biotech twins 2023-01-08 12:02:18 -08:00
lutepickle
fcfb7cdefb Add support for pregenerated babies into Implant 2023-01-08 12:01:45 -08:00
lutepickle
89f26b2601 Add the two transpilers to allow looping through babies 2023-01-08 11:29:21 -08:00
lutepickle
e42bbdb3d4 Add the ApplyBirthOutcome transpiler 2023-01-08 10:11:58 -08:00
lutepickle
7bf9f80742 Add a missing using directive to PregnancyCommon 2023-01-07 21:23:08 -08:00
lutepickle
8aff96e5a4 Prevent two humanlikes from creating an animal for Biotech pregnancies 2023-01-07 20:58:28 -08:00
lutepickle
12c760d16c Fix periodic ovulator cycle variability 2023-01-07 20:26:13 -08:00
lutepickle
045e9548f6 Framework for pregenerated babies 2023-01-07 20:18:17 -08:00
lutepickle
3f21b760b2 Make the MethodInfos in MultiplePregnancy static. 2023-01-07 12:00:48 -08:00
lutepickle
21e471ebf3 Use the builtin BestOutcome for the childbirth ritual instead of searching our own. 2023-01-07 11:50:37 -08:00
lutepickle
da9903aaf9 Updated Traditional Chinese by Hydrogen 2023-01-07 06:46:15 -08:00
lutepickle
22b2aca312 Change the terminology of the gene descriptions a bit 2023-01-07 06:28:16 -08:00
lutepickle
b4aa55c159 Re-add GetMenstruationComp(Hediff) marked as obsolete. There's code out there that calls it. 2023-01-07 06:08:42 -08:00
lutepickle
68f05dc272 The genes aren't inheritable, so don't bother saying "born with" in the egg multiplier descriptions. Leave support in the code, though. 2023-01-07 05:32:19 -08:00
lutepickle
f3e14e67b0 Initial implementation of genes 2023-01-03 22:48:06 -08:00
exoxemsn.com
8000949752 Update 1.4/Languages/Korean/Keyed/RJW_Menstruation.xml 2022-12-27 08:06:00 +00:00
exoxemsn.com
765b85dc2c Update 1.4/Languages/Korean/DefInjected/ThingDef/Pills_Menstruation.xml 2022-12-26 14:30:59 +00:00
exoxemsn.com
6cf5cba76b Update 1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Cum.xml, 1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Menstruation.xml, 1.4/Languages/Korean/DefInjected/JobDef/Jobs_CleanSelf.xml, 1.4/Languages/Korean/DefInjected/JobDef/Jobs_MilkSelf.xml, 1.4/Languages/Korean/DefInjected/KeyBinding/KeyBindings_Menstruation.xml, 1.4/Languages/Korean/DefInjected/RecipeDef/Recipes_Surgery_Breast.xml, 1.4/Languages/Korean/DefInjected/RecordDef/Records_Womb.xml, 1.4/Languages/Korean/DefInjected/StatDef/Stats_Absorber.xml, 1.4/Languages/Korean/DefInjected/TaleDef/Tales_Cum.xml, 1.4/Languages/Korean/DefInjected/ThingDef/Apparel_Absorbers.xml, 1.4/Languages/Korean/DefInjected/ThingDef/ApparelLayerDefs_Absorber.xml, 1.4/Languages/Korean/DefInjected/ThingDef/Filth_Mixture.xml, 1.4/Languages/Korean/DefInjected/ThingDef/Pills_Menstruation.xml, 1.4/Languages/Korean/DefInjected/ThoughtDef/Thoughts_sex.xml, 1.4/Languages/Korean/Keyed/RJW_Menstruation.xml 2022-12-22 13:46:10 +00:00
exoxemsn.com
8768c1b7e7 Deleted 1.4/Languages/Korean/DefInjected/ApparelLayerDef/RJWMenstruation.xml, 1.4/Languages/Korean/DefInjected/HediffDef/RJWMenstruation.xml, 1.4/Languages/Korean/DefInjected/JobDef/RJWMenstruation.xml, 1.4/Languages/Korean/DefInjected/RecipeDef/BreastSurgeries.xml, 1.4/Languages/Korean/DefInjected/RecordDef/RJWMenstruation.xml, 1.4/Languages/Korean/DefInjected/StatDef/RJWMenstruation.xml, 1.4/Languages/Korean/DefInjected/ThingDef/RJWMenstruation.xml, 1.4/Languages/Korean/DefInjected/ThoughtDef/RJWMenstruation.xml, 1.4/Languages/Korean/Keyed/RJW_Menstruation.xml 2022-12-22 13:38:18 +00:00
52 changed files with 1319 additions and 504 deletions

Binary file not shown.

View file

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Defs>
<GeneCategoryDef>
<defName>Menstruation</defName>
<label>menstruation</label>
<displayPriorityInXenotype>402</displayPriorityInXenotype>
</GeneCategoryDef>
<GeneDef Name="Menstruation_EggLifetime" Abstract="True">
<displayCategory>Menstruation</displayCategory>
<exclusionTags>
<li>Menstruation_EggLifetime</li>
</exclusionTags>
</GeneDef>
<GeneDef ParentName="Menstruation_EggLifetime">
<defName>Menstruation_ShortEggLifetime</defName>
<label>short egg lifetime</label>
<description>Unfertilized eggs with this gene last three-quarters as long.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>1</biostatMet>
<displayOrderInCategory>10</displayOrderInCategory>
</GeneDef>
<GeneDef ParentName="Menstruation_EggLifetime">
<defName>Menstruation_DoubleEggLifetime</defName>
<label>double egg lifetime</label>
<description>Unfertilized eggs with this gene last twice as long.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>-1</biostatMet>
<displayOrderInCategory>12</displayOrderInCategory>
</GeneDef>
<GeneDef ParentName="Menstruation_EggLifetime">
<defName>Menstruation_QuadEggLifetime</defName>
<label>quadrule egg lifetime</label>
<description>Eggs with this gene last four times as long.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>-2</biostatMet>
<biostatCpx>1</biostatCpx>
<displayOrderInCategory>16</displayOrderInCategory>
</GeneDef>
<GeneDef Name="Menstruation_Estrus" Abstract="True">
<displayCategory>Menstruation</displayCategory>
<exclusionTags>
<li>Menstruation_Estrus</li>
</exclusionTags>
</GeneDef>
<GeneDef ParentName="Menstruation_Estrus">
<defName>Menstruation_NeverEstrus</defName>
<label>never estrus</label>
<description>Carriers of this gene will never go into estrus.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>1</biostatMet>
<displayOrderInCategory>20</displayOrderInCategory>
</GeneDef>
<GeneDef ParentName="Menstruation_Estrus">
<defName>Menstruation_FullEstrus</defName>
<label>full estrus</label>
<description>Carriers of this gene will enter full estrus every menstrual cycle, regardless of vagina type.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>-1</biostatMet>
<biostatCpx>1</biostatCpx>
<displayOrderInCategory>25</displayOrderInCategory>
</GeneDef>
<GeneDef Name="Menstruation_Ovulation" Abstract="True">
<displayCategory>Menstruation</displayCategory>
<exclusionTags>
<li>Menstruation_Ovulation</li>
</exclusionTags>
</GeneDef>
<GeneDef ParentName="Menstruation_Ovulation">
<defName>Menstruation_DoubleOvulation</defName>
<label>double ovulation</label>
<description>Carriers of this gene will ovulate twice as many eggs.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>-1</biostatMet>
<displayOrderInCategory>30</displayOrderInCategory>
</GeneDef>
<GeneDef ParentName="Menstruation_Ovulation">
<defName>Menstruation_QuadOvulation</defName>
<label>quadruple ovulation</label>
<description>Carriers of this gene will ovulate four times as many eggs.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>-1</biostatMet>
<displayOrderInCategory>35</displayOrderInCategory>
</GeneDef>
<GeneDef>
<defName>Menstruation_NoBleeding</defName>
<label>no bleeding</label>
<displayCategory>Menstruation</displayCategory>
<description>Carriers of this gene will not bleed at the end of their cycle.</description>
<iconPath>UI/Genes/Placeholder</iconPath>
<biostatMet>1</biostatMet>
<displayOrderInCategory>40</displayOrderInCategory>
</GeneDef>
<!-- Pheromones? -->
</Defs>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<LanguageData>
<Menstruation.label>月經週期</Menstruation.label>
<Menstruation_ShortEggLifetime.label>較短卵細胞壽命</Menstruation_ShortEggLifetime.label>
<Menstruation_ShortEggLifetime.description>未受精卵細胞存活時長僅有原先的3/4</Menstruation_ShortEggLifetime.description>
<Menstruation_DoubleEggLifetime.label>雙倍卵細胞壽命</Menstruation_DoubleEggLifetime.label>
<Menstruation_DoubleEggLifetime.description>未受精卵細胞可存活至原先的2倍之久</Menstruation_DoubleEggLifetime.description>
<Menstruation_QuadEggLifetime.label>四倍卵細胞壽命</Menstruation_QuadEggLifetime.label>
<Menstruation_QuadEggLifetime.description>未受精卵細胞可存活至原先的4倍之久</Menstruation_QuadEggLifetime.description>
<Menstruation_NeverEstrus.label>永不發情</Menstruation_NeverEstrus.label>
<Menstruation_NeverEstrus.description>基因攜帶者永遠不會進入發情期。</Menstruation_NeverEstrus.description>
<Menstruation_FullEstrus.label>始終發情</Menstruation_FullEstrus.label>
<Menstruation_FullEstrus.description>基因攜帶者的每一個月經週期均具備發情期,無論陰道類型為何。</Menstruation_FullEstrus.description>
<Menstruation_DoubleOvulation.label>雙倍排卵</Menstruation_DoubleOvulation.label>
<Menstruation_DoubleOvulation.description>基因攜帶者的子宮可以在每個排卵週期產生雙倍的卵子。</Menstruation_DoubleOvulation.description>
<Menstruation_QuadOvulation.label>四倍排卵</Menstruation_QuadOvulation.label>
<Menstruation_QuadOvulation.description>基因攜帶者的子宮可以在每個排卵週期產生四倍的卵子。</Menstruation_QuadOvulation.description>
<Menstruation_NoBleeding.label>無經血</Menstruation_NoBleeding.label>
<Menstruation_NoBleeding.description>基因攜帶者的子宮內膜不會脫落出血。</Menstruation_NoBleeding.description>
</LanguageData>

View file

@ -8,4 +8,7 @@
<TookContraceptivePill.stages.0.description>總算把這事了結了。</TookContraceptivePill.stages.0.description>
<HateTookContraceptivePill.stages.0.label>吃了避孕藥</HateTookContraceptivePill.stages.0.label>
<HateTookContraceptivePill.stages.0.description>我想要小孩!</HateTookContraceptivePill.stages.0.description>
<!--Auto generated: Thu Jan 5 22:13:15 2023-->
<EggRestorationReceived.stages.0.label>卵母細胞再生術</EggRestorationReceived.stages.0.label>
<EggRestorationReceived.stages.0.description>我可以繼續繁衍一小段時間了!</EggRestorationReceived.stages.0.description>
</LanguageData>

View file

@ -37,7 +37,7 @@
<Option7_Label>月經加速</Option7_Label>
<Option7_Desc>加快月經週期</Option7_Desc>
<Option8_Label>除錯</Option8_Label>
<Option8_Desc>顯示除錯資訊</Option8_Desc>
<Option8_Desc>顯示除錯資訊&#10;啟用時會令「胎兒信息級別」選項調至「全部細節」。</Option8_Desc>
<Option9_Label>子宮狀態</Option9_Label>
<Option9_Desc>在狀態窗口中繪製子宮圖標</Option9_Desc>
<Option10_Label>陰道狀態</Option10_Label>
@ -62,7 +62,6 @@
<Option17_Label>最大雙胞胎數量</Option17_Label>
<Option17_Desc>設置最大雙胞胎數量</Option17_Desc>
<FloatMenu_CleanSelf>清洗陰道</FloatMenu_CleanSelf>
<!--Auto generated: Mon Oct 3 21:49:26 2022-->
<Stage_Menopause>絕經</Stage_Menopause>
<Stage_Anestrus>乏情期</Stage_Anestrus>
@ -98,7 +97,7 @@
<Option21_Label>本模組作用於:</Option21_Label>
<Option21_Desc>這些小人的「RJW月經週期」工具欄對玩家可見。</Option21_Desc>
<Option22_Label>使用進階雜交定義</Option22_Label>
<Option22_Desc>寫RJW和RaceSupport插件的雜交定義。Overrides RJW and RaceSupport's hybrid definition.
<Option22_Desc>寫RJW和RaceSupport插件的雜交定義。Overrides RJW and RaceSupport's hybrid definition.
主導混合擴展決定了首先使用誰的定義。不建議更改此設置。Dominant hybrid extension determines whose definition used first. Not recommended to change this.</Option22_Desc>
<Option23_Label>主導混合擴展Dominant hybrid extension</Option23_Label>
<Option23_Label_1>母本</Option23_Label_1>
@ -111,7 +110,7 @@
<Option_PermanentNippleChange_Desc>乳頭在孕期間的改變會在孕期結束後保留多少?</Option_PermanentNippleChange_Desc>
<Option28_Label>客製化雜交細節</Option28_Label>
<Option28_Tooltip>開啟雜交編輯器
該選項會寫XML文件中的雜交定義。</Option28_Tooltip>
該選項會寫XML文件中的雜交定義。</Option28_Tooltip>
<Option29_Label>允許圖標縮小</Option29_Label>
<Option29_Desc>允許圖標在特殊場合縮小。</Option29_Desc>
<Option30_Label>卵細胞生命期乘數</Option30_Label>
@ -123,7 +122,7 @@
<Option32_Label>擴張力度</Option32_Label>
<Option32_Desc>調節擴張力度。</Option32_Desc>
<Option_EnableGatherCumGizmo_Label>啟用「擠出精液」按鈕</Option_EnableGatherCumGizmo_Label>
<Option_EstrusOverride_Label>令「發情期」機制寫RJW的濫交選項</Option_EstrusOverride_Label>
<Option_EstrusOverride_Label>令「發情期」機制寫RJW的濫交選項</Option_EstrusOverride_Label>
<Option_EstrusOverride_Desc>啟用時處於顯式發情期的小人將會使用以下選項來選定床伴。RJW的原始設定會被忽略。
所有數值與RJW的對應選項相同。</Option_EstrusOverride_Desc>
<Option_EstrusFuckability_Label>發情期床伴最低fuckability</Option_EstrusFuckability_Label>
@ -139,4 +138,13 @@
<CustomHybrid_Title>{0}之雜交</CustomHybrid_Title>
<CustomHybrid_Tooltip>當{0}與{1}產生後代,有{3}的概率生出{2}。
若兩個種族相互間皆存在雜交定義,則以父本的定義為準。</CustomHybrid_Tooltip>
<!--Auto generated: Thu Jan 5 22:13:15 2023-->
<Option_PregnancyFromBaseRJW_Label>使用RJW的簡單懷孕系統</Option_PregnancyFromBaseRJW_Label>
<Option_PregnancyFromMultiplePregnancy_Label>使用本模組的多重懷孕</Option_PregnancyFromMultiplePregnancy_Label>
<Option_PregnancyFromBiotech_Label>使用「生機」(Biotech)追加的懷孕機制</Option_PregnancyFromBiotech_Label>
<Option_EnableDraftedIcon_Label>於「徵召」狀態下仍顯示子宮狀態</Option_EnableDraftedIcon_Label>
<Option_EnableDraftedIcon_Desc>角色處於被徵召狀態時,子宮圖標不予隱藏。</Option_EnableDraftedIcon_Desc>
<CannotNoEggs>沒有卵細胞</CannotNoEggs>
<CannotNoWomb>必須擁有子宮</CannotNoWomb>
<EggRestorationCompleted>{PAWN_labelShort}完成了{PAWN_possessive}卵母細胞再生術(cycle)</EggRestorationCompleted>
</LanguageData>

View file

@ -124,6 +124,8 @@
<Option_PregnancyFromBaseRJW_Label>Use basic RJW pregnancy</Option_PregnancyFromBaseRJW_Label>
<Option_PregnancyFromMultiplePregnancy_Label>Use menstruation multiple pregnancy</Option_PregnancyFromMultiplePregnancy_Label>
<Option_PregnancyFromBiotech_Label>Use Biotech pregnancy</Option_PregnancyFromBiotech_Label>
<Option_EnableBiotechTwins_Label>(EXPERIMENTAL) Enable multiple babies/twins in a single Biotech pregnancy.</Option_EnableBiotechTwins_Label>
<Option_EnableBiotechTwins_Desc>Enabling this option will allow identical and hetero ovular twins with Biotech.&#10;Also allows the hybrid system, but two humanlikes cannot produce an animal.</Option_EnableBiotechTwins_Desc>
<Option_EnableDraftedIcon_Label>Show womb status when drafted</Option_EnableDraftedIcon_Label>
<Option_EnableDraftedIcon_Desc>Draw womb icon for drafted pawns</Option_EnableDraftedIcon_Desc>
<Button_ResetToDefault>Reset to default</Button_ResetToDefault>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Hediff_ASA.label>항정자 항체</Hediff_ASA.label>
<Hediff_ASA.labelNoun>항정자 항체</Hediff_ASA.labelNoun>
<Hediff_ASA.description>항정자 항체. 정자의 생존 시간을 줄입니다.</Hediff_ASA.description>
<Hediff_ASA.labelNounPretty>{0}(은)는 항정자 항체를 가졌습니다.</Hediff_ASA.labelNounPretty>
<Hediff_ForceFertile.label>좋은 임신률</Hediff_ForceFertile.label>
<Hediff_ForceFertile.labelNoun>좋은 임신률</Hediff_ForceFertile.labelNoun>
<Hediff_ForceFertile.description>좋은 임신률</Hediff_ForceFertile.description>
<Hediff_ForceFertile.labelNounPretty>{0}(은)는 좋은 임신률을 가지고 있습니다.</Hediff_ForceFertile.labelNounPretty>
</LanguageData>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Hediff_MenstrualCramp.label>생리통</Hediff_MenstrualCramp.label>
<Hediff_MenstrualCramp.description>생리 주기가 끝날 때 보지에서 출혈이 있습니다.
종종 고통스럽습니다.</Hediff_MenstrualCramp.description>
<Hediff_MenstrualCramp.stages.0.label>불편함</Hediff_MenstrualCramp.stages.0.label>
<Hediff_MenstrualCramp.stages.1.label>짜증남</Hediff_MenstrualCramp.stages.1.label>
<Hediff_MenstrualCramp.stages.2.label>아픔</Hediff_MenstrualCramp.stages.2.label>
<Hediff_MenstrualCramp.stages.3.label>고통스러움</Hediff_MenstrualCramp.stages.3.label>
<Hediff_Estrus.label>발정기</Hediff_Estrus.label>
<Hediff_Estrus.description>자궁이 생리 주기의 가장 비옥한 단계로 접어든 상태입니다. 신체가 임신하기를 갈망함에 따라 성적 흥분과 욕망은 극적으로 증가합니다.
질내 성교의 가능성이 증가하고 잠재적으로 짝짓기 선택의 기준이 낮아집니다.</Hediff_Estrus.description>
<Hediff_Estrus_Concealed.label>발정기(숨김)</Hediff_Estrus_Concealed.label>
<Hediff_Estrus_Concealed.description>자궁이 생리 주기의 가장 비옥한 단계로 접어든 상태입니다. 성적 흥분과 욕망이 약간 증가합니다.
질내 성교의 가능성이 약간 증가합니다.</Hediff_Estrus_Concealed.description>
<Hediff_PainReliever.label>진통제</Hediff_PainReliever.label>
<Hediff_PainReliever.description>생리통(및 기타)의 통증을 완화해 줍니다.</Hediff_PainReliever.description>
<Hediff_Cyclosporine.label>면역 억제제</Hediff_Cyclosporine.label>
<Hediff_Cyclosporine.description>면역 억제제의 영향으로, 감염과 질병을 물리치는 신체의 면역력이 떨어집니다.</Hediff_Cyclosporine.description>
</LanguageData>

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Hediff_MenstrualCramp.label>생리통</Hediff_MenstrualCramp.label>
<Hediff_MenstrualCramp.description>생리중입니다.</Hediff_MenstrualCramp.description>
<Hediff_MenstrualCramp.stages.0.label>불편함</Hediff_MenstrualCramp.stages.0.label>
<Hediff_MenstrualCramp.stages.1.label>짜증남</Hediff_MenstrualCramp.stages.1.label>
<Hediff_MenstrualCramp.stages.2.label>아픔</Hediff_MenstrualCramp.stages.2.label>
<Hediff_MenstrualCramp.stages.3.label>고통스러움</Hediff_MenstrualCramp.stages.3.label>
<Hediff_Estrus.label>발정기</Hediff_Estrus.label>
<Hediff_Estrus.description>발정기입니다.</Hediff_Estrus.description>
<Hediff_Estrus_Concealed.label>발정기(숨김)</Hediff_Estrus_Concealed.label>
<Hediff_Estrus_Concealed.description>발정기입니다.</Hediff_Estrus_Concealed.description>
<Hediff_PainReliever.label>진통제</Hediff_PainReliever.label>
<Hediff_PainReliever.description>약간의 고통을 줄여줍니다.</Hediff_PainReliever.description>
</LanguageData>

View file

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<VaginaWashing.reportString>질세척 하는중</VaginaWashing.reportString>
</LanguageData>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<LactateSelf.reportString>스스로 젖 짜는 중</LactateSelf.reportString>
</LanguageData>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<OpenStatusWindow.label>생리: 상태 창을 엽니다.</OpenStatusWindow.label>
</LanguageData>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Surgery_ExpandAreola.label>유륜확대 수술</Surgery_ExpandAreola.label>
<Surgery_ExpandAreola.description>유륜을 크게만듭니다.</Surgery_ExpandAreola.description>
<Surgery_ExpandAreola.jobString>유륜확대 수술중</Surgery_ExpandAreola.jobString>
<Surgery_ContractAreola.label>유륜축소 수술</Surgery_ContractAreola.label>
<Surgery_ContractAreola.description>유륜을 작게만듭니다.</Surgery_ContractAreola.description>
<Surgery_ContractAreola.jobString>유륜축소 수술중</Surgery_ContractAreola.jobString>
<Surgery_ExpandNipple.label>유두확대 수술</Surgery_ExpandNipple.label>
<Surgery_ExpandNipple.description>유두를 크게만듭니다.</Surgery_ExpandNipple.description>
<Surgery_ExpandNipple.jobString>유두확대 수술중</Surgery_ExpandNipple.jobString>
<Surgery_ContractNipple.label>유두축소 수술</Surgery_ContractNipple.label>
<Surgery_ContractNipple.description>유두를 작게만듭니다.</Surgery_ContractNipple.description>
<Surgery_ContractNipple.jobString>유두축소 수술중</Surgery_ContractNipple.jobString>
</LanguageData>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<LanguageData>
<Surgery_ExpandAreola.label>유륜 확대</Surgery_ExpandAreola.label>
<Surgery_ExpandAreola.description>유륜을 크게 만듭니다.</Surgery_ExpandAreola.description>
<Surgery_ExpandAreola.jobString>유륜 확대 중</Surgery_ExpandAreola.jobString>
<Surgery_ContractAreola.label>유륜 축소</Surgery_ContractAreola.label>
<Surgery_ContractAreola.description>유륜을 작게 만듭니다.</Surgery_ContractAreola.description>
<Surgery_ContractAreola.jobString>유륜 축소 중</Surgery_ContractAreola.jobString>
<Surgery_ExpandNipple.label>유두 확대</Surgery_ExpandNipple.label>
<Surgery_ExpandNipple.description>유두를 크게 만듭니다.</Surgery_ExpandNipple.description>
<Surgery_ExpandNipple.jobString>유두 확대 중</Surgery_ExpandNipple.jobString>
<Surgery_ContractNipple.label>유두 축소</Surgery_ContractNipple.label>
<Surgery_ContractNipple.description>유두를 작게 만듭니다.</Surgery_ContractNipple.description>
<Surgery_ContractNipple.jobString>유두 축소 중</Surgery_ContractNipple.jobString>
<Surgery_DarkenNipple.label>유두 흑화</Surgery_DarkenNipple.label>
<Surgery_DarkenNipple.description>유두를 어둡게 만듭니다.</Surgery_DarkenNipple.description>
<Surgery_DarkenNipple.jobString>유두 흑화 중</Surgery_DarkenNipple.jobString>
<Surgery_LightenNipple.label>유두 미백</Surgery_LightenNipple.label>
<Surgery_LightenNipple.description>유두를 밝게 만듭니다.</Surgery_LightenNipple.description>
<Surgery_LightenNipple.jobString>유두 미백 중</Surgery_LightenNipple.jobString>
</LanguageData>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<AmountofCreampied.label>질내사정</AmountofCreampied.label>
<AmountofCreampied.description>질내사정당한 정액 양</AmountofCreampied.description>
</LanguageData>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<AmountofCreampied.label>질내사정</AmountofCreampied.label>
<AmountofCreampied.description>질내사정당한 정액 양</AmountofCreampied.description>
<AmountofFertilizedEggs.label>수정된 알</AmountofFertilizedEggs.label>
<AmountofFertilizedEggs.description>정자에 의해 수정된 알의 갯수</AmountofFertilizedEggs.description>
</LanguageData>

View file

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<MaxAbsorbable.label>흡수량</MaxAbsorbable.label>
<MaxAbsorbable.description>액체를 흡수할수 있는 정도입니다.</MaxAbsorbable.description>
</LanguageData>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<CameInside.label>질내사정</CameInside.label>
<CameInside.rulePack.rulesStrings.0>tale_noun-&gt;[FUCKER_nameDef](은)는 [FUCKED_nameDef]의 안에 들어갔다.</CameInside.rulePack.rulesStrings.0>
<CameInside.rulePack.rulesStrings.1>image-&gt;[FUCKER_nameFull]의 자지는 [circumstance_group] [FUCKED_nameFull]의 보지 안에 깊숙히 들어갔다.</CameInside.rulePack.rulesStrings.1>
<CameInside.rulePack.rulesStrings.2>image-&gt;[FUCKER_nameFull]의 자지는 [circumstance_group] [FUCKED_nameFull]의 보지 속으로 사라졌다.</CameInside.rulePack.rulesStrings.2>
<CameInside.rulePack.rulesStrings.3>image-&gt;[FUCKED_nameFull]의 보지는 [circumstance_group] [FUCKER_nameFull]의 자지로 꽉 채워졌다.</CameInside.rulePack.rulesStrings.3>
<CameInside.rulePack.rulesStrings.4>image-&gt;[FUCKED_nameFull]의 보지는 [circumstance_group] [FUCKER_nameFull]의 자지를 꽉꽉 물어대었다.</CameInside.rulePack.rulesStrings.4>
<CameInside.rulePack.rulesStrings.5>circumstance_phrase-&gt;[FUCKER_nameDef](이)가 흥분에 이를 갈 때</CameInside.rulePack.rulesStrings.5>
<CameInside.rulePack.rulesStrings.6>circumstance_phrase-&gt;[FUCKER_nameDef](이)가 만족스런 미소를 짓는 동안</CameInside.rulePack.rulesStrings.6>
<CameInside.rulePack.rulesStrings.7>circumstance_phrase-&gt;[FUCKED_nameDef]쾌락에 몸을 떨 때</CameInside.rulePack.rulesStrings.7>
<CameInside.rulePack.rulesStrings.8>circumstance_phrase-&gt;[FUCKER_nameDef](이)가 [FUCKED_nameDef]에게 한 발 쌀 동안</CameInside.rulePack.rulesStrings.8>
<CameInside.rulePack.rulesStrings.9>circumstance_phrase-&gt;[FUCKED_nameDef](이)가 미소로 [FUCKER_nameDef]의 눈을 마주칠 때</CameInside.rulePack.rulesStrings.9>
<CameInside.rulePack.rulesStrings.10>desc_sentence-&gt;[FUCKER_nameDef]의 정액이 [FUCKED_nameDef]의 보지를 넘어 바닥에 넘쳐흘렀다.</CameInside.rulePack.rulesStrings.10>
<CameInside.rulePack.rulesStrings.11>desc_sentence-&gt;[FUCKER_nameDef]의 정자가 [FUCKED_nameDef]의 자궁에서 경주를 벌이고, 끝내 [FUCKED_possessive]의 난자에 도달했다.</CameInside.rulePack.rulesStrings.11>
<CameInside.rulePack.rulesStrings.12>desc_sentence-&gt;[FUCKER_nameDef]의 정액이 [FUCKED_nameDef]의 자궁에 쏟아졌다.</CameInside.rulePack.rulesStrings.12>
<CameInside.rulePack.rulesStrings.13>desc_sentence-&gt;[FUCKED_nameDef]의 자궁은 정액으로 가득찼다.</CameInside.rulePack.rulesStrings.13>
<CameInside.rulePack.rulesStrings.14>desc_sentence-&gt;[FUCKER_nameDef]의 얼굴에 땀이 흘러내렸다.</CameInside.rulePack.rulesStrings.14>
<CameInside.rulePack.rulesStrings.15>desc_sentence-&gt;[FUCKED_nameDef](은)는 심하게 헐떡였다.</CameInside.rulePack.rulesStrings.15>
</LanguageData>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Absorber.label>성기</Absorber.label>
</LanguageData>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Absorber_Tampon.label>탐폰</Absorber_Tampon.label>
<Absorber_Tampon.description>보지에서 나오는 액체를 흡수하는 탐폰입니다.
오래 착용하고 있을 경우 감염이 발생할수도 있습니다.</Absorber_Tampon.description>
<Absorber_Tampon_Dirty.label>더러운 탐폰</Absorber_Tampon_Dirty.label>
<Absorber_Tampon_Dirty.description>사용된 축축한 탐폰입니다.</Absorber_Tampon_Dirty.description>
<Absorber_Pad.label>생리대</Absorber_Pad.label>
<Absorber_Pad.description>보지에서 나오는 액체를 흡수하는 생리대입니다.
흡수량 이상의 액체가 나올경우 샐수있습니다.</Absorber_Pad.description>
<Absorber_Pad_Dirty.label>젖은 생리대</Absorber_Pad_Dirty.label>
<Absorber_Pad_Dirty.description>사용된 축축한 생리대입니다.</Absorber_Pad_Dirty.description>
</LanguageData>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<FilthMixture.label>혼합물</FilthMixture.label>
</LanguageData>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<OvaryRegenerationPill.label>난소 재생약</OvaryRegenerationPill.label>
<OvaryRegenerationPill.description>난소를 재생시켜 평생 배출할 수 있는 난자의 총 양을 복구시킵니다.
난자 소모량이 클수록 효과가 줄어듭니다.
폐경을 회복시키지 않습니다.</OvaryRegenerationPill.description>
<SuperovulationInducingAgent.label>과배란 유도제</SuperovulationInducingAgent.label>
<SuperovulationInducingAgent.description>과배란을 유도하는 약물입니다. 과배란을 유도하여 다음 배란에서 1-4개의 여분의 난자를 배란합니다.
조기폐경을 초래할수도 있습니다.</SuperovulationInducingAgent.description>
<PainReliever.label>진통제</PainReliever.label>
<PainReliever.description>24시간 동안 생리통을 완화시켜 줍니다.
다른 통증에도 효과적입니다.</PainReliever.description>
<Cyclosporine.label>면역 억제제</Cyclosporine.label>
<Cyclosporine.description>면역 억제제.
항정자 항체를 치료할 수 있지만, 24시간 동안 감염과 질병을 퇴치하는 신체의 면역력을 떨어뜨립니다. 복용하면 정자의 생존 시간을 늘립니다.</Cyclosporine.description>
</LanguageData>

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Absorber_Tampon.label>탐폰</Absorber_Tampon.label>
<Absorber_Tampon.description>보지에서 나오는 액체를 흡수하는 탐폰입니다.&#10;오래 착용하고 있을 경우 감염이 발생할수도 있습니다.</Absorber_Tampon.description>
<Absorber_Tampon_Dirty.label>더러운 탐폰</Absorber_Tampon_Dirty.label>
<Absorber_Tampon_Dirty.description>사용된 축축한 탐폰입니다.</Absorber_Tampon_Dirty.description>
<Absorber_Pad.label>생리대</Absorber_Pad.label>
<Absorber_Pad.description>보지에서 나오는 액체를 흡수하는 생리대입니다.&#10;흡수량 이상의 액체가 나올경우 샐수있습니다.</Absorber_Pad.description>
<Absorber_Pad_Dirty.label>젖은 생리대</Absorber_Pad_Dirty.label>
<Absorber_Pad_Dirty.description>사용된 축축한 생리대입니다.</Absorber_Pad_Dirty.description>
<OvaryRegenerationPill.label>난소 재생약</OvaryRegenerationPill.label>
<OvaryRegenerationPill.description>난소를 재생시켜 배출할수있는 난자의 양을 증가시킵니다.&#10;난자 소모량이 클수록 효과가 줄어듭니다.&#10;폐경을 회복시키지 않습니다.</OvaryRegenerationPill.description>
<SuperovulationInducingAgent.label>과배란 유도제</SuperovulationInducingAgent.label>
<SuperovulationInducingAgent.description>과배란을 유도하는 약물입니다.&#10;조기폐경을 초래할수도 있습니다.</SuperovulationInducingAgent.description>
<PainReliever.label>진통제</PainReliever.label>
<PainReliever.description>하루동안 약간의 통증을 줄여줍니다.</PainReliever.description>
<FilthMixture.label>혼합물</FilthMixture.label>
</LanguageData>

View file

@ -1,29 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<LeakingFluids.stages.0.label>가랑이가 축축함</LeakingFluids.stages.0.label>
<LeakingFluids.stages.0.description>찝찝해...</LeakingFluids.stages.0.description>
<CameInsideF.stages.0.label>{0}에게 질내사정당함</CameInsideF.stages.0.label>
<CameInsideF.stages.0.description>임신할까봐 걱정돼...</CameInsideF.stages.0.description>
<LeakingFluids.stages.0.description>이걸 닦아낼 뭔가가 없을까?
</LeakingFluids.stages.0.description>
<HaterCameInsideM.stages.0.label>{0}에게 질내사정함</HaterCameInsideM.stages.0.label>
<HaterCameInsideM.stages.0.description>그 년한테 질싸를 했어!</HaterCameInsideM.stages.0.description>
<CameInsideM.stages.0.label>{0}에게 질내사정함</CameInsideM.stages.0.label>
<CameInsideM.stages.0.description>질싸를하니 기분이 좋네.</CameInsideM.stages.0.description>
<CameInsideFFetish.stages.0.label>{0}에게 질내사정당함</CameInsideFFetish.stages.0.label>
<CameInsideFFetish.stages.0.description>임신하면 좋을 텐데.</CameInsideFFetish.stages.0.description>
<HaterCameInsideF.stages.0.label>{0}에게 질내사정당함</HaterCameInsideF.stages.0.label>
<HaterCameInsideF.stages.0.description>나는 그 새끼의 자식을 임신하고 싶지 않아!</HaterCameInsideF.stages.0.description>
<HaterCameInsideFEstrus.stages.0.label>{0}에게 질내사정당함</HaterCameInsideFEstrus.stages.0.label>
<HaterCameInsideFEstrus.stages.0.description>아. 이런 일을 당해야 하다니...</HaterCameInsideFEstrus.stages.0.description>
<CameInsideFLowFert.stages.0.label>{0}에게 질내사정당함</CameInsideFLowFert.stages.0.label>
<CameInsideFLowFert.stages.0.description>확률은 낮겠지만 임신할까봐 걱정돼...</CameInsideFLowFert.stages.0.description>
<CameInsideFFetish.stages.0.label>{0}에게 질내사정당함</CameInsideFFetish.stages.0.label>
<CameInsideFFetish.stages.0.description>임신할것 같아</CameInsideFFetish.stages.0.description>
<CameInsideF.stages.0.label>{0}에게 질내사정당함</CameInsideF.stages.0.label>
<CameInsideF.stages.0.description>임신할까봐 걱정돼...</CameInsideF.stages.0.description>
<CameInsideFFetishSafe.stages.0.label>{0}에게 질내사정당함</CameInsideFFetishSafe.stages.0.label>
<CameInsideFFetishSafe.stages.0.description>좋았어...</CameInsideFFetishSafe.stages.0.description>
<CameInsideM.stages.0.label>{0}에게 질내사정함</CameInsideM.stages.0.label>
<CameInsideM.stages.0.description>질싸를하니 기분이 좋네</CameInsideM.stages.0.description>
<HaterCameInsideF.stages.0.label>{0}에게 질내사정당함</HaterCameInsideF.stages.0.label>
<HaterCameInsideF.stages.0.description>그새끼의 자식을 임신하고 싶지 않아...</HaterCameInsideF.stages.0.description>
<CameInsideFFetishSafe.stages.0.description>아마 임신 안할꺼야. 게다가 좋기도 했어...</CameInsideFFetishSafe.stages.0.description>
<HaterCameInsideFSafe.stages.0.label>{0}에게 질내사정당함</HaterCameInsideFSafe.stages.0.label>
<HaterCameInsideFSafe.stages.0.description>안전일이였지만 기분나빠</HaterCameInsideFSafe.stages.0.description>
<HaterCameInsideM.stages.0.label>{0}에게 질내사정함</HaterCameInsideM.stages.0.label>
<HaterCameInsideM.stages.0.description>그년한테 질싸를했어</HaterCameInsideM.stages.0.description>
<HaterCameInsideFSafe.stages.0.description>안전일이였지만, 기분 더러워.</HaterCameInsideFSafe.stages.0.description>
<UnwantedPregnancy.stages.0.label>원치않은 임신</UnwantedPregnancy.stages.0.label>
<UnwantedPregnancy.stages.0.description>어떻게 해야하지?...</UnwantedPregnancy.stages.0.description> <HaterCameInsideM.stages.0.description>그년한테 질싸를했어</HaterCameInsideM.stages.0.description>
<UexpectedPregnancyMild.stages.0.label>원치않은 임신</UexpectedPregnancyMild.stages.0.label>
<UexpectedPregnancyMild.stages.0.description>어떻게 해야하지?...</UexpectedPregnancyMild.stages.0.description>
<UnwantedPregnancy.stages.0.description>어떻게 해야하지?...</UnwantedPregnancy.stages.0.description>
<UnwantedPregnancyMild.stages.0.label>원치않은 임신</UnwantedPregnancyMild.stages.0.label>
<UnwantedPregnancyMild.stages.0.description>아이를 가졌어. 하지만 아마 괜찮을꺼야.</UnwantedPregnancyMild.stages.0.description>
<TookContraceptivePill.stages.0.label>피임약 복용</TookContraceptivePill.stages.0.label>
<TookContraceptivePill.stages.0.description>괜찮을거야</TookContraceptivePill.stages.0.description>
<TookContraceptivePill.stages.0.description>이젠 해도 괜찮아.</TookContraceptivePill.stages.0.description>
<HateTookContraptivePill.stages.0.label>피임약 복용</HateTookContraptivePill.stages.0.label>
<HateTookContraptivePill.stages.0.description>임신하고싶어</HateTookContraptivePill.stages.0.description>
<HateTookContraptivePill.stages.0.description>임신하고 싶은데.</HateTookContraptivePill.stages.0.description>
</LanguageData>

View file

@ -1,18 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Mod_Title>RJW Menstruation Cycle</Mod_Title>
<Mod_Title>RJW 생리 주기</Mod_Title>
<Menstrual_Blood>생리혈</Menstrual_Blood>
<Info_noCum>없음</Info_noCum>
<Info_noCum>정액 없음</Info_noCum>
<Stage_Follicular>난포기</Stage_Follicular>
<Stage_Ovulatory>배란</Stage_Ovulatory>
<Stage_Luteal>황체기</Stage_Luteal>
<Stage_Bleeding>생리중</Stage_Bleeding>
<Stage_Pregnant>임신</Stage_Pregnant>
<Stage_Recover>회복기</Stage_Recover>
<Stage_None>없음</Stage_None>
<Stage_None>불임</Stage_None>
<Stage_Climacteric>갱년기</Stage_Climacteric>
<Stage_Menopause>폐경</Stage_Menopause>
<Stage_Anestrus>휴지기</Stage_Anestrus>
<Stage_Follicular_Desc>난소가 배란할 준비를 하고 있습니다. 배란은 이 단계가 끝날 때 발생합니다.</Stage_Follicular_Desc>
<Stage_Follicular_Induced_Desc>난소가 배란할 준비를 하고 있습니다. 정액이 자궁에 들어가면 배란이 일어날 것입니다.</Stage_Follicular_Induced_Desc>
<Stage_Ovulatory_Desc>난소는 자궁 안으로 난자를 방출하고 있습니다.</Stage_Ovulatory_Desc>
<Stage_Luteal_Desc>자궁은 수정란을 받을 준비가 되어 있습니다. 이 단계가 끝나기 전에 착상이 되면 임신이 됩니다.</Stage_Luteal_Desc>
<Stage_Bleeding_Desc>착상에 실패한 난자와 함께 자궁의 내벽이 허물어지고 있습니다.</Stage_Bleeding_Desc>
<Stage_Pregnant_Desc>아기가 자궁 안에서 자라고 있습니다. 정성으로 보살핀다면, 이 세상에 새롭게 태어날 것입니다.</Stage_Pregnant_Desc>
<Stage_Recover_Desc>자궁이 최근 임신에서 회복되고 있습니다.</Stage_Recover_Desc>
<Stage_None_Desc>자궁이 불임으로 임신할 수 없습니다.</Stage_None_Desc>
<Stage_Climacteric_Desc>난소가 거의 고갈되어 생리 주기가 불규칙해졌습니다.</Stage_Climacteric_Desc>
<Stage_Menopause_Desc>난소가 고갈되어 자궁은 더 이상 난자를 품을 수 없습니다.</Stage_Menopause_Desc>
<Stage_Anestrus_Desc>자궁이 번식기가 아닙니다. 조건이 충족되면 주기가 재개됩니다.</Stage_Anestrus_Desc>
<Button_HealthTab>상태창</Button_HealthTab>
<Button_MilkTooltip>모유 짜기</Button_MilkTooltip>
<Dialog_WombInfo01>상태</Dialog_WombInfo01>
@ -24,11 +35,15 @@
<Dialog_WombInfo07>배란</Dialog_WombInfo07>
<Dialog_WombInfo08></Dialog_WombInfo08>
<Dialog_WombInfo09></Dialog_WombInfo09>
<Dialog_DoCleanWomb_Tooltip>양동이에 정액 모으기</Dialog_DoCleanWomb_Tooltip>
<Dialog_DontCleanWomb_Tooltip>자궁의 정액 모으기</Dialog_DontCleanWomb_Tooltip>
<Dialog_FatherUnknown>알려지지 않음</Dialog_FatherUnknown>
<Option1_Label_1>자궁아이콘 활성화</Option1_Label_1>
<Option1_Label_2>건강탭에 버튼 추가</Option1_Label_2>
<Option2_Label>동물주기 활성화</Option2_Label>
<Option2_Desc>동물의 월경주기를 시뮬레이션합니다.&#10;변경한후에 세이브로드가 필요합니다.&#10;not recommended</Option2_Desc>
<Option2_Desc>동물의 월경주기를 시뮬레이션합니다.
변경한후에 세이브로드가 필요합니다.
추천하지 않음</Option2_Desc>
<Option3_Label>착상확률</Option3_Label>
<Option3_Desc>수정란의 착상확률을 설정합니다.</Option3_Desc>
<Option4_Label>수정확률</Option4_Label>
@ -36,10 +51,14 @@
<Option5_Label>시간당 정액배출비율</Option5_Label>
<Option5_Desc>이 비율만큼 매 시간마다 정액이 배출됩니다.</Option5_Desc>
<Option6_Label>시간당 정자 사망비율</Option6_Label>
<Option6_Desc>이 비율만큼 매 시간마다 정자가 사망해 정액이 생식능력을 잃습니다.&#10;정자 예상수명: 정액이 대부분의 생식능력을 잃는 시간입니다.</Option6_Desc>
<Option6_Desc>이 비율만큼 매 시간마다 정자가 사망해 정액이 생식능력을 잃습니다.
정자 예상수명: 정액이 대부분의 생식능력을 잃는 시간입니다.</Option6_Desc>
<Option7_Label>주기 가속</Option7_Label>
<Option7_Desc>월경주기를 더 빠르게합니다.&#10;이 설정은 조기폐경과 난임을 유발할수도 있습니다.&#10;12배속 이하로 설정하는것을 권장합니다.&#10;림월드의 시간배율: x6(default)</Option7_Desc>
<Option8_Label>Debug</Option8_Label>
<Option7_Desc>월경주기를 더 빠르게합니다.
이 설정은 조기폐경과 난임을 유발할수도 있습니다.
12배속 이하로 설정하는것을 권장합니다.
림월드의 시간배율: x6(기본)</Option7_Desc>
<Option8_Label>디버그</Option8_Label>
<Option8_Desc>디버그정보를 보여줍니다.</Option8_Desc>
<Option9_Label>자궁 그림</Option9_Label>
<Option9_Desc>상태창에 자궁그림을 표시합니다.</Option9_Desc>
@ -51,9 +70,13 @@
<Option11_Desc_3>태아에 대한 정보를 표시하지 않지만, 임신한 이후 태아이미지를 표시합니다.</Option11_Desc_3>
<Option11_Desc_4>태아에 대한 어떠한 정보도 표시하지 않습니다.</Option11_Desc_4>
<Option12_Label>폐경기 활성화</Option12_Label>
<Option12_Desc>시간이 지남에따라 불임상태로 만드는 폐경기를 활성화합니다.&#10;수명이 긴 종족을 사용할때 문제가 있으면 이 옵션을 끄세요.&#10;변경한후에 세이브로드가 필요합니다.</Option12_Desc>
<Option12_Desc>시간이 지남에따라 불임상태로 만드는 폐경기를 활성화합니다.
수명이 긴 종족을 사용할때 문제가 있으면 이 옵션을 끄세요.
변경한후에 세이브로드가 필요합니다.</Option12_Desc>
<Option13_Label>다중임신</Option13_Label>
<Option13_Desc>RJW의 기본임신 대신 다중임신을 사용합니다.&#10;임신에 문제가 있다면 이 기능을 끄는것으로 해결될수도 있습니다.&#10;RJW 임신이 활성화 되어야 합니다.</Option13_Desc>
<Option13_Desc>RJW의 기본임신 대신 다중임신을 사용합니다.
임신에 문제가 있다면 이 기능을 끄는것으로 해결될수도 있습니다.
RJW 임신이 활성화 되어야 합니다.</Option13_Desc>
<Option14_Label>이란성 쌍둥이 활성화</Option14_Label>
<Option14_Desc>다수의 난자가 임신으로 이어지게 합니다.</Option14_Desc>
<Option15_Label>일란성 쌍둥이 활성화</Option15_Label>
@ -66,7 +89,9 @@
<Option18_Desc>자궁그림 위에 난자그림를 표시합니다.</Option18_Desc>
<Option19_Label_1>생리양</Option19_Label_1>
<Option19_Label_2>예상되는 총 생리양</Option19_Label_2>
<Option19_Desc>생리혈의 양을 설정합니다.&#10;실제 생리양은 보지에따라 다를수 있습니다.&#10;일반적인 인간 여성의 생리량은 약 20~80ml입니다.</Option19_Desc>
<Option19_Desc>생리혈의 양을 설정합니다.
실제 생리양은 보지에따라 다를수 있습니다.
일반적인 인간 여성의 생리량은 약 20~80ml입니다.</Option19_Desc>
<Option20_Label_1>정착민</Option20_Label_1>
<Option20_Label_2>죄수</Option20_Label_2>
<Option20_Label_3>동맹관계</Option20_Label_3>
@ -75,36 +100,54 @@
<Option21_Label>표시 대상</Option21_Label>
<Option21_Desc>아이콘과 버튼을 표시할 대상입니다.</Option21_Desc>
<Option22_Label>잡종 정의 대체</Option22_Label>
<Option22_Desc>RJW와 RaceSupport의 잡종정의를 대체합니다.&#10;우선순위는 누구의 잡종 정의를 우선으로 사용할지 정합니다. 변경하지 않는것을 추천합니다.</Option22_Desc>
<Option22_Desc>RJW와 RaceSupport의 잡종정의를 대체합니다.
우선순위는 누구의 잡종 정의를 우선으로 사용할지 정합니다. 변경하지 않는것을 추천합니다.</Option22_Desc>
<Option23_Label>우선순위</Option23_Label>
<Option23_Label_1></Option23_Label_1>
<Option23_Label_2></Option23_Label_2>
<Option24_Label>임신후 유두 변화량</Option24_Label>
<Option24_Desc>임신후에 유두가 얼마나 어두워지고 커지는지 설정합니다.</Option24_Desc>
<Option25_Label>유두 영구변화량</Option25_Label>
<Option25_Desc>매번 임신할때마다 유두가 얼마나 영구적으로 어두워지고 커지는지 설정합니다.</Option25_Desc>
<Option26_Label>최대 변화량</Option26_Label>
<Option26_Desc>유두는 이 값 이상으로 변하지 않습니다.</Option26_Desc>
<Option27_Label>유두 변화 속도</Option27_Label>
<Option27_Desc>유두가 얼마나 빨리 변하는지 설정합니다.</Option27_Desc>
<Option_MaxBreastIncrementFactor_Label>임신 중 유방 크기 변화</Option_MaxBreastIncrementFactor_Label>
<Option_MaxBreastIncrementFactor_Desc>임신했을 때 가슴이 얼마나 커질지 설정합니다. 폰에 따라 변화 정도가 다릅니다.</Option_MaxBreastIncrementFactor_Desc>
<Option_MaxNippleIncrementFactor_Label>임신 중 유두 변화</Option_MaxNippleIncrementFactor_Label>
<Option_MaxNippleIncrementFactor_Desc>임신 중에 유두가 얼마나 변할지를 설정합니다.</Option_MaxNippleIncrementFactor_Desc>
<Option_PermanentNippleChange_Label>임신 후 유두 영구 변화</Option_PermanentNippleChange_Label>
<Option_PermanentNippleChange_Desc>임신한 폰의 유두가 임신이 끝난 후 변화된 상태를 유지할 대략적인 양을 설정합니다.</Option_PermanentNippleChange_Desc>
<Option28_Label>잡종 정의 변경하기</Option28_Label>
<Option28_Tooltip>사용자 지정 잡종 편집기를 엽니다.&#10;이 설정은 XML파일의 잡종 정의를 대체합니다.</Option28_Tooltip>
<Option28_Tooltip>사용자 지정 잡종 편집기를 엽니다.
이 설정은 XML파일의 잡종 정의를 대체합니다.</Option28_Tooltip>
<Option29_Label>아이콘 축소 허용</Option29_Label>
<Option29_Desc>아이콘 축소를 허용합니다.</Option29_Desc>
<Option30_Label>난자 수명 배수</Option30_Label>
<Option30_Desc>난자 수명을 늘립니다.&#10;이 설정에 관계없이 황체기가 끝나면 난자는 죽습니다.</Option30_Desc>
<Option30_Desc>난자 수명을 늘립니다.
이 설정에 관계없이 황체기가 끝나면 난자는 죽습니다.</Option30_Desc>
<Option31_Label>출산 이후 보지 변화 활성화</Option31_Label>
<Option31_Desc>출산 이후 보지가 영구적으로 늘어나게 합니다.&#10;만약 이 설정을 다루고있는 다른 모드가 있다면, 이 설정을 끄세요.</Option31_Desc>
<Option31_Desc>출산 이후 보지가 영구적으로 늘어나게 합니다.
만약 이 설정을 다루고있는 다른 모드가 있다면, 이 설정을 끄세요.</Option31_Desc>
<Option32_Label>변화 강도</Option32_Label>
<Option32_Desc>변화 강도를 설정합니다.</Option32_Desc>
<Option_EnableGatherCumGizmo_Label>정액 모으기 아이콘을 보이기</Option_EnableGatherCumGizmo_Label>
<Option_EstrusOverride_Label>발정기 시, RJW 유혹 설정 덮어쓰기</Option_EstrusOverride_Label>
<Option_EstrusOverride_Desc>활성화된 경우 발정기에 있는 폰은 RJW 설정 대신 유혹으로 이 설정을 사용합니다.
모든 설정은 기본적으로 해당 RJW 설정으로 설정됩니다.</Option_EstrusOverride_Desc>
<Option_EstrusFuckability_Label>발정기 시 유혹 최소 섹스 가능성</Option_EstrusFuckability_Label>
<Option_EstrusAttractability_Label>발정기 시 유혹 최소 매력</Option_EstrusAttractability_Label>
<Option_EstrusRelationship_Label>발정기 시 유혹 최소 의견</Option_EstrusRelationship_Label>
<EstimatedCumLifespan>정자 예상수명</EstimatedCumLifespan>
<EstimatedEggLifespan>난자 예상수명</EstimatedEggLifespan>
<FertilityDesc>한시간 안에 수정될 확률: {0}%&#10;수정란이 임신으로 진행될 확률입니다.&#10;흰색 오버레이는 정자가 난자를 수정시킬 확률을 표시하는 것입니다.</FertilityDesc>
<FertilityDesc>한시간 안에 수정될 확률: {0}%
흰색 오버레이는 정자가 난자를 수정시킬 확률을 표시하는 것이고,
분홍색 임신률 그래프는 수정된 난자가 착상되어 임신으로 진행될 확률입니다.
수정이 되더라도 착상에 실패하면 임신하지 않습니다.</FertilityDesc>
<Option_PregnancyFromBaseRJW_Label>RJW 기본 임신 사용</Option_PregnancyFromBaseRJW_Label>
<Option_PregnancyFromMultiplePregnancy_Label>생리 모드 다중 임신 사용</Option_PregnancyFromMultiplePregnancy_Label>
<Option_PregnancyFromBiotech_Label>바이오테크 임신 사용</Option_PregnancyFromBiotech_Label>
<Button_ResetToDefault>기본값으로 재설정</Button_ResetToDefault>
<Gizmo_GatherCum>정액 모으기</Gizmo_GatherCum>
<FloatMenu_CleanSelf>질세척</FloatMenu_CleanSelf>
<CustomHybrid_List_Title>사용자 지정 잡종 편집기</CustomHybrid_List_Title>
<CustomHybrid_Title>{0}의 잡종설정</CustomHybrid_Title>
<CustomHybrid_Tooltip>{0}이(가) {1}와(과) 교미했을 때, {2}이(가) {3}의 확률로 태어납니다.&#10;만약 두 종족이 서로에 대한 잡종 정의가 있을경우 아버지 쪽의 정의가 우선적으로 사용됩니다.</CustomHybrid_Tooltip>
<CustomHybrid_Tooltip>{0}이(가) {1}와(과) 교미했을 때, {2}이(가) {3}의 확률로 태어납니다.
만약 두 종족이 서로에 대한 잡종 정의가 있을경우 아버지 쪽의 정의가 우선적으로 사용됩니다.</CustomHybrid_Tooltip>
<CannotNoEggs>난자 없음</CannotNoEggs>
</LanguageData>

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Patch>
<Operation Class="PatchOperationConditional">
<xpath>/Defs/ThingDef[defName="HumanMilk" or defName="HumanoidMilk"]/graphicData</xpath>
<match Class="PatchOperationReplace">
<xpath>/Defs/ThingDef[defName="HumanMilk" or defName="HumanoidMilk"]/graphicData</xpath>
<value>
<graphicData>
<texPath>Things/Item/Milkbottle</texPath>
<graphicClass>Graphic_StackCount</graphicClass>
</graphicData>
</value>
</match>
</Operation>
</Patch>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>Biotech</li>
</mods>
<match Class="PatchOperationAdd">
<xpath>/Defs/HediffDef[defName="PregnantHuman" or defName="PregnancyLabor" or defName="PregnancyLaborPushing"]/comps</xpath>
<value>
<li>
<compClass>RJW_Menstruation.HediffComp_PregeneratedBabies</compClass>
</li>
</value>
</match>
</Operation>
</Patch>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -1,4 +1,5 @@
using AlienRace;
using System;
using System.Collections.Generic;
using UnityEngine;
using Verse;
@ -11,7 +12,7 @@ namespace RJW_Menstruation
public static bool IsHAR(this Pawn pawn)
{
if (!Configurations.HARActivated) return false;
return pawn?.def is ThingDef_AlienRace;
return GenTypes.GetTypeInAnyAssembly("AlienRace.ThingDef_AlienRace").IsInstanceOfType(pawn?.def);
}
public static void CopyHARProperties(Pawn baby, Pawn original)

View file

@ -55,6 +55,7 @@ namespace RJW_Menstruation
public static float EstrusAttractivenessToHookup = RJWHookupSettings.MinimumAttractivenessToHookup;
public static float EstrusRelationshipToHookup = RJWHookupSettings.MinimumRelationshipToHookup;
public static PregnancyType PregnancySource = PregnancyType.MultiplePregnancy;
public static bool EnableBiotechTwins = false;
public static bool EnableHeteroOvularTwins = true;
public static bool EnableEnzygoticTwins = true;
public static float EnzygoticTwinsChance = EnzygoticTwinsChanceDefault;
@ -89,6 +90,7 @@ namespace RJW_Menstruation
EstrusAttractivenessToHookup = RJWHookupSettings.MinimumAttractivenessToHookup;
EstrusRelationshipToHookup = RJWHookupSettings.MinimumRelationshipToHookup;
EnzygoticTwinsChanceAdjust = EnzygoticTwinsChanceAdjustDefault;
EnableBiotechTwins = false;
EnableEnzygoticTwins = true;
EnableHeteroOvularTwins = true;
PregnancySource = PregnancyType.MultiplePregnancy;
@ -200,6 +202,7 @@ namespace RJW_Menstruation
Scribe_Values.Look(ref EstrusAttractivenessToHookup, "EstrusAttractivenessToHookup", EstrusAttractivenessToHookup, true);
Scribe_Values.Look(ref EstrusRelationshipToHookup, "EstrusRelationshipToHookup", EstrusRelationshipToHookup, true);
Scribe_Values.Look(ref PregnancySource, "PregnancySource", PregnancySource, true);
Scribe_Values.Look(ref EnableBiotechTwins, "EnableBiotechTwins", EnableBiotechTwins, 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);
@ -271,11 +274,12 @@ namespace RJW_Menstruation
public override void DoSettingsWindowContents(Rect inRect)
{
Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
float mainRectHeight = -3f +
float mainRectHeight = 30f +
(Configurations.EnableWombIcon || Configurations.EnableButtonInHT ? 400f : 0f) +
(Configurations.EstrusOverridesHookupSettings ? 144f : 0f) +
// TODO: Also for modified Biotech pregnancies
(Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy ? (Configurations.EnableEnzygoticTwins ? 175f : 75f) : 0f) +
(Configurations.PregnancySource == Configurations.PregnancyType.Biotech ? 75f : 0f) +
(Configurations.PregnancySource == Configurations.PregnancyType.Biotech ? (Configurations.EnableBiotechTwins ? 175f : 75f) : 0f) +
(Configurations.EnableBirthVaginaMorph ? 48f : 0f);
Rect mainRect = new Rect(0f, 0f, inRect.width - 30f, Math.Max(inRect.height + mainRectHeight, 1f));
int Adjust;
@ -435,8 +439,10 @@ namespace RJW_Menstruation
Configurations.PregnancySource = Configurations.PregnancyType.MultiplePregnancy;
if (ModsConfig.BiotechActive && listmain.RadioButton(Translations.Option_PregnancyFromBiotech_Label, Configurations.PregnancySource == Configurations.PregnancyType.Biotech))
Configurations.PregnancySource = Configurations.PregnancyType.Biotech;
// TODO: Also for modified Biotech pregnancy
if (Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy)
if (Configurations.PregnancySource == Configurations.PregnancyType.Biotech)
listmain.CheckboxLabeled(Translations.Option_EnableBiotechTwins_Label, ref Configurations.EnableBiotechTwins, Translations.Option_EnableBiotechTwins_Desc);
if (Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy ||
(Configurations.PregnancySource == Configurations.PregnancyType.Biotech && Configurations.EnableBiotechTwins))
{
float sectionheight = 75f;
if (Configurations.EnableEnzygoticTwins) sectionheight += 100;

View file

@ -365,7 +365,7 @@ namespace RJW_Menstruation
cachedNipple = baseNipple + nippleProgress * nippleChange;
// For some reason, Props can go null when RJW relocates the chest (e.g. some animals), so catch that
cachedColor = Colors.CMYKLerp(Pawn.story?.SkinColor ?? Color.white, (Props?.BlackNippleColor ?? CompProperties_Breast.DefaultBlacknippleColor.ToColor), Alpha);
cachedColor = Colors.CMYKLerp(Utility.SafeSkinColor(Pawn), (Props?.BlackNippleColor ?? CompProperties_Breast.DefaultBlacknippleColor.ToColor), Alpha);
}
public void CopyBreastProperties(HediffComp_Breast original)

View file

@ -75,7 +75,7 @@ namespace RJW_Menstruation
case Stage.Ovulatory:
return true;
case Stage.Luteal:
return IsEggExist && curStageHrs < Props.eggLifespanDays * 24;
return IsEggExist && curStageHrs < EggLifespanHours * 24;
default:
return false;
}
@ -93,7 +93,7 @@ namespace RJW_Menstruation
case Stage.Ovulatory:
return true;
case Stage.Luteal:
return IsEggExist && curStageHrs < Props.eggLifespanDays * 24;
return IsEggExist && curStageHrs < EggLifespanHours * 24;
default:
return false;
}

View file

@ -126,6 +126,11 @@ namespace RJW_Menstruation
// RJW pregnancy, or Biotech pregnancy/labor/laborpushing
protected Hediff pregnancy = null;
protected int eggLifeSpanHours = 48;
protected EstrusLevel estrusLevel = EstrusLevel.Visible;
protected float ovulationFactor = 1f;
protected bool noBleeding = false;
private static readonly SimpleCurve SexFrequencyCurve = new SimpleCurve()
{
new CurvePoint(0.4f,0.05f),
@ -179,6 +184,7 @@ namespace RJW_Menstruation
// Any exceptions in that will have been reported elsewhere in the code by now
avglittersize = 1.0f;
};
avglittersize *= ovulationFactor;
const float yearsBeforeMenopause = 6.0f;
opcache = (int)(RaceCyclesPerYear() *
avglittersize *
@ -470,6 +476,15 @@ namespace RJW_Menstruation
return !eggs.NullOrEmpty();
}
}
public int EggLifespanHours
{
get
{
return eggLifeSpanHours;
}
}
public virtual bool IsDangerDay
{
get
@ -483,7 +498,7 @@ namespace RJW_Menstruation
case Stage.Ovulatory:
return true;
case Stage.Luteal:
return curStageHrs < Props.eggLifespanDays * 24;
return curStageHrs < EggLifespanHours * 24;
default:
return false;
}
@ -606,6 +621,28 @@ namespace RJW_Menstruation
}
}
public void Notify_UpdatedGenes()
{
eggLifeSpanHours = Props.eggLifespanDays * 24;
estrusLevel = Props.concealedEstrus ? EstrusLevel.Concealed : EstrusLevel.Visible;
ovulationFactor = 1f;
noBleeding = false;
if (Pawn.genes == null || !ModsConfig.BiotechActive) return;
if (Pawn.genes.HasGene(VariousDefOf.ShortEggLifetime)) eggLifeSpanHours = eggLifeSpanHours * 3 / 4;
else if (Pawn.genes.HasGene(VariousDefOf.DoubleEggLifetime)) eggLifeSpanHours *= 2;
else if (Pawn.genes.HasGene(VariousDefOf.QuadEggLifetime)) eggLifeSpanHours *= 4;
if (Pawn.genes.HasGene(VariousDefOf.NeverEstrus)) estrusLevel = EstrusLevel.None;
else if (Pawn.genes.HasGene(VariousDefOf.FullEstrus)) estrusLevel = EstrusLevel.Visible;
if (Pawn.genes.HasGene(VariousDefOf.DoubleOvulation)) ovulationFactor = 2f;
else if (Pawn.genes.HasGene(VariousDefOf.QuadOvulation)) ovulationFactor = 4f;
noBleeding = Pawn.genes.HasGene(VariousDefOf.NoBleeding);
}
public bool ShouldSimulate()
{
if (!Configurations.EnableAnimalCycle && Pawn.IsAnimal()) return false;
@ -636,12 +673,12 @@ namespace RJW_Menstruation
if (Pregnancy != null && curStage != Stage.Pregnant)
{
Log.Warning($"{Pawn}'s womb has a pregnancy, but was not in the pregnant stage");
curStage = Stage.Pregnant;
GoNextStage(Stage.Pregnant);
}
BeforeSimulator();
if (pregnancy == null && (Pawn.health.capacities.GetLevel(xxx.reproduction) <= 0 || EggHealth <= 0 || Pawn.SterileGenes())) curStage = Stage.Infertile;
if (pregnancy == null && (Pawn.health.capacities.GetLevel(xxx.reproduction) <= 0 || EggHealth <= 0 || Pawn.SterileGenes())) GoNextStage(Stage.Infertile);
switch (curStage)
{
case Stage.Follicular:
@ -1029,6 +1066,8 @@ namespace RJW_Menstruation
initError = true;
Props = (CompProperties_Menstruation)props;
Notify_UpdatedGenes();
if (Props.infertile)
{
if (cums == null) cums = new List<Cum>();
@ -1101,6 +1140,7 @@ namespace RJW_Menstruation
{
avglittersize = 1.0f;
}
avglittersize *= ovulationFactor;
float fertStartAge = Pawn.RaceProps.lifeStageAges?.Find(stage => stage.def.reproductive)?.minAge ?? 0.0f;
float fertEndAge = Pawn.RaceProps.lifeExpectancy * (Pawn.IsAnimal() ? RJWPregnancySettings.fertility_endage_female_animal : RJWPregnancySettings.fertility_endage_female_humanlike);
@ -1160,7 +1200,7 @@ namespace RJW_Menstruation
case Stage.Ovulatory:
return true;
case Stage.Luteal:
return curStageHrs < Props.eggLifespanDays * 24;
return curStageHrs < EggLifespanHours * 24;
default:
return false;
}
@ -1169,12 +1209,13 @@ namespace RJW_Menstruation
public EstrusLevel GetEstrusLevel()
{
if (!ShouldBeInEstrus()) return EstrusLevel.None;
else return Props.concealedEstrus ? EstrusLevel.Concealed : EstrusLevel.Visible;
else return estrusLevel;
}
public void SetEstrus()
{
Hediff hediff = HediffMaker.MakeHediff(Props.concealedEstrus ? VariousDefOf.Hediff_Estrus_Concealed : VariousDefOf.Hediff_Estrus, Pawn);
if (estrusLevel == EstrusLevel.None) return;
Hediff hediff = HediffMaker.MakeHediff(estrusLevel == EstrusLevel.Concealed ? VariousDefOf.Hediff_Estrus_Concealed : VariousDefOf.Hediff_Estrus, Pawn);
Pawn.health.AddHediff(hediff);
}
@ -1256,8 +1297,19 @@ namespace RJW_Menstruation
if (Configurations.Debug) Log.Message($"Implanting fertilized egg of {Pawn} into {parent}, father {egg.fertilizer}");
if (pregnancy != null)
{
// TODO: Modified Biotech pregnancy
if (Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy && Configurations.EnableHeteroOvularTwins)
if (Configurations.PregnancySource == Configurations.PregnancyType.Biotech && Configurations.EnableBiotechTwins && Configurations.EnableHeteroOvularTwins)
{
if (Configurations.Debug) Log.Message($"Adding to existing Biotech pregnancy {pregnancy}");
HediffComp_PregeneratedBabies comp = pregnancy.TryGetComp<HediffComp_PregeneratedBabies>();
if (comp == null) Log.Warning($"Trying to add Biotech egg to {Pawn}'s pregnancy without a pregenerated baby comp: {pregnancy}");
else
{
comp.AddNewBaby(Pawn, egg.fertilizer);
pregnant = true;
deadeggs.Add(egg);
}
}
else if (Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy && Configurations.EnableHeteroOvularTwins)
{
if (pregnancy is Hediff_MultiplePregnancy h)
{
@ -1299,8 +1351,12 @@ namespace RJW_Menstruation
case Configurations.PregnancyType.Biotech:
if (Configurations.Debug) Log.Message($"Creating new biotech pregnancy");
pregnancy = HediffMaker.MakeHediff(HediffDefOf.PregnantHuman, Pawn);
if(Configurations.EnableBiotechTwins)
pregnancy.TryGetComp<HediffComp_PregeneratedBabies>().AddNewBaby(Pawn, egg.fertilizer);
((Hediff_Pregnant)pregnancy).SetParents(Pawn, egg.fertilizer, PregnancyUtility.GetInheritedGeneSet(egg.fertilizer, Pawn));
Pawn.health.AddHediff(pregnancy);
pregnant = true;
deadeggs.Add(egg);
break;
}
if (pregnancy is Hediff_BasePregnancy rjw_preg)
@ -1320,7 +1376,9 @@ namespace RJW_Menstruation
}
}
if (pregnant && (Configurations.PregnancySource != Configurations.PregnancyType.MultiplePregnancy || !Configurations.EnableHeteroOvularTwins))
if (pregnant &&
(Configurations.PregnancySource != Configurations.PregnancyType.MultiplePregnancy || !Configurations.EnableHeteroOvularTwins) &&
(Configurations.PregnancySource != Configurations.PregnancyType.Biotech || !Configurations.EnableBiotechTwins || !Configurations.EnableHeteroOvularTwins))
{
eggs.Clear();
return true;
@ -1454,25 +1512,27 @@ namespace RJW_Menstruation
protected virtual void OvulatoryAction()
{
estrusflag = false;
int eggnum;
float eggnum;
int ovulated;
try
{
eggnum = Math.Max((int)Rand.ByCurve(Pawn.def.race.litterSizeCurve), 1);
eggnum = Math.Max(Rand.ByCurve(Pawn.def.race.litterSizeCurve), 1f);
}
catch (NullReferenceException)
{
eggnum = 1;
eggnum = 1f;
}
catch (ArgumentException e)
{
Log.Warning($"Invalid litterSizeCurve for {Pawn.def}: {e}");
eggnum = 1;
eggnum = 1f;
}
eggnum += eggstack;
eggnum *= ovulationFactor;
ovulated = (int)eggnum + eggstack;
for (int i = 0; i < eggnum; i++)
eggs.Add(new Egg((int)(Props.eggLifespanDays * 24 / CycleFactor)));
ovarypower -= eggnum;
for (int i = 0; i < ovulated; i++)
eggs.Add(new Egg((int)(EggLifespanHours * 24 / CycleFactor)));
ovarypower -= ovulated;
eggstack = 0;
if (EggHealth <= 0)
@ -1709,7 +1769,7 @@ namespace RJW_Menstruation
protected void GoFollicularOrBleeding()
{
if (Props.bleedingIntervalDays == 0)
if (Props.bleedingIntervalDays == 0 || noBleeding)
{
GoNextStage(Stage.Follicular);
}
@ -1739,7 +1799,7 @@ namespace RJW_Menstruation
return (int)(Props.recoveryIntervalDays * 24 * Rand.Range(0.95f, 1.05f));
case Stage.Pregnant:
return (int)MenstruationUtility.GestationHours(pregnancy);
default: // Often unused
default:
return 1;
}
}

View file

@ -33,7 +33,7 @@ namespace RJW_Menstruation
// Make the cutoff halfway into cycle, just to be sure there isn't a double-cycle the first time
if ((curStage == Stage.Follicular || curStage == Stage.Luteal || curStage == Stage.Bleeding)
&& (averageCycleIntervalHours - hoursToNextCycle) / 2 >= 24 * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed)
curStage = Stage.Anestrus;
GoNextStage(Stage.Anestrus);
}
}
@ -75,14 +75,14 @@ namespace RJW_Menstruation
base.PregnantAction();
if (curStage != Stage.Pregnant)
// Go halfway into the cycle
hoursToNextCycle = (int)(averageCycleIntervalHours * Rand.Range(-cycleVariability, cycleVariability)) / 2;
hoursToNextCycle = (int)(averageCycleIntervalHours * (1 + Rand.Range(-cycleVariability, cycleVariability))) / 2;
}
protected override void AnestrusAction()
{
if (hoursToNextCycle <= 0)
{
hoursToNextCycle = (int)(averageCycleIntervalHours * Rand.Range(-cycleVariability, cycleVariability));
hoursToNextCycle = (int)(averageCycleIntervalHours * (1 + Rand.Range(-cycleVariability, cycleVariability)));
if (IsBreedingSeason()) GoNextStage(Stage.Follicular);
return;
}

View file

@ -0,0 +1,300 @@
using HarmonyLib;
using Mono.Cecil.Cil;
using RimWorld;
using rjw;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using Verse;
namespace RJW_Menstruation
{
public class HediffComp_PregeneratedBabies : HediffComp
{
public List<Pawn> babies;
// Unused, but can't hurt to track
protected Dictionary<Pawn, Pawn> 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();
// Send the babies from this comp to the new one
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<HediffComp_PregeneratedBabies>();
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<HediffComp_PregeneratedBabies>();
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<Pawn>();
PawnKindDef babyPawnKind = PregnancyCommon.BabyPawnKindDecider(mother, father, true);
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,
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<Pawn, Pawn>();
for (int i = 0; i < division; i++)
{
Pawn baby = PawnGenerator.GeneratePawn(request);
if (baby == null) break;
PregnancyCommon.SetupBabyXenotype(mother, father, baby); // Probably redundant with Biotech post-birth xenotyping
baby.Drawer.renderer.graphics.ResolveAllGraphics();
if (division > 1)
{
if (i == 0)
{
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.HairColor = firstbaby.story.HairColor;
baby.story.bodyType = firstbaby.story.bodyType;
baby.story.furDef = firstbaby.story.furDef;
baby.story.skinColorOverride = firstbaby.story.skinColorOverride;
}
if (baby.genes != null)
{
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);
// These get cleared out later, but setting the relations now will help keep track of things.
baby.SetMother(mother);
if (mother != father)
{
if (father.gender != Gender.Female) baby.SetFather(father);
else baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, father);
}
}
}
}
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome))]
public static class ApplyBirthOutcome_PregeneratedBabies_Patch
{
private static Pawn GetPregeneratedBaby(PawnGenerationRequest request, Thing birtherThing)
{
// Don't test for the config set here. We can do it at the functions that call ApplyBirthOutcome
// Easier to work out twins that way
// From e.g. a vat
if (!(birtherThing is Pawn mother) || !xxx.is_human(mother))
return PawnGenerator.GeneratePawn(request);
// No babies found. Could be an unmodified pregnancy
HediffComp_PregeneratedBabies comp = mother.health.hediffSet.GetFirstHediff<Hediff_LaborPushing>()?.TryGetComp<HediffComp_PregeneratedBabies>();
if (comp == null || !comp.HasBaby)
return PawnGenerator.GeneratePawn(request);
Pawn baby = comp.PopBaby();
if (baby == null) return PawnGenerator.GeneratePawn(request); // Shouldn't happen
baby.ageTracker.AgeBiologicalTicks = 0;
baby.ageTracker.AgeChronologicalTicks = 0;
baby.babyNamingDeadline = Find.TickManager.TicksGame + GenDate.TicksPerDay;
if (request.ForceDead) baby.Kill(null, null);
return baby;
}
private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome));
private static readonly int birtherThing = ApplyBirthOutcome.GetParameters().FirstIndexOf(parameter => parameter.Name == "birtherThing" && parameter.ParameterType == typeof(Thing));
private static readonly MethodInfo GeneratePawn = typeof(PawnGenerator).GetMethod(nameof(PawnGenerator.GeneratePawn), new Type[] {typeof (PawnGenerationRequest)});
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (birtherThing < 0) throw new InvalidOperationException("Could not locate index of birtherThing");
if (GeneratePawn == null || GeneratePawn.ReturnType != typeof(Pawn)) throw new InvalidOperationException("GeneratePawn not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(GeneratePawn))
{
yield return new CodeInstruction(OpCodes.Ldarg, birtherThing);
yield return CodeInstruction.Call(typeof(ApplyBirthOutcome_PregeneratedBabies_Patch), nameof(GetPregeneratedBaby));
}
else yield return instruction;
}
}
}
[HarmonyPatch(typeof(Hediff_LaborPushing), nameof(Hediff_LaborPushing.PreRemoved))]
public static class Hediff_LaborPushing_PreRemoved_Patch
{
private static Thing ApplyBirthLoop(OutcomeChance outcome, float quality, Precept_Ritual ritual, List<GeneDef> genes, Pawn geneticMother, Thing birtherThing, Pawn father, Pawn doctor, LordJob_Ritual lordJobRitual, RitualRoleAssignments assignments)
{
if (birtherThing is Pawn mother)
{
HediffComp_PregeneratedBabies comp = mother.health.hediffSet.GetFirstHediff<Hediff_LaborPushing>().TryGetComp<HediffComp_PregeneratedBabies>();
if (comp?.HasBaby ?? false)
{
OutcomeChance thisOutcome = outcome;
Precept_Ritual precept_Ritual = (Precept_Ritual)comp.Pawn.Ideo.GetPrecept(PreceptDefOf.ChildBirth);
float birthQuality = PregnancyUtility.GetBirthQualityFor(mother);
do
{
Pawn baby = comp.babies[0];
Pawn thisFather = baby.GetFather();
if (thisFather == null) thisFather = father;
baby.relations.ClearAllRelations(); // To keep ApplyBirthOutcome from erroring when it tries to set up relations
PregnancyUtility.ApplyBirthOutcome(thisOutcome, quality, ritual, genes, geneticMother, birtherThing, thisFather, doctor, lordJobRitual, assignments);
// No more babies if mom dies halfway through. Unrealistic maybe, but saves a lot of headache in ApplyBirthOutcome
if (mother.health.Dead) break;
thisOutcome = ((RitualOutcomeEffectWorker_ChildBirth)precept_Ritual.outcomeEffect).GetOutcome(birthQuality, null);
} while (comp.HasBaby);
// PreRemoved doesn't use the return value
return null;
}
}
return PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments);
}
private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome),
new Type[] {typeof(OutcomeChance), typeof(float), typeof(Precept_Ritual), typeof(List<GeneDef>), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments)});
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (ApplyBirthOutcome == null || ApplyBirthOutcome.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(ApplyBirthOutcome))
yield return CodeInstruction.Call(typeof(Hediff_LaborPushing_PreRemoved_Patch), nameof(Hediff_LaborPushing_PreRemoved_Patch.ApplyBirthLoop));
else yield return instruction;
}
}
}
[HarmonyPatch(typeof(RitualOutcomeEffectWorker_ChildBirth), nameof (RitualOutcomeEffectWorker_ChildBirth.Apply))]
public static class Ritual_ChildBirth_Apply_Patch
{
private static Thing ApplyBirthLoop(OutcomeChance outcome, float quality, Precept_Ritual ritual, List<GeneDef> genes, Pawn geneticMother, Thing birtherThing, Pawn father, Pawn doctor, LordJob_Ritual lordJobRitual, RitualRoleAssignments assignments)
{
if (birtherThing is Pawn mother)
{
HediffComp_PregeneratedBabies comp = mother.health.hediffSet.GetFirstHediff<Hediff_LaborPushing>().TryGetComp<HediffComp_PregeneratedBabies>();
if (comp?.HasBaby ?? false)
{
// Much the same as the other one
// Don't reroll the outcome every time, I think
// This is all one ritual, so every baby has the same ritual outcome
// I don't think this will add the ritual memory every time?
// Though even if it does, that's probably okay. More babies more memories after all
do
{
Pawn baby = comp.babies[0];
Pawn thisFather = baby.GetFather();
if (thisFather == null) thisFather = father;
baby.relations.ClearAllRelations();
PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, thisFather, doctor, lordJobRitual, assignments);
if (mother.health.Dead) break;
} while (comp.HasBaby);
// The ritual version doesn't use the return value, either
return null;
}
}
return PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments);
}
private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome),
new Type[] { typeof(OutcomeChance), typeof(float), typeof(Precept_Ritual), typeof(List<GeneDef>), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments) });
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (ApplyBirthOutcome == null || ApplyBirthOutcome.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found");
foreach (var instruction in instructions)
{
if (instruction.Calls(ApplyBirthOutcome))
yield return CodeInstruction.Call(typeof(Ritual_ChildBirth_Apply_Patch), nameof(Ritual_ChildBirth_Apply_Patch.ApplyBirthLoop));
else yield return instruction;
}
}
}
// HAR patches ApplyBirthOutcome to produce multiple babies based on the mother's littersize. But the pregenerated babies system already makes multiple babies
// So make it always consider the mother to have one baby
public static class HAR_LitterSize_Undo
{
public static void Postfix(ref int __result, Pawn mother)
{
if (Configurations.PregnancySource != Configurations.PregnancyType.Biotech || !Configurations.EnableBiotechTwins) return;
__result = 0;
return;
}
}
}

View file

@ -73,6 +73,29 @@ namespace RJW_Menstruation
return null;
}
[Obsolete("This method is obsolete and can cause ambiguity. Use GetMenstruationCompFromVagina or GetMenstruationCompFromPregnancy instead.", true)]
public static HediffComp_Menstruation GetMenstruationComp(Hediff hediff)
{
switch (hediff)
{
case Hediff_BasePregnancy rjwPreg:
return rjwPreg.GetMenstruationCompFromPregnancy();
case Hediff_Pregnant vanillaPreg:
return vanillaPreg.GetMenstruationCompFromPregnancy();
case Hediff_Labor vanillaLabor:
return vanillaLabor.GetMenstruationCompFromPregnancy();
case Hediff_LaborPushing vanillaLaborPushing:
return vanillaLaborPushing.GetMenstruationCompFromPregnancy();
case Hediff_PartBaseNatural rjwNatrual:
return rjwNatrual.GetMenstruationCompFromVagina();
case Hediff_PartBaseArtifical rjwArtificial:
return rjwArtificial.GetMenstruationCompFromVagina();
default:
Log.Warning("Obsolete GetMenstruationComp called with unknown hediff. Ensure your submods are up to date.");
return null;
}
}
public static HediffComp_Anus GetAnusComp(this Hediff hediff)
{
if (hediff is Hediff_PartBaseNatural || hediff is Hediff_PartBaseArtifical)
@ -92,13 +115,25 @@ namespace RJW_Menstruation
if (hediff is Hediff_MechanoidPregnancy)
return ContentFinder<Texture2D>.Get(("Womb/Mechanoid_Fluid"), true);
ThingDef babydef = comp.Pawn.def; // TODO: Pregenerated babies
float gestationProgress = comp.StageProgress;
int babycount = hediff is Hediff_BasePregnancy preg ? preg.babies.Count : 1;
if (hediff is Hediff_BasePregnancy h)
ThingDef babydef;
int babycount;
HediffComp_PregeneratedBabies babiescomp = hediff?.TryGetComp<HediffComp_PregeneratedBabies>();
if (hediff is Hediff_BasePregnancy preg)
{
babydef = h.babies?.FirstOrDefault()?.def ?? ThingDefOf.Human;
babydef = preg.babies?.FirstOrDefault()?.def ?? ThingDefOf.Human;
babycount = preg.babies?.Count ?? 1;
}
else if (babiescomp?.HasBaby ?? false)
{
babydef = babiescomp.babies.First().def;
babycount = babiescomp.babies.Count;
}
else
{
babydef = comp.Pawn.def;
babycount = 1;
}
string fetustex = babydef.GetModExtension<PawnDNAModExtension>()?.fetusTexPath ?? "Fetus/Fetus_Default";

View file

@ -13,9 +13,6 @@ namespace RJW_Menstruation
{
protected Dictionary<Pawn, Pawn> enzygoticSiblings = new Dictionary<Pawn, Pawn>(); // Each pawn and who they split from
protected readonly MethodInfo TryGetInheritedXenotype = typeof(PregnancyUtility).GetMethod("TryGetInheritedXenotype", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn), typeof(XenotypeDef).MakeByRefType() }, null );
protected 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<Pawn> 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<Pawn> 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);
@ -167,11 +122,12 @@ namespace RJW_Menstruation
if (ModsConfig.BiotechActive)
{
// Ugly, but it'll have to do
OutcomeChance bestOutcome = RitualOutcomeEffectDefOf.ChildBirth.outcomeChances.Find(chance => chance.positivityIndex == 1);
OutcomeChance bestOutcome = RitualOutcomeEffectDefOf.ChildBirth.BestOutcome;
string label = bestOutcome.label;
string description = bestOutcome.description.Formatted(mother.Named("MOTHER"));
baby.babyNamingDeadline = Find.TickManager.TicksGame + GenDate.TicksPerDay;
ChoiceLetter_BabyBirth choiceLetter_BabyBirth = (ChoiceLetter_BabyBirth)LetterMaker.MakeLetter(
label, description, LetterDefOf.BabyBirth, baby
);
@ -212,65 +168,12 @@ namespace RJW_Menstruation
//baby.story.birthLastName = last_name;
}
protected 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);
}
}
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 +314,7 @@ namespace RJW_Menstruation
allowAddictions: false,
relationWithExtraPawnChanceFactor: 0,
fixedLastName: lastname,
kind: BabyPawnKindDecider(mother, father),
kind: PregnancyCommon.BabyPawnKindDecider(mother, father, false),
//fixedIdeo: mother.Ideo,
forbidAnyTitle: true,
forceNoBackstory: true,
@ -428,31 +331,15 @@ 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);
// HAR and some xenotype mods don't randomize graphics until it's rendered
// So poke it early
baby.Drawer.renderer.graphics.ResolveAllGraphics();
if (division > 1)
{
if (i == 0)
{
if (baby.IsHAR()) // Have HAR determine the first baby's properties
baby.Drawer.renderer.graphics.ResolveAllGraphics();
firstbaby = baby;
request.FixedGender = baby.gender;
request.ForcedEndogenes = baby.genes?.Endogenes.Select(gene => gene.def).ToList();
@ -465,7 +352,10 @@ namespace RJW_Menstruation
{
baby.story.headType = firstbaby.story.headType;
baby.story.hairDef = firstbaby.story.hairDef;
baby.story.HairColor = firstbaby.story.HairColor;
baby.story.bodyType = firstbaby.story.bodyType;
baby.story.furDef = firstbaby.story.furDef;
baby.story.skinColorOverride = firstbaby.story.skinColorOverride;
}
if (baby.genes != null && ModsConfig.BiotechActive)
@ -519,174 +409,6 @@ namespace RJW_Menstruation
return baby;
}
/// <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 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();
}
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<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;
}
/// <summary>
/// Copy from RJW
/// </summary>
@ -746,12 +468,6 @@ namespace RJW_Menstruation
pawn.story.traits.allTraits = selectedTraits;
}
public string DueDate()
{
if (pawn.Tile == -1) return "";
return GenDate.DateFullStringWithHourAt(GenDate.TickGameToAbs((int)p_end_tick), Find.WorldGrid.LongLatOf(pawn.Tile));
}
public override bool TryMergeWith(Hediff other)
{
return false;

View file

@ -4,6 +4,8 @@ using RimWorld;
using Verse;
using System.Collections.Generic;
using System.Reflection;
using System;
using System.Reflection.Emit;
namespace RJW_Menstruation
{
@ -24,8 +26,10 @@ namespace RJW_Menstruation
public static void Postfix(Hediff_Pregnant __instance)
{
HediffComp_Menstruation comp = __instance.GetMenstruationCompFromPregnancy();
if (Configurations.Debug) Log.Message($"{comp.Pawn}'s labor starting, menstruation comp is {comp}");
if (comp == null) return;
comp.Pregnancy = __instance.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PregnancyLabor);
if (Configurations.Debug) Log.Message($"New pregnancy Hediff is {comp.Pregnancy}");
}
}
@ -35,8 +39,10 @@ namespace RJW_Menstruation
public static void PostFix(Hediff_Labor __instance)
{
HediffComp_Menstruation comp = __instance.GetMenstruationCompFromPregnancy();
if (Configurations.Debug) Log.Message($"{comp.Pawn}'s initial labor ending, menstruation comp is {comp}");
if (comp == null) return;
comp.Pregnancy = __instance.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PregnancyLaborPushing);
if (Configurations.Debug) Log.Message($"New pregnancy Hediff is {comp.Pregnancy}");
}
}
@ -46,6 +52,7 @@ namespace RJW_Menstruation
public static void PostFix(Hediff_LaborPushing __instance)
{
HediffComp_Menstruation comp = __instance.GetMenstruationCompFromPregnancy();
if (Configurations.Debug) Log.Message($"{comp.Pawn}'s labor pushing ending, menstruation comp is {comp}");
if (comp == null) return;
comp.Pregnancy = null;
}
@ -111,7 +118,7 @@ namespace RJW_Menstruation
}
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome))]
public class ApplyBirthOutcome_Patch
public class ApplyBirthOutcome_Breast_Patch
{
public static void PostFix(Thing birtherThing)
{
@ -120,9 +127,21 @@ namespace RJW_Menstruation
}
}
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.TryTerminatePregnancy))]
public class TryTerminatePregnancy_Patch
[HarmonyPatch]
public class TerminatePregnancy_Patch
{
public static IEnumerable<MethodBase> TargetMethods()
{
yield return AccessTools.Method(typeof(PregnancyUtility), nameof(PregnancyUtility.TryTerminatePregnancy));
yield return AccessTools.Method(typeof(Recipe_TerminatePregnancy), nameof(Recipe_TerminatePregnancy.ApplyOnPawn));
}
private static PregnancyAttitude? GetAttitude(Hediff pregnancy)
{
if (pregnancy is Hediff_Pregnant preg) return preg.Attitude;
else return null;
}
private static Hediff GetEarliestPregnancy(Pawn pawn)
{
Hediff Earliest_Pregnancy = PregnancyUtility.GetPregnancyHediff(pawn);
@ -136,20 +155,30 @@ namespace RJW_Menstruation
return Earliest_Pregnancy;
}
private static readonly MethodInfo GetPregnancyHediff = AccessTools.Method(typeof(PregnancyUtility), nameof(PregnancyUtility.GetPregnancyHediff), new System.Type[] { typeof(Pawn) });
private static readonly MethodInfo GetPregnancyHediff = AccessTools.Method(typeof(PregnancyUtility), nameof(PregnancyUtility.GetPregnancyHediff), new Type[] { typeof(Pawn) });
private static readonly MethodInfo Get_Attitude = AccessTools.DeclaredPropertyGetter(typeof(Hediff_Pregnant), nameof(Hediff_Pregnant.Attitude));
// Also called for Recipe_TerminatePregnancy.ApplyOnPawn
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (GetPregnancyHediff == null || GetPregnancyHediff.ReturnType != typeof(Hediff)) throw new System.InvalidOperationException("GetPregnancyHediff not found");
if (GetPregnancyHediff == null || GetPregnancyHediff.ReturnType != typeof(Hediff)) throw new InvalidOperationException("GetPregnancyHediff not found");
if (Get_Attitude == null || Nullable.GetUnderlyingType(Get_Attitude.ReturnType) != typeof(PregnancyAttitude)) throw new InvalidOperationException("get_Attitude not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(GetPregnancyHediff))
yield return CodeInstruction.Call(typeof(TryTerminatePregnancy_Patch), nameof(TryTerminatePregnancy_Patch.GetEarliestPregnancy));
yield return CodeInstruction.Call(typeof(TerminatePregnancy_Patch), nameof(TerminatePregnancy_Patch.GetEarliestPregnancy));
// Menstruation pregnancies don't have an attitude, so skip the cast to Hediff_Pregnant and call a version that handles it
else if (instruction.opcode == OpCodes.Castclass && (Type)instruction.operand == typeof(Hediff_Pregnant))
yield return new CodeInstruction(OpCodes.Nop);
else if (instruction.Calls(Get_Attitude))
yield return CodeInstruction.Call(typeof(TerminatePregnancy_Patch), nameof(TerminatePregnancy_Patch.GetAttitude));
else yield return instruction;
}
}
}
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.TryTerminatePregnancy))]
public class PregnancyUtility_TryTerminatePregnancy_Patch
{
public static void Postfix(bool __result, Pawn pawn)
{
if (__result)
@ -168,13 +197,51 @@ namespace RJW_Menstruation
}
}
[HarmonyPatch(typeof(Recipe_TerminatePregnancy), nameof(Recipe_TerminatePregnancy.ApplyOnPawn))]
public class TerminatePregnancy_ApplyOnPawn_Patch
[HarmonyPatch(typeof(Pawn_GeneTracker), "AddGene", new Type[] {typeof(Gene), typeof(bool)})]
public class AddGene_Patch
{
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
public static bool Prefix(ref Gene __result, Gene gene, Pawn ___pawn)
{
return TryTerminatePregnancy_Patch.Transpiler(instructions);
if(VariousDefOf.WombGenes.Contains(gene.def) && !___pawn.GetMenstruationComps().Any())
{
__result = null;
return false;
}
else return true;
}
}
[HarmonyPatch(typeof(Pawn_GeneTracker), "Notify_GenesChanged")]
public class Notify_GenesChanged_Patch
{
public static void Postfix(Pawn_GeneTracker __instance)
{
foreach (HediffComp_Menstruation comp in __instance.pawn.GetMenstruationComps())
comp.Notify_UpdatedGenes();
}
}
//[HarmonyPatch(typeof(ChildcareUtility), nameof(ChildcareUtility.SuckleFromLactatingPawn))]
//public class GreedyConsume_Patch
//{
// private static float ConsumeAndAdjustNipples(HediffComp_Chargeable instance, float desiredCharge)
// {
// // Pulling breast comp every tick might be too much for performance.
// const float averageNippleChangePerTick = 0.0025f / 50000f;
// instance.Pawn.GetBreastComp()?.AdjustNippleProgress(Rand.Range(0.0f, averageNippleChangePerTick * 2) * Configurations.MaxBreastIncrementFactor);
// return instance.GreedyConsume(desiredCharge);
// }
// private static readonly MethodInfo GreedyConsume = AccessTools.Method(typeof(HediffComp_Chargeable), nameof(HediffComp_Chargeable.GreedyConsume), new Type[] { typeof(HediffComp_Chargeable), typeof(float) });
// public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
// {
// if(GreedyConsume == null) throw new InvalidOperationException("GreedyConsume not found");
// foreach (var instruction in instructions)
// {
// if (instruction.Calls(GreedyConsume))
// yield return CodeInstruction.Call(typeof(GreedyConsume_Patch), nameof(GreedyConsume_Patch.ConsumeAndAdjustNipples));
// yield return instruction;
// }
// }
//}
}

View file

@ -48,8 +48,10 @@ namespace RJW_Menstruation
{
description
.AppendFormat("{0}: {1}\n", comp.curStage, comp.curStageHrs);
if (comp.Pregnancy is Hediff_MultiplePregnancy preg) description
.AppendFormat("due: {0}\n", preg.DueDate());
if (comp.Pregnancy is Hediff_BasePregnancy rjwpreg) description
.AppendFormat("due: {0}\n", rjwpreg.DueDate());
else if (comp.Pregnancy is Hediff_Pregnant biopreg) description
.AppendFormat("due: {0}\n", biopreg.DueDate());
description
.AppendFormat("fertcums: {0}\n" +
"ovarypower: {1}\n" +

View file

@ -1,4 +1,5 @@
using HarmonyLib;
using AlienRace;
using HarmonyLib;
using rjw;
using rjw.Modules.Interactions.Internals.Implementation;
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
@ -16,6 +17,11 @@ namespace RJW_Menstruation
{
Harmony har = new Harmony("RJW_Menstruation");
har.PatchAll(Assembly.GetExecutingAssembly());
if (ModsConfig.IsActive("erdelf.HumanoidAlienRaces")) // Don't use the cached in Configurations, it isn't initialized yet
{
har.Patch(GenTypes.GetTypeInAnyAssembly("AlienRace.HarmonyPatches").GetMethod(nameof(AlienRace.HarmonyPatches.BirthOutcomeMultiplier)),
postfix: new HarmonyMethod(typeof(HAR_LitterSize_Undo).GetMethod(nameof(HAR_LitterSize_Undo.Postfix))));
}
InjectIntoRjwInteractionServices();
}

View file

@ -0,0 +1,322 @@
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();
IEnumerable<Pawn> 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<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();
IEnumerable<Pawn> 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();
}
/// <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));
}
}
}

View file

@ -69,12 +69,14 @@
<Compile Include="EstrusPartKindUsageRule.cs" />
<Compile Include="HediffComps\HediffComp_InducedOvulator.cs" />
<Compile Include="HediffComps\HediffComp_PeriodicOvulator.cs" />
<Compile Include="HediffComps\HediffComp_PregeneratedBabies.cs" />
<Compile Include="HediffComps\MenstruationUtility.cs" />
<Compile Include="Hediff_Estrus.cs" />
<Compile Include="IngestionOutcomeDoers.cs" />
<Compile Include="Patch\Biotech_Patch.cs" />
<Compile Include="Patch\GC_Patch.cs" />
<Compile Include="Patch\Gizmo_Patch.cs" />
<Compile Include="PregnancyCommon.cs" />
<Compile Include="Recipe_Surgery.cs" />
<Compile Include="StatParts.cs" />
<Compile Include="UI\Dialog_HybridCustom.cs" />

View file

@ -125,6 +125,8 @@ namespace RJW_Menstruation
public static readonly string Option_PregnancyFromBaseRJW_Label = "Option_PregnancyFromBaseRJW_Label".Translate();
public static readonly string Option_PregnancyFromMultiplePregnancy_Label = "Option_PregnancyFromMultiplePregnancy_Label".Translate();
public static readonly string Option_PregnancyFromBiotech_Label = "Option_PregnancyFromBiotech_Label".Translate();
public static readonly string Option_EnableBiotechTwins_Label = "Option_EnableBiotechTwins_Label".Translate();
public static readonly string Option_EnableBiotechTwins_Desc = "Option_EnableBiotechTwins_Desc".Translate();
public static readonly string Option_EnableDraftedIcon_Label = "Option_EnableDraftedIcon_Label".Translate();
public static readonly string Option_EnableDraftedIcon_Desc = "Option_EnableDraftedIcon_Desc".Translate();

View file

@ -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;
@ -221,19 +221,36 @@ namespace RJW_Menstruation
{
if (p is Hediff_Pregnant hp && hp.Severity < 0.2f) cum = comp.GetCumIcon();
else cum = ContentFinder<Texture2D>.Get("Womb/Empty", true);
// TODO: Pregenerated babies (base on multiplepregnancy)
HediffComp_PregeneratedBabies babiescomp = p.TryGetComp<HediffComp_PregeneratedBabies>();
if (Utility.ShowFetusInfo())
{
string feinfo = PregnancyCommon.GetBabyInfo(babiescomp?.babies);
string fainfo = PregnancyCommon.GetFatherInfo(babiescomp?.babies, babiescomp.Pawn, true) + " "; // Keep all parents known, for now
if (feinfo == "Null") feinfo = "1 " + p.Mother.def.label + " " + Translations.Dialog_WombInfo02;
if (fainfo == "Null")
{
string father = p.Father?.LabelShort ?? Translations.Dialog_FatherUnknown;
fainfo = Translations.Dialog_WombInfo03 + ": " + father + " ";
}
if (feinfo.Length + fainfo.Length > 45)
{
preginfoheight = fontheight + 2;
buttonstyle.alignment = TextAnchor.UpperLeft;
fontstyleright.alignment = TextAnchor.LowerRight;
}
else
{
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;
string father = p.Father?.LabelShort ?? Translations.Dialog_FatherUnknown;
}
GUI.Box(preginfo, "1 " + p.Mother.def.label + " " + Translations.Dialog_WombInfo02, buttonstyle);
GUI.Label(preginfo, Translations.Dialog_WombInfo03 + ": " + father + " ", fontstyleright);
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 cum = ContentFinder<Texture2D>.Get(("Womb/Empty"), true);
@ -377,7 +394,7 @@ namespace RJW_Menstruation
anal = pawn.GetAnalIcon(showOrigin);
GUI.color = new Color(1.00f, 0.47f, 0.47f, 1);
GUI.Box(rect, "", boxstyle);
GUI.color = pawn.story.SkinColor;
GUI.color = Utility.SafeSkinColor(pawn);
//Widgets.DrawTextureFitted(genitalIconRect, anal, 1.0f);
//Widgets.DrawTextureFitted(genitalIconRect, vagina, 1.0f);
GUI.DrawTexture(genitalIconRect, anal, ScaleMode.ScaleToFit);

View file

@ -188,8 +188,8 @@ namespace RJW_Menstruation
return null;
}
}
// TODO: Biotech pregenerated babies
return null;
HediffComp_PregeneratedBabies babiescomp = comp.Pregnancy.TryGetComp<HediffComp_PregeneratedBabies>();
return babiescomp?.babies?.FirstOrDefault();
}
public static void DrawBreastIcon(this Pawn pawn, Rect rect)
@ -209,7 +209,7 @@ namespace RJW_Menstruation
nipple = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Nipple00", false);
areola = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Areola00", false);
GUI.color = pawn.story?.SkinColor ?? Color.white;
GUI.color = SafeSkinColor(pawn);
GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
GUI.color = Color.white;
GUI.DrawTexture(rect, areola, ScaleMode.ScaleToFit);
@ -236,7 +236,7 @@ namespace RJW_Menstruation
breast = ContentFinder<Texture2D>.Get(icon, false);
areola = ContentFinder<Texture2D>.Get(areolaicon, false);
nipple = ContentFinder<Texture2D>.Get(nippleicon, false);
GUI.color = pawn.story.SkinColor;
GUI.color = SafeSkinColor(pawn);
GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
GUI.color = comp.NippleColor;
@ -255,7 +255,7 @@ namespace RJW_Menstruation
nipple = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Nipple00", false);
areola = ContentFinder<Texture2D>.Get("Breasts/Breast_Breast00_Areola00", false);
GUI.color = pawn.story.SkinColor;
GUI.color = SafeSkinColor(pawn);
GUI.DrawTexture(rect, breast, ScaleMode.ScaleToFit);
GUI.color = Color.white;
GUI.DrawTexture(rect, areola, ScaleMode.ScaleToFit);
@ -454,5 +454,18 @@ namespace RJW_Menstruation
if (pawn.IsAnimal() && !Configurations.EnableAnimalCycle) return false;
return true;
}
// Apparently with some mods, even doing pawn.story?.SkinColor can throw a null reference, so we're stuck doing this
public static Color SafeSkinColor(Pawn pawn)
{
try
{
return pawn.story?.SkinColor ?? Color.white;
}
catch (NullReferenceException)
{
return Color.white;
}
}
}
}

View file

@ -44,8 +44,24 @@ namespace RJW_Menstruation
public static readonly RecordDef AmountofCreampied = DefDatabase<RecordDef>.GetNamed("AmountofCreampied");
public static readonly RecordDef AmountofFertilizedEggs = DefDatabase<RecordDef>.GetNamed("AmountofFertilizedEggs");
public static readonly TaleDef TaleCameInside = DefDatabase<TaleDef>.GetNamed("CameInside");
public static readonly GeneDef ShortEggLifetime = DefDatabase<GeneDef>.GetNamed("Menstruation_ShortEggLifetime");
public static readonly GeneDef DoubleEggLifetime = DefDatabase<GeneDef>.GetNamed("Menstruation_DoubleEggLifetime");
public static readonly GeneDef QuadEggLifetime = DefDatabase<GeneDef>.GetNamed("Menstruation_QuadEggLifetime");
public static readonly GeneDef NeverEstrus = DefDatabase<GeneDef>.GetNamed("Menstruation_NeverEstrus");
public static readonly GeneDef FullEstrus = DefDatabase<GeneDef>.GetNamed("Menstruation_FullEstrus");
public static readonly GeneDef DoubleOvulation = DefDatabase<GeneDef>.GetNamed("Menstruation_DoubleOvulation");
public static readonly GeneDef QuadOvulation = DefDatabase<GeneDef>.GetNamed("Menstruation_QuadOvulation");
public static readonly GeneDef NoBleeding = DefDatabase<GeneDef>.GetNamed("Menstruation_NoBleeding");
public static readonly HashSet<GeneDef> WombGenes = new HashSet<GeneDef>() {
ShortEggLifetime,
DoubleEggLifetime,
QuadEggLifetime,
NeverEstrus,
FullEstrus,
DoubleOvulation,
QuadOvulation,
NoBleeding };
private static List<ThingDef> allraces = null;
private static List<PawnKindDef> allkinds = null;

View file

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

View file

@ -1,3 +1,10 @@
Version 1.0.8.6
- Updated Traditional Chinese translation by Hydrogen.
- Fix error when trying to terminate a non-Biotech pregnancy.
- Properly give the opportunity to name a newborn with Biotech and multiple pregnancy.
- Added several menstruation-related genes, with a placeholder graphic for now.
- Added experimental support for twins and hybrids with Biotech pregnancies, disabled by default.
Version 1.0.8.5
- Added biosculpter recipe to restore 1 year's worth of eggs, with icon by DestinyPlayer.
- Vaginal sex with the "avoid pregnancy" relation will (usually) pull out prevent cum from entering the womb if there's a risk of pregnancy.