diff --git a/1.4/Assemblies/RJW_Menstruation.dll b/1.4/Assemblies/RJW_Menstruation.dll
index 325db98..0215954 100644
Binary files a/1.4/Assemblies/RJW_Menstruation.dll and b/1.4/Assemblies/RJW_Menstruation.dll differ
diff --git a/1.4/Defs/GeneDefs/GeneDefs_Menstruation.xml b/1.4/Defs/GeneDefs/GeneDefs_Menstruation.xml
new file mode 100644
index 0000000..d430d3f
--- /dev/null
+++ b/1.4/Defs/GeneDefs/GeneDefs_Menstruation.xml
@@ -0,0 +1,107 @@
+
+
+
+
+ Menstruation
+ menstruation
+ 402
+
+
+
+ Menstruation
+
+ Menstruation_EggLifetime
+
+
+
+
+ Menstruation_ShortEggLifetime
+ short egg lifetime
+ Unfertilized eggs with this gene last three-quarters as long.
+ UI/Genes/Placeholder
+ 1
+ 10
+
+
+
+ Menstruation_DoubleEggLifetime
+ double egg lifetime
+ Unfertilized eggs with this gene last twice as long.
+ UI/Genes/Placeholder
+ -1
+ 12
+
+
+
+ Menstruation_QuadEggLifetime
+ quadrule egg lifetime
+ Eggs with this gene last four times as long.
+ UI/Genes/Placeholder
+ -2
+ 1
+ 16
+
+
+
+ Menstruation
+
+ Menstruation_Estrus
+
+
+
+
+ Menstruation_NeverEstrus
+ never estrus
+ Carriers of this gene will never go into estrus.
+ UI/Genes/Placeholder
+ 1
+ 20
+
+
+
+ Menstruation_FullEstrus
+ full estrus
+ Carriers of this gene will enter full estrus every menstrual cycle, regardless of vagina type.
+ UI/Genes/Placeholder
+ -1
+ 1
+ 25
+
+
+
+ Menstruation
+
+ Menstruation_Ovulation
+
+
+
+
+ Menstruation_DoubleOvulation
+ double ovulation
+ Carriers of this gene will ovulate twice as many eggs.
+ UI/Genes/Placeholder
+ -1
+ 30
+
+
+
+ Menstruation_QuadOvulation
+ quadruple ovulation
+ Carriers of this gene will ovulate four times as many eggs.
+ UI/Genes/Placeholder
+ -1
+ 35
+
+
+
+ Menstruation_NoBleeding
+ no bleeding
+ Menstruation
+ Carriers of this gene will not bleed at the end of their cycle.
+ UI/Genes/Placeholder
+ 1
+ 40
+
+
+
+
\ No newline at end of file
diff --git a/1.4/Languages/ChineseTraditional/DefInjected/GeneDefs/GeneDefs_Menstruation.xml b/1.4/Languages/ChineseTraditional/DefInjected/GeneDefs/GeneDefs_Menstruation.xml
new file mode 100644
index 0000000..377a6b5
--- /dev/null
+++ b/1.4/Languages/ChineseTraditional/DefInjected/GeneDefs/GeneDefs_Menstruation.xml
@@ -0,0 +1,20 @@
+
+
+ 月經週期
+ 較短卵細胞壽命
+ 未受精卵細胞存活時長僅有原先的3/4
+ 雙倍卵細胞壽命
+ 未受精卵細胞可存活至原先的2倍之久
+ 四倍卵細胞壽命
+ 未受精卵細胞可存活至原先的4倍之久
+ 永不發情
+ 基因攜帶者永遠不會進入發情期。
+ 始終發情
+ 基因攜帶者的每一個月經週期均具備發情期,無論陰道類型為何。
+ 雙倍排卵
+ 基因攜帶者的子宮可以在每個排卵週期產生雙倍的卵子。
+ 四倍排卵
+ 基因攜帶者的子宮可以在每個排卵週期產生四倍的卵子。
+ 無經血
+ 基因攜帶者的子宮內膜不會脫落出血。
+
diff --git a/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml b/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml
index 7cd43fc..b1eeb56 100644
--- a/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml
+++ b/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml
@@ -8,4 +8,7 @@
總算把這事了結了。
吃了避孕藥
我想要小孩!
+
+ 卵母細胞再生術
+ 我可以繼續繁衍一小段時間了!
diff --git a/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml b/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml
index 1f4b8e7..c436751 100644
--- a/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml
+++ b/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml
@@ -37,7 +37,7 @@
月經加速
加快月經週期
除錯
- 顯示除錯資訊
+ 顯示除錯資訊
啟用時會令「胎兒信息級別」選項調至「全部細節」。
子宮狀態
在狀態窗口中繪製子宮圖標
陰道狀態
@@ -62,7 +62,6 @@
最大雙胞胎數量
設置最大雙胞胎數量
清洗陰道
-
絕經
乏情期
@@ -98,7 +97,7 @@
本模組作用於:
這些小人的「RJW月經週期」工具欄對玩家可見。
使用進階雜交定義
- 複寫RJW和RaceSupport插件的雜交定義。Overrides RJW and RaceSupport's hybrid definition.
+ 覆寫RJW和RaceSupport插件的雜交定義。Overrides RJW and RaceSupport's hybrid definition.
主導混合擴展決定了首先使用誰的定義。不建議更改此設置。Dominant hybrid extension determines whose definition used first. Not recommended to change this.
主導混合擴展Dominant hybrid extension
母本
@@ -111,7 +110,7 @@
乳頭在孕期間的改變會在孕期結束後保留多少?
客製化雜交細節
開啟雜交編輯器
-該選項會複寫XML文件中的雜交定義。
+該選項會覆寫XML文件中的雜交定義。
允許圖標縮小
允許圖標在特殊場合縮小。
卵細胞生命期乘數
@@ -123,7 +122,7 @@
擴張力度
調節擴張力度。
啟用「擠出精液」按鈕
- 令「發情期」機制複寫RJW的濫交選項
+ 令「發情期」機制覆寫RJW的濫交選項
啟用時,處於顯式發情期的小人將會使用以下選項來選定床伴。RJW的原始設定會被忽略。
所有數值與RJW的對應選項相同。
發情期床伴:最低fuckability
@@ -139,4 +138,13 @@
{0}之雜交
當{0}與{1}產生後代,有{3}的概率生出{2}。
若兩個種族相互間皆存在雜交定義,則以父本的定義為準。
+
+ 使用RJW的簡單懷孕系統
+ 使用本模組的多重懷孕
+ 使用「生機」(Biotech)追加的懷孕機制
+ 於「徵召」狀態下仍顯示子宮狀態
+ 角色處於被徵召狀態時,子宮圖標不予隱藏。
+ 沒有卵細胞
+ 必須擁有子宮
+ {PAWN_labelShort}完成了{PAWN_possessive}卵母細胞再生術(cycle)
diff --git a/1.4/Languages/English/Keyed/RJW_Menstruation.xml b/1.4/Languages/English/Keyed/RJW_Menstruation.xml
index f28203c..3df2d06 100644
--- a/1.4/Languages/English/Keyed/RJW_Menstruation.xml
+++ b/1.4/Languages/English/Keyed/RJW_Menstruation.xml
@@ -124,6 +124,8 @@
Use basic RJW pregnancy
Use menstruation multiple pregnancy
Use Biotech pregnancy
+ (EXPERIMENTAL) Enable multiple babies/twins in a single Biotech pregnancy.
+ Enabling this option will allow identical and hetero ovular twins with Biotech.
Also allows the hybrid system, but two humanlikes cannot produce an animal.
Show womb status when drafted
Draw womb icon for drafted pawns
Reset to default
diff --git a/1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Cum.xml b/1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Cum.xml
new file mode 100644
index 0000000..aa9304d
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Cum.xml
@@ -0,0 +1,11 @@
+
+
+ 항정자 항체
+ 항정자 항체
+ 항정자 항체. 정자의 생존 시간을 줄입니다.
+ {0}(은)는 항정자 항체를 가졌습니다.
+ 좋은 임신률
+ 좋은 임신률
+ 좋은 임신률
+ {0}(은)는 좋은 임신률을 가지고 있습니다.
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Menstruation.xml b/1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Menstruation.xml
new file mode 100644
index 0000000..8ff5c76
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/HediffDef/Hediffs_Menstruation.xml
@@ -0,0 +1,20 @@
+
+
+ 생리통
+ 생리 주기가 끝날 때 보지에서 출혈이 있습니다.
+ 종종 고통스럽습니다.
+ 불편함
+ 짜증남
+ 아픔
+ 고통스러움
+ 발정기
+ 자궁이 생리 주기의 가장 비옥한 단계로 접어든 상태입니다. 신체가 임신하기를 갈망함에 따라 성적 흥분과 욕망은 극적으로 증가합니다.
+ 질내 성교의 가능성이 증가하고 잠재적으로 짝짓기 선택의 기준이 낮아집니다.
+ 발정기(숨김)
+ 자궁이 생리 주기의 가장 비옥한 단계로 접어든 상태입니다. 성적 흥분과 욕망이 약간 증가합니다.
+ 질내 성교의 가능성이 약간 증가합니다.
+ 진통제
+ 생리통(및 기타)의 통증을 완화해 줍니다.
+ 면역 억제제
+ 면역 억제제의 영향으로, 감염과 질병을 물리치는 신체의 면역력이 떨어집니다.
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/HediffDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/HediffDef/RJWMenstruation.xml
deleted file mode 100644
index 0b9539a..0000000
--- a/1.4/Languages/Korean/DefInjected/HediffDef/RJWMenstruation.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
- 생리통
- 생리중입니다.
- 불편함
- 짜증남
- 아픔
- 고통스러움
- 발정기
- 발정기입니다.
- 발정기(숨김)
- 발정기입니다.
- 진통제
- 약간의 고통을 줄여줍니다.
-
-
-
-
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/JobDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/JobDef/Jobs_CleanSelf.xml
similarity index 59%
rename from 1.4/Languages/Korean/DefInjected/JobDef/RJWMenstruation.xml
rename to 1.4/Languages/Korean/DefInjected/JobDef/Jobs_CleanSelf.xml
index 67ae283..797f994 100644
--- a/1.4/Languages/Korean/DefInjected/JobDef/RJWMenstruation.xml
+++ b/1.4/Languages/Korean/DefInjected/JobDef/Jobs_CleanSelf.xml
@@ -1,7 +1,4 @@
-
+
질세척 하는중
-
-
-
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/JobDef/Jobs_MilkSelf.xml b/1.4/Languages/Korean/DefInjected/JobDef/Jobs_MilkSelf.xml
new file mode 100644
index 0000000..8a21fd6
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/JobDef/Jobs_MilkSelf.xml
@@ -0,0 +1,4 @@
+
+
+ 스스로 젖 짜는 중
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/KeyBinding/KeyBindings_Menstruation.xml b/1.4/Languages/Korean/DefInjected/KeyBinding/KeyBindings_Menstruation.xml
new file mode 100644
index 0000000..8415670
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/KeyBinding/KeyBindings_Menstruation.xml
@@ -0,0 +1,4 @@
+
+
+ 생리: 상태 창을 엽니다.
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/RecipeDef/BreastSurgeries.xml b/1.4/Languages/Korean/DefInjected/RecipeDef/BreastSurgeries.xml
deleted file mode 100644
index 8c501f4..0000000
--- a/1.4/Languages/Korean/DefInjected/RecipeDef/BreastSurgeries.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- 유륜확대 수술
- 유륜을 크게만듭니다.
- 유륜확대 수술중
- 유륜축소 수술
- 유륜을 작게만듭니다.
- 유륜축소 수술중
- 유두확대 수술
- 유두를 크게만듭니다.
- 유두확대 수술중
- 유두축소 수술
- 유두를 작게만듭니다.
- 유두축소 수술중
-
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/RecipeDef/Recipes_Surgery_Breast.xml b/1.4/Languages/Korean/DefInjected/RecipeDef/Recipes_Surgery_Breast.xml
new file mode 100644
index 0000000..4c6cb9d
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/RecipeDef/Recipes_Surgery_Breast.xml
@@ -0,0 +1,21 @@
+
+
+ 유륜 확대
+ 유륜을 크게 만듭니다.
+ 유륜 확대 중
+ 유륜 축소
+ 유륜을 작게 만듭니다.
+ 유륜 축소 중
+ 유두 확대
+ 유두를 크게 만듭니다.
+ 유두 확대 중
+ 유두 축소
+ 유두를 작게 만듭니다.
+ 유두 축소 중
+ 유두 흑화
+ 유두를 어둡게 만듭니다.
+ 유두 흑화 중
+ 유두 미백
+ 유두를 밝게 만듭니다.
+ 유두 미백 중
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/RecordDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/RecordDef/RJWMenstruation.xml
deleted file mode 100644
index b807e13..0000000
--- a/1.4/Languages/Korean/DefInjected/RecordDef/RJWMenstruation.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- 질내사정
- 질내사정당한 정액 양
-
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/RecordDef/Records_Womb.xml b/1.4/Languages/Korean/DefInjected/RecordDef/Records_Womb.xml
new file mode 100644
index 0000000..6831206
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/RecordDef/Records_Womb.xml
@@ -0,0 +1,7 @@
+
+
+ 질내사정
+ 질내사정당한 정액 양
+ 수정된 알
+ 정자에 의해 수정된 알의 갯수
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/StatDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/StatDef/Stats_Absorber.xml
similarity index 73%
rename from 1.4/Languages/Korean/DefInjected/StatDef/RJWMenstruation.xml
rename to 1.4/Languages/Korean/DefInjected/StatDef/Stats_Absorber.xml
index f92112e..52f4854 100644
--- a/1.4/Languages/Korean/DefInjected/StatDef/RJWMenstruation.xml
+++ b/1.4/Languages/Korean/DefInjected/StatDef/Stats_Absorber.xml
@@ -1,7 +1,5 @@
-
+
흡수량
액체를 흡수할수 있는 정도입니다.
-
-
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/TaleDef/Tales_Cum.xml b/1.4/Languages/Korean/DefInjected/TaleDef/Tales_Cum.xml
new file mode 100644
index 0000000..9709f39
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/TaleDef/Tales_Cum.xml
@@ -0,0 +1,20 @@
+
+
+ 질내사정
+ tale_noun->[FUCKER_nameDef](은)는 [FUCKED_nameDef]의 안에 들어갔다.
+ image->[FUCKER_nameFull]의 자지는 [circumstance_group] [FUCKED_nameFull]의 보지 안에 깊숙히 들어갔다.
+ image->[FUCKER_nameFull]의 자지는 [circumstance_group] [FUCKED_nameFull]의 보지 속으로 사라졌다.
+ image->[FUCKED_nameFull]의 보지는 [circumstance_group] [FUCKER_nameFull]의 자지로 꽉 채워졌다.
+ image->[FUCKED_nameFull]의 보지는 [circumstance_group] [FUCKER_nameFull]의 자지를 꽉꽉 물어대었다.
+ circumstance_phrase->[FUCKER_nameDef](이)가 흥분에 이를 갈 때
+ circumstance_phrase->[FUCKER_nameDef](이)가 만족스런 미소를 짓는 동안
+ circumstance_phrase->[FUCKED_nameDef]쾌락에 몸을 떨 때
+ circumstance_phrase->[FUCKER_nameDef](이)가 [FUCKED_nameDef]에게 한 발 쌀 동안
+ circumstance_phrase->[FUCKED_nameDef](이)가 미소로 [FUCKER_nameDef]의 눈을 마주칠 때
+ desc_sentence->[FUCKER_nameDef]의 정액이 [FUCKED_nameDef]의 보지를 넘어 바닥에 넘쳐흘렀다.
+ desc_sentence->[FUCKER_nameDef]의 정자가 [FUCKED_nameDef]의 자궁에서 경주를 벌이고, 끝내 [FUCKED_possessive]의 난자에 도달했다.
+ desc_sentence->[FUCKER_nameDef]의 정액이 [FUCKED_nameDef]의 자궁에 쏟아졌다.
+ desc_sentence->[FUCKED_nameDef]의 자궁은 정액으로 가득찼다.
+ desc_sentence->[FUCKER_nameDef]의 얼굴에 땀이 흘러내렸다.
+ desc_sentence->[FUCKED_nameDef](은)는 심하게 헐떡였다.
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/ApparelLayerDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/ThingDef/ApparelLayerDefs_Absorber.xml
similarity index 50%
rename from 1.4/Languages/Korean/DefInjected/ApparelLayerDef/RJWMenstruation.xml
rename to 1.4/Languages/Korean/DefInjected/ThingDef/ApparelLayerDefs_Absorber.xml
index 9c687e3..771e108 100644
--- a/1.4/Languages/Korean/DefInjected/ApparelLayerDef/RJWMenstruation.xml
+++ b/1.4/Languages/Korean/DefInjected/ThingDef/ApparelLayerDefs_Absorber.xml
@@ -1,4 +1,4 @@
-
+
성기
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/ThingDef/Apparel_Absorbers.xml b/1.4/Languages/Korean/DefInjected/ThingDef/Apparel_Absorbers.xml
new file mode 100644
index 0000000..e568485
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/ThingDef/Apparel_Absorbers.xml
@@ -0,0 +1,13 @@
+
+
+ 탐폰
+ 보지에서 나오는 액체를 흡수하는 탐폰입니다.
+오래 착용하고 있을 경우 감염이 발생할수도 있습니다.
+ 더러운 탐폰
+ 사용된 축축한 탐폰입니다.
+ 생리대
+ 보지에서 나오는 액체를 흡수하는 생리대입니다.
+흡수량 이상의 액체가 나올경우 샐수있습니다.
+ 젖은 생리대
+ 사용된 축축한 생리대입니다.
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/ThingDef/Filth_Mixture.xml b/1.4/Languages/Korean/DefInjected/ThingDef/Filth_Mixture.xml
new file mode 100644
index 0000000..477650e
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/ThingDef/Filth_Mixture.xml
@@ -0,0 +1,4 @@
+
+
+ 혼합물
+
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/ThingDef/Pills_Menstruation.xml b/1.4/Languages/Korean/DefInjected/ThingDef/Pills_Menstruation.xml
new file mode 100644
index 0000000..5f788e0
--- /dev/null
+++ b/1.4/Languages/Korean/DefInjected/ThingDef/Pills_Menstruation.xml
@@ -0,0 +1,17 @@
+
+
+ 난소 재생약
+ 난소를 재생시켜 평생 배출할 수 있는 난자의 총 양을 복구시킵니다.
+난자 소모량이 클수록 효과가 줄어듭니다.
+폐경을 회복시키지 않습니다.
+ 과배란 유도제
+ 과배란을 유도하는 약물입니다. 과배란을 유도하여 다음 배란에서 1-4개의 여분의 난자를 배란합니다.
+조기폐경을 초래할수도 있습니다.
+ 진통제
+ 24시간 동안 생리통을 완화시켜 줍니다.
+
+다른 통증에도 효과적입니다.
+ 면역 억제제
+ 면역 억제제.
+항정자 항체를 치료할 수 있지만, 24시간 동안 감염과 질병을 퇴치하는 신체의 면역력을 떨어뜨립니다. 복용하면 정자의 생존 시간을 늘립니다.
+
diff --git a/1.4/Languages/Korean/DefInjected/ThingDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/ThingDef/RJWMenstruation.xml
deleted file mode 100644
index c48a975..0000000
--- a/1.4/Languages/Korean/DefInjected/ThingDef/RJWMenstruation.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- 탐폰
- 보지에서 나오는 액체를 흡수하는 탐폰입니다.
오래 착용하고 있을 경우 감염이 발생할수도 있습니다.
- 더러운 탐폰
- 사용된 축축한 탐폰입니다.
- 생리대
- 보지에서 나오는 액체를 흡수하는 생리대입니다.
흡수량 이상의 액체가 나올경우 샐수있습니다.
- 젖은 생리대
- 사용된 축축한 생리대입니다.
- 난소 재생약
- 난소를 재생시켜 배출할수있는 난자의 양을 증가시킵니다.
난자 소모량이 클수록 효과가 줄어듭니다.
폐경을 회복시키지 않습니다.
- 과배란 유도제
- 과배란을 유도하는 약물입니다.
조기폐경을 초래할수도 있습니다.
- 진통제
- 하루동안 약간의 통증을 줄여줍니다.
- 혼합물
-
-
-
\ No newline at end of file
diff --git a/1.4/Languages/Korean/DefInjected/ThoughtDef/RJWMenstruation.xml b/1.4/Languages/Korean/DefInjected/ThoughtDef/Thoughts_sex.xml
similarity index 50%
rename from 1.4/Languages/Korean/DefInjected/ThoughtDef/RJWMenstruation.xml
rename to 1.4/Languages/Korean/DefInjected/ThoughtDef/Thoughts_sex.xml
index 9509437..6d817ee 100644
--- a/1.4/Languages/Korean/DefInjected/ThoughtDef/RJWMenstruation.xml
+++ b/1.4/Languages/Korean/DefInjected/ThoughtDef/Thoughts_sex.xml
@@ -1,29 +1,32 @@
-
+
가랑이가 축축함
- 찝찝해...
- {0}에게 질내사정당함
- 임신할까봐 걱정돼...
+ 이걸 닦아낼 뭔가가 없을까?
+
+ {0}에게 질내사정함
+ 그 년한테 질싸를 했어!
+ {0}에게 질내사정함
+ 질싸를하니 기분이 좋네.
+ {0}에게 질내사정당함
+ 임신하면 좋을 텐데.
+ {0}에게 질내사정당함
+ 나는 그 새끼의 자식을 임신하고 싶지 않아!
+ {0}에게 질내사정당함
+ 아. 이런 일을 당해야 하다니...
{0}에게 질내사정당함
확률은 낮겠지만 임신할까봐 걱정돼...
- {0}에게 질내사정당함
- 임신할것 같아
+ {0}에게 질내사정당함
+ 임신할까봐 걱정돼...
{0}에게 질내사정당함
- 좋았어...
- {0}에게 질내사정함
- 질싸를하니 기분이 좋네
- {0}에게 질내사정당함
- 그새끼의 자식을 임신하고 싶지 않아...
+ 아마 임신 안할꺼야. 게다가 좋기도 했어...
{0}에게 질내사정당함
- 안전일이였지만 기분나빠
- {0}에게 질내사정함
- 그년한테 질싸를했어
+ 안전일이였지만, 기분 더러워.
원치않은 임신
- 어떻게 해야하지?... 그년한테 질싸를했어
- 원치않은 임신
- 어떻게 해야하지?...
+ 어떻게 해야하지?...
+ 원치않은 임신
+ 아이를 가졌어. 하지만 아마 괜찮을꺼야.
피임약 복용
- 괜찮을거야
+ 이젠 해도 괜찮아.
피임약 복용
- 임신하고싶어
+ 임신하고 싶은데.
\ No newline at end of file
diff --git a/1.4/Languages/Korean/Keyed/RJW_Menstruation.xml b/1.4/Languages/Korean/Keyed/RJW_Menstruation.xml
index 829fcf5..1a80cfd 100644
--- a/1.4/Languages/Korean/Keyed/RJW_Menstruation.xml
+++ b/1.4/Languages/Korean/Keyed/RJW_Menstruation.xml
@@ -1,18 +1,29 @@
-
+
- RJW Menstruation Cycle
-
+ RJW 생리 주기
생리혈
- 없음
+ 정액 없음
난포기
- 배란
+ 배란
황체기
생리중
임신
회복기
- 없음
+ 불임
갱년기
+ 폐경
휴지기
+ 난소가 배란할 준비를 하고 있습니다. 배란은 이 단계가 끝날 때 발생합니다.
+ 난소가 배란할 준비를 하고 있습니다. 정액이 자궁에 들어가면 배란이 일어날 것입니다.
+ 난소는 자궁 안으로 난자를 방출하고 있습니다.
+ 자궁은 수정란을 받을 준비가 되어 있습니다. 이 단계가 끝나기 전에 착상이 되면 임신이 됩니다.
+ 착상에 실패한 난자와 함께 자궁의 내벽이 허물어지고 있습니다.
+ 아기가 자궁 안에서 자라고 있습니다. 정성으로 보살핀다면, 이 세상에 새롭게 태어날 것입니다.
+ 자궁이 최근 임신에서 회복되고 있습니다.
+ 자궁이 불임으로 임신할 수 없습니다.
+ 난소가 거의 고갈되어 생리 주기가 불규칙해졌습니다.
+ 난소가 고갈되어 자궁은 더 이상 난자를 품을 수 없습니다.
+ 자궁이 번식기가 아닙니다. 조건이 충족되면 주기가 재개됩니다.
상태창
모유 짜기
상태
@@ -24,11 +35,15 @@
배란
-
+ 양동이에 정액 모으기
+ 자궁의 정액 모으기
+ 알려지지 않음
자궁아이콘 활성화
건강탭에 버튼 추가
동물주기 활성화
- 동물의 월경주기를 시뮬레이션합니다.
변경한후에 세이브로드가 필요합니다.
not recommended
+ 동물의 월경주기를 시뮬레이션합니다.
+변경한후에 세이브로드가 필요합니다.
+추천하지 않음
착상확률
수정란의 착상확률을 설정합니다.
수정확률
@@ -36,10 +51,14 @@
시간당 정액배출비율
이 비율만큼 매 시간마다 정액이 배출됩니다.
시간당 정자 사망비율
- 이 비율만큼 매 시간마다 정자가 사망해 정액이 생식능력을 잃습니다.
정자 예상수명: 정액이 대부분의 생식능력을 잃는 시간입니다.
+ 이 비율만큼 매 시간마다 정자가 사망해 정액이 생식능력을 잃습니다.
+정자 예상수명: 정액이 대부분의 생식능력을 잃는 시간입니다.
주기 가속
- 월경주기를 더 빠르게합니다.
이 설정은 조기폐경과 난임을 유발할수도 있습니다.
12배속 이하로 설정하는것을 권장합니다.
림월드의 시간배율: x6(default)
- Debug
+ 월경주기를 더 빠르게합니다.
+이 설정은 조기폐경과 난임을 유발할수도 있습니다.
+12배속 이하로 설정하는것을 권장합니다.
+림월드의 시간배율: x6(기본)
+ 디버그
디버그정보를 보여줍니다.
자궁 그림
상태창에 자궁그림을 표시합니다.
@@ -51,9 +70,13 @@
태아에 대한 정보를 표시하지 않지만, 임신한 이후 태아이미지를 표시합니다.
태아에 대한 어떠한 정보도 표시하지 않습니다.
폐경기 활성화
- 시간이 지남에따라 불임상태로 만드는 폐경기를 활성화합니다.
수명이 긴 종족을 사용할때 문제가 있으면 이 옵션을 끄세요.
변경한후에 세이브로드가 필요합니다.
+ 시간이 지남에따라 불임상태로 만드는 폐경기를 활성화합니다.
+수명이 긴 종족을 사용할때 문제가 있으면 이 옵션을 끄세요.
+변경한후에 세이브로드가 필요합니다.
다중임신
- RJW의 기본임신 대신 다중임신을 사용합니다.
임신에 문제가 있다면 이 기능을 끄는것으로 해결될수도 있습니다.
RJW 임신이 활성화 되어야 합니다.
+ RJW의 기본임신 대신 다중임신을 사용합니다.
+임신에 문제가 있다면 이 기능을 끄는것으로 해결될수도 있습니다.
+RJW 임신이 활성화 되어야 합니다.
이란성 쌍둥이 활성화
다수의 난자가 임신으로 이어지게 합니다.
일란성 쌍둥이 활성화
@@ -66,7 +89,9 @@
자궁그림 위에 난자그림를 표시합니다.
생리양
예상되는 총 생리양
- 생리혈의 양을 설정합니다.
실제 생리양은 보지에따라 다를수 있습니다.
일반적인 인간 여성의 생리량은 약 20~80ml입니다.
+ 생리혈의 양을 설정합니다.
+실제 생리양은 보지에따라 다를수 있습니다.
+일반적인 인간 여성의 생리량은 약 20~80ml입니다.
정착민
죄수
동맹관계
@@ -75,36 +100,54 @@
표시 대상
아이콘과 버튼을 표시할 대상입니다.
잡종 정의 대체
- RJW와 RaceSupport의 잡종정의를 대체합니다.
우선순위는 누구의 잡종 정의를 우선으로 사용할지 정합니다. 변경하지 않는것을 추천합니다.
+ RJW와 RaceSupport의 잡종정의를 대체합니다.
+우선순위는 누구의 잡종 정의를 우선으로 사용할지 정합니다. 변경하지 않는것을 추천합니다.
우선순위
모
부
- 임신후 유두 변화량
- 임신후에 유두가 얼마나 어두워지고 커지는지 설정합니다.
- 유두 영구변화량
- 매번 임신할때마다 유두가 얼마나 영구적으로 어두워지고 커지는지 설정합니다.
- 최대 변화량
- 유두는 이 값 이상으로 변하지 않습니다.
- 유두 변화 속도
- 유두가 얼마나 빨리 변하는지 설정합니다.
+ 임신 중 유방 크기 변화
+ 임신했을 때 가슴이 얼마나 커질지 설정합니다. 폰에 따라 변화 정도가 다릅니다.
+ 임신 중 유두 변화
+ 임신 중에 유두가 얼마나 변할지를 설정합니다.
+ 임신 후 유두 영구 변화
+ 임신한 폰의 유두가 임신이 끝난 후 변화된 상태를 유지할 대략적인 양을 설정합니다.
잡종 정의 변경하기
- 사용자 지정 잡종 편집기를 엽니다.
이 설정은 XML파일의 잡종 정의를 대체합니다.
+ 사용자 지정 잡종 편집기를 엽니다.
+이 설정은 XML파일의 잡종 정의를 대체합니다.
아이콘 축소 허용
아이콘 축소를 허용합니다.
난자 수명 배수
- 난자 수명을 늘립니다.
이 설정에 관계없이 황체기가 끝나면 난자는 죽습니다.
+ 난자 수명을 늘립니다.
+이 설정에 관계없이 황체기가 끝나면 난자는 죽습니다.
출산 이후 보지 변화 활성화
- 출산 이후 보지가 영구적으로 늘어나게 합니다.
만약 이 설정을 다루고있는 다른 모드가 있다면, 이 설정을 끄세요.
+ 출산 이후 보지가 영구적으로 늘어나게 합니다.
+만약 이 설정을 다루고있는 다른 모드가 있다면, 이 설정을 끄세요.
변화 강도
변화 강도를 설정합니다.
+ 정액 모으기 아이콘을 보이기
+ 발정기 시, RJW 유혹 설정 덮어쓰기
+ 활성화된 경우 발정기에 있는 폰은 RJW 설정 대신 유혹으로 이 설정을 사용합니다.
+모든 설정은 기본적으로 해당 RJW 설정으로 설정됩니다.
+ 발정기 시 유혹 최소 섹스 가능성
+ 발정기 시 유혹 최소 매력
+ 발정기 시 유혹 최소 의견
정자 예상수명
난자 예상수명
- 한시간 안에 수정될 확률: {0}%
수정란이 임신으로 진행될 확률입니다.
흰색 오버레이는 정자가 난자를 수정시킬 확률을 표시하는 것입니다.
+ 한시간 안에 수정될 확률: {0}%
+흰색 오버레이는 정자가 난자를 수정시킬 확률을 표시하는 것이고,
+분홍색 임신률 그래프는 수정된 난자가 착상되어 임신으로 진행될 확률입니다.
+
+수정이 되더라도 착상에 실패하면 임신하지 않습니다.
+ RJW 기본 임신 사용
+ 생리 모드 다중 임신 사용
+ 바이오테크 임신 사용
+ 기본값으로 재설정
+ 정액 모으기
질세척
-
사용자 지정 잡종 편집기
{0}의 잡종설정
- {0}이(가) {1}와(과) 교미했을 때, {2}이(가) {3}의 확률로 태어납니다.
만약 두 종족이 서로에 대한 잡종 정의가 있을경우 아버지 쪽의 정의가 우선적으로 사용됩니다.
-
-
\ No newline at end of file
+ {0}이(가) {1}와(과) 교미했을 때, {2}이(가) {3}의 확률로 태어납니다.
+만약 두 종족이 서로에 대한 잡종 정의가 있을경우 아버지 쪽의 정의가 우선적으로 사용됩니다.
+ 난자 없음
+
diff --git a/1.4/MilkModule/Assemblies/MilkModule.dll b/1.4/MilkModule/Assemblies/MilkModule.dll
index 5961d35..5c953b2 100644
Binary files a/1.4/MilkModule/Assemblies/MilkModule.dll and b/1.4/MilkModule/Assemblies/MilkModule.dll differ
diff --git a/1.4/Patches/MilkPatch.xml b/1.4/Patches/MilkPatch.xml
deleted file mode 100644
index 5097577..0000000
--- a/1.4/Patches/MilkPatch.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- /Defs/ThingDef[defName="HumanMilk" or defName="HumanoidMilk"]/graphicData
-
- /Defs/ThingDef[defName="HumanMilk" or defName="HumanoidMilk"]/graphicData
-
-
- Things/Item/Milkbottle
- Graphic_StackCount
-
-
-
-
-
-
-
diff --git a/1.4/Patches/Pregenerated_Babies.xml b/1.4/Patches/Pregenerated_Babies.xml
new file mode 100644
index 0000000..07d05b3
--- /dev/null
+++ b/1.4/Patches/Pregenerated_Babies.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Biotech
+
+
+ /Defs/HediffDef[defName="PregnantHuman" or defName="PregnancyLabor" or defName="PregnancyLaborPushing"]/comps
+
+
+ RJW_Menstruation.HediffComp_PregeneratedBabies
+
+
+
+
+
\ No newline at end of file
diff --git a/1.4/Textures/Things/Item/Milkbottle/Milkbottle_a.png b/1.4/Textures/Things/Item/Milkbottle/Milkbottle_a.png
deleted file mode 100644
index c9ac05f..0000000
Binary files a/1.4/Textures/Things/Item/Milkbottle/Milkbottle_a.png and /dev/null differ
diff --git a/1.4/Textures/Things/Item/Milkbottle/Milkbottle_b.png b/1.4/Textures/Things/Item/Milkbottle/Milkbottle_b.png
deleted file mode 100644
index 9fced73..0000000
Binary files a/1.4/Textures/Things/Item/Milkbottle/Milkbottle_b.png and /dev/null differ
diff --git a/1.4/Textures/Things/Item/Milkbottle/Milkbottle_c.png b/1.4/Textures/Things/Item/Milkbottle/Milkbottle_c.png
deleted file mode 100644
index 88a8899..0000000
Binary files a/1.4/Textures/Things/Item/Milkbottle/Milkbottle_c.png and /dev/null differ
diff --git a/1.4/Textures/UI/Genes/Placeholder.png b/1.4/Textures/UI/Genes/Placeholder.png
new file mode 100644
index 0000000..deaa2c0
Binary files /dev/null and b/1.4/Textures/UI/Genes/Placeholder.png differ
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Compatibility/HARCompatibility.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Compatibility/HARCompatibility.cs
index add9b43..7eb1e66 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Compatibility/HARCompatibility.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Compatibility/HARCompatibility.cs
@@ -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)
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs
index 6a843bb..d450c4d 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Configurations.cs
@@ -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;
@@ -434,9 +438,11 @@ namespace RJW_Menstruation
if (listmain.RadioButton(Translations.Option_PregnancyFromMultiplePregnancy_Label, Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy))
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)
+ Configurations.PregnancySource = Configurations.PregnancyType.Biotech;
+ 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;
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs
index 1d5eb60..71e930c 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Breast.cs
@@ -356,7 +356,7 @@ namespace RJW_Menstruation
{
baseAreola = Mathf.Clamp01(baseAreola + amount);
UpdateNipples();
- }
+ }
public void UpdateNipples()
{
@@ -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)
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs
index 55b7ecf..3bccc44 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs
@@ -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;
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs
index 5064dc2..070c6ef 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs
@@ -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();
@@ -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();
+ 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().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;
}
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs
index 11509de..b3fa2ac 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PeriodicOvulator.cs
@@ -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;
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
new file mode 100644
index 0000000..51b497a
--- /dev/null
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
@@ -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 babies;
+ // Unused, but can't hurt to track
+ protected Dictionary enzygoticSiblings;
+
+ protected static readonly MethodInfo RandomLastName = typeof(PregnancyUtility).GetMethod("RandomLastName", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Pawn), typeof(Pawn), typeof(Pawn) }, null);
+
+ public bool HasBaby
+ {
+ get => !babies.NullOrEmpty();
+ }
+
+ public Pawn PopBaby()
+ {
+ if (babies.NullOrEmpty()) return null;
+
+ Pawn firstBaby = babies.First();
+ babies.Remove(firstBaby);
+ return firstBaby;
+ }
+
+ public override void CompPostPostRemoved()
+ {
+ // At this point in the hediff removal process, the new hediff is already on the pawn
+ // But it is possible that there is no new hediff (be it a birth, miscarrage, or dev edit)
+ base.CompPostPostRemoved();
+
+ // 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();
+ if (laborcomp == null) return;
+ laborcomp.babies = this.babies;
+ laborcomp.enzygoticSiblings = this.enzygoticSiblings;
+ break;
+ case Hediff_Labor hediff_Labor:
+ Hediff_LaborPushing pushing = (Hediff_LaborPushing)Pawn.health.hediffSet.hediffs.Where(hediff => hediff is Hediff_LaborPushing).MaxByWithFallback(hediff => hediff.loadID);
+ HediffComp_PregeneratedBabies pushingcomp = pushing?.TryGetComp();
+ if (pushingcomp == null) return;
+ pushingcomp.babies = this.babies;
+ pushingcomp.enzygoticSiblings = this.enzygoticSiblings;
+ break;
+ case Hediff_LaborPushing hediff_LaborPushing:
+ // Nothing to do, the laborpushing transpiler will pick it up
+ break;
+ }
+ }
+
+ public override void CompExposeData()
+ {
+ base.CompExposeData();
+ Scribe_Collections.Look(ref babies, "babies", LookMode.Deep);
+ Scribe_Collections.Look(ref enzygoticSiblings, "enzygoticSiblings", keyLookMode: LookMode.Reference, valueLookMode: LookMode.Reference);
+ }
+
+
+ public void AddNewBaby(Pawn mother, Pawn father)
+ {
+ if (babies == null) babies = new List();
+ PawnKindDef babyPawnKind = PregnancyCommon.BabyPawnKindDecider(mother, father, 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();
+ 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()?.TryGetComp();
+ 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 Transpiler(IEnumerable 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 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().TryGetComp();
+ 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), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments)});
+ public static IEnumerable Transpiler(IEnumerable 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 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().TryGetComp();
+ 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), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments) });
+ public static IEnumerable Transpiler(IEnumerable 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;
+ }
+ }
+}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs
index 18a9604..43e2717 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs
@@ -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.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();
+ 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()?.fetusTexPath ?? "Fetus/Fetus_Default";
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
index c1d995a..cab288a 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
@@ -13,9 +13,6 @@ namespace RJW_Menstruation
{
protected Dictionary enzygoticSiblings = new Dictionary(); // Each pawn and who they split from
- protected 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 babiesdistinct = babies.Distinct(new RaceComparer());
- int iteration = 0;
- foreach (Pawn baby in babiesdistinct)
- {
- int num = babies.Where(x => x.def.Equals(baby.def)).Count();
- if (iteration > 0) res.Append(", ");
- res.AppendFormat("{0} {1}", num, baby.def.label);
- iteration++;
- }
- res.AppendFormat(" {0}", Translations.Dialog_WombInfo02);
- return res.ToString();
- }
-
- public string GetFatherInfo()
- {
- if (babies.NullOrEmpty())
- return "Null";
-
- StringBuilder res = new StringBuilder();
- res.AppendFormat("{0}: ", Translations.Dialog_WombInfo03);
-
- if (!is_parent_known && Configurations.InfoDetail != Configurations.DetailLevel.All)
- return res.Append(Translations.Dialog_FatherUnknown).ToString();
-
- IEnumerable babiesdistinct = babies.Distinct(new FatherComparer(pawn));
- int iteration = 0;
- foreach (Pawn baby in babiesdistinct)
- {
- if (iteration > 0) res.Append(", ");
- res.Append(Utility.GetFather(baby, pawn)?.LabelShort ?? Translations.Dialog_FatherUnknown);
- iteration++;
- }
- return res.ToString();
- }
-
private void HumanlikeBirth(Pawn baby)
{
Pawn mother = pawn; Pawn father = Utility.GetFather(baby, pawn);
@@ -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 originalComp = originalPart.TryGetComp();
-
- if (comp != null && originalComp != null)
- {
- // the string properties should be the same between both pawns anyways, besides the name of the owner
- part.Severity = originalPart.Severity;
- comp.SizeBase = originalComp.SizeBase;
- comp.SizeOwner = originalComp.SizeOwner;
- comp.EffSize = originalComp.EffSize;
- comp.FluidAmmount = originalComp.FluidAmmount;
- comp.FluidModifier = originalComp.FluidModifier;
- }
-
- HediffComp_Menstruation originalMenstruationComp = originalPart.GetMenstruationCompFromVagina();
- if (originalMenstruationComp != null)
- {
- part.GetMenstruationCompFromVagina()?.CopyCycleProperties(originalMenstruationComp);
- }
- HediffComp_Breast originalBreastComp = originalPart.GetBreastComp();
- if (originalBreastComp != null)
- {
- part.GetBreastComp()?.CopyBreastProperties(originalBreastComp);
- }
- }
-
- protected void CopyBodyPartRecord(Pawn baby, Pawn original, BodyPartRecord babyBPR, BodyPartRecord originalBPR)
- {
- if (babyBPR == null || originalBPR == null) return;
-
- RemoveBabyParts(baby, Genital_Helper.get_PartsHediffList(baby, babyBPR));
- foreach (Hediff originalPart in Genital_Helper.get_PartsHediffList(original, originalBPR))
- {
- Hediff part = SexPartAdder.MakePart(originalPart.def, baby, babyBPR);
- CopyBodyPartProperties(part, originalPart);
- baby.health.AddHediff(part, babyBPR);
- }
- }
-
- // Baby is the sibling to be changed, original is the first of the set and the one to copy to the rest.
- public virtual void ProcessIdenticalSibling(Pawn baby, Pawn original)
- {
- // They'll be the same pawnkind, which lets us make a lot of useful assumptions
- // However, some RNG might still be involved in genital generation (e.g. futas), so the easiest method is to clear out and re-generate
- // A bit wasteful since Hediff_BasePregnancy.PostBirth already redid the genitals
- CopyBodyPartRecord(baby, original, Genital_Helper.get_genitalsBPR(baby), Genital_Helper.get_genitalsBPR(original));
- CopyBodyPartRecord(baby, original, Genital_Helper.get_breastsBPR(baby), Genital_Helper.get_breastsBPR(original));
- CopyBodyPartRecord(baby, original, Genital_Helper.get_uddersBPR(baby), Genital_Helper.get_uddersBPR(original));
- CopyBodyPartRecord(baby, original, Genital_Helper.get_anusBPR(baby), Genital_Helper.get_anusBPR(original));
- }
-
public override void PostBirth(Pawn mother, Pawn father, Pawn baby)
{
base.PostBirth(mother, father, baby);
// Has to happen on birth since RJW redoes the genitals at birth
if (!enzygoticSiblings.NullOrEmpty() && enzygoticSiblings.TryGetValue(baby, out Pawn original) && baby != original)
- ProcessIdenticalSibling(baby, original);
+ PregnancyCommon.ProcessIdenticalSibling(baby, original);
}
// From RJW's trait code
@@ -411,7 +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;
}
- ///
- /// Decide pawnkind from mother and father
- /// Come from RJW
- ///
- ///
- ///
- ///
- public PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father)
- {
- PawnKindDef motherKindDef = Utility.GetRacesPawnKind(mother);
- PawnKindDef fatherKindDef = Utility.GetRacesPawnKind(father);
-
- PawnKindDef spawn_kind_def = motherKindDef;
-
- int flag = 0;
- if (xxx.is_human(mother)) flag += 2;
- if (xxx.is_human(father)) flag += 1;
- //Mother - Father = Flag
- //Human - Human = 3
- //Human - Animal = 2
- //Animal - Human = 1
- //Animal - Animal = 0
-
- switch (flag)
- {
- case 3:
- if (!Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- case 2:
- if (RJWPregnancySettings.bestiality_DNA_inheritance == 0f) spawn_kind_def = fatherKindDef;
- else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- case 1:
- if (RJWPregnancySettings.bestiality_DNA_inheritance == 1f) spawn_kind_def = fatherKindDef;
- else if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- case 0:
- if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother)) spawn_kind_def = fatherKindDef;
- break;
- }
-
- bool IsAndroidmother = AndroidsCompatibility.IsAndroid(mother);
- bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father);
- if (IsAndroidmother && !IsAndroidfather)
- {
- spawn_kind_def = fatherKindDef;
- }
- else if (!IsAndroidmother && IsAndroidfather)
- {
- spawn_kind_def = motherKindDef;
- }
-
- string MotherRaceName = "";
- string FatherRaceName = "";
- MotherRaceName = motherKindDef?.race?.defName;
- PawnKindDef non_hybrid_kind_def = spawn_kind_def;
- if (father != null)
- FatherRaceName = fatherKindDef?.race?.defName;
-
-
- if (FatherRaceName != "" && Configurations.UseHybridExtention)
- {
- spawn_kind_def = GetHybrid(father, mother);
- //Log.Message("pawnkind: " + spawn_kind_def?.defName);
- }
-
- if (MotherRaceName != FatherRaceName && FatherRaceName != "")
- {
- if (!Configurations.UseHybridExtention || spawn_kind_def == null)
- {
- spawn_kind_def = non_hybrid_kind_def;
- IEnumerable groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty()));
-
-
- //ModLog.Message(" found custom RaceGroupDefs " + groups.Count());
- foreach (RaceGroupDef t in groups)
- {
- if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName))
- || (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName))))
- {
- //ModLog.Message(" has hybridRaceParents");
- if (t.hybridChildKindDef.Contains("MotherKindDef"))
- spawn_kind_def = motherKindDef;
- else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null)
- spawn_kind_def = fatherKindDef;
- else
- {
- //ModLog.Message(" trying hybridChildKindDef " + t.defName);
- List child_kind_def_list = new List();
- child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName)));
-
- //ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count);
- if (!child_kind_def_list.NullOrEmpty())
- spawn_kind_def = child_kind_def_list.RandomElement();
- }
- }
- }
- }
-
- }
- else if (!Configurations.UseHybridExtention || spawn_kind_def == null)
- {
- spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? motherKindDef;
- }
-
- if (spawn_kind_def.defName.Contains("Nymph"))
- {
- //child is nymph, try to find other PawnKindDef
- List spawn_kind_def_list = new List();
- spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph")));
- //no other PawnKindDef found try mother
- if (spawn_kind_def_list.NullOrEmpty())
- spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == motherKindDef.race && !x.defName.Contains("Nymph")));
- //no other PawnKindDef found try father
- if (spawn_kind_def_list.NullOrEmpty() && father != null)
- spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == fatherKindDef.race && !x.defName.Contains("Nymph")));
- //no other PawnKindDef found fallback to generic colonist
- if (spawn_kind_def_list.NullOrEmpty())
- spawn_kind_def = PawnKindDefOf.Colonist;
-
- if (!spawn_kind_def_list.NullOrEmpty()) spawn_kind_def = spawn_kind_def_list.RandomElement();
- }
-
- return spawn_kind_def;
-
- }
-
- public PawnKindDef GetHybrid(Pawn first, Pawn second)
- {
- PawnKindDef res = null;
- Pawn opposite = second;
- HybridInformations info = null;
-
-
- if (!Configurations.HybridOverride.NullOrEmpty())
- {
- info = Configurations.HybridOverride.FirstOrDefault(x => x.DefName == first.def?.defName && (x.hybridExtension?.Exists(y => y.DefName == second.def?.defName) ?? false));
- if (info == null)
- {
- info = Configurations.HybridOverride.FirstOrDefault(x => x.DefName == second.def?.defName && (x.hybridExtension?.Exists(y => y.DefName == first.def?.defName) ?? false));
- opposite = first;
- }
- }
-
- if (info != null)
- {
- res = info.GetHybridWith(opposite.def.defName) ?? null;
- }
- if (res != null) return res;
-
-
- PawnDNAModExtension dna;
- dna = first.def.GetModExtension();
- if (dna != null)
- {
- res = dna.GetHybridWith(second.def.defName) ?? null;
- }
- else
- {
- dna = second.def.GetModExtension();
- if (dna != null)
- {
- res = dna.GetHybridWith(first.def.defName) ?? null;
- }
- }
- return res;
- }
-
///
/// Copy from RJW
///
@@ -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;
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs
index 4de0dfa..2ffe8b3 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs
@@ -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 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 Transpiler(IEnumerable 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 Transpiler(IEnumerable 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 Transpiler(IEnumerable 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;
+ // }
+ // }
+ //}
}
\ No newline at end of file
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs
index e640659..7185ccf 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Gizmo_Patch.cs
@@ -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" +
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs
index d701d49..7194d0e 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Harmony.cs
@@ -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();
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
new file mode 100644
index 0000000..7cbf28c
--- /dev/null
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
@@ -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 babies)
+ {
+ if (babies == null || !babies.Any()) return "Null";
+
+ StringBuilder res = new StringBuilder();
+
+ IEnumerable babiesdistinct = babies.Distinct(new RaceComparer());
+ int iteration = 0;
+ foreach (Pawn baby in babiesdistinct)
+ {
+ int num = babies.Where(x => x.def.Equals(baby.def)).Count();
+ if (iteration > 0) res.Append(", ");
+ res.AppendFormat("{0} {1}", num, baby.def.label);
+ iteration++;
+ }
+ res.AppendFormat(" {0}", Translations.Dialog_WombInfo02);
+ return res.ToString();
+ }
+
+ public static string GetFatherInfo(IEnumerable babies, Pawn mother, bool is_parent_known)
+ {
+ if (babies == null || !babies.Any()) return "Null";
+
+ StringBuilder res = new StringBuilder();
+ res.AppendFormat("{0}: ", Translations.Dialog_WombInfo03);
+
+ if (!is_parent_known && Configurations.InfoDetail != Configurations.DetailLevel.All)
+ return res.Append(Translations.Dialog_FatherUnknown).ToString();
+
+ IEnumerable babiesdistinct = babies.Distinct(new FatherComparer(mother));
+ int iteration = 0;
+ foreach (Pawn baby in babiesdistinct)
+ {
+ if (iteration > 0) res.Append(", ");
+ res.Append(Utility.GetFather(baby, mother)?.LabelShort ?? Translations.Dialog_FatherUnknown);
+ iteration++;
+ }
+ return res.ToString();
+ }
+
+ ///
+ /// Decide pawnkind from mother and father
+ /// Come from RJW
+ ///
+ ///
+ ///
+ ///
+
+ ///
+ public static PawnKindDef BabyPawnKindDecider(Pawn mother, Pawn father, 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 groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty()));
+
+
+ //ModLog.Message(" found custom RaceGroupDefs " + groups.Count());
+ foreach (RaceGroupDef t in groups)
+ {
+ if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName))
+ || (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName))))
+ {
+ //ModLog.Message(" has hybridRaceParents");
+ if (t.hybridChildKindDef.Contains("MotherKindDef"))
+ spawn_kind_def = motherKindDef;
+ else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null)
+ spawn_kind_def = fatherKindDef;
+ else
+ {
+ //ModLog.Message(" trying hybridChildKindDef " + t.defName);
+ List child_kind_def_list = new List();
+ child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName)));
+
+ //ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count);
+ if (!child_kind_def_list.NullOrEmpty())
+ spawn_kind_def = child_kind_def_list.RandomElement();
+ }
+ }
+ }
+ }
+
+ }
+ else if (!Configurations.UseHybridExtention || spawn_kind_def == null)
+ {
+ spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? motherKindDef;
+ }
+
+ if (spawn_kind_def.defName.Contains("Nymph"))
+ {
+ //child is nymph, try to find other PawnKindDef
+ List spawn_kind_def_list = new List();
+ spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph")));
+ //no other PawnKindDef found try mother
+ if (spawn_kind_def_list.NullOrEmpty())
+ spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == motherKindDef.race && !x.defName.Contains("Nymph")));
+ //no other PawnKindDef found try father
+ if (spawn_kind_def_list.NullOrEmpty() && father != null)
+ spawn_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => x.race == fatherKindDef.race && !x.defName.Contains("Nymph")));
+ //no other PawnKindDef found fallback to generic colonist
+ if (spawn_kind_def_list.NullOrEmpty())
+ spawn_kind_def = PawnKindDefOf.Colonist;
+
+ if (!spawn_kind_def_list.NullOrEmpty()) spawn_kind_def = spawn_kind_def_list.RandomElement();
+ }
+
+ // 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();
+ if (dna != null)
+ {
+ res = dna.GetHybridWith(second.def.defName) ?? null;
+ }
+ else
+ {
+ dna = second.def.GetModExtension();
+ if (dna != null)
+ {
+ res = dna.GetHybridWith(first.def.defName) ?? null;
+ }
+ }
+ return res;
+ }
+
+ private static void CopyBodyPartProperties(Hediff part, Hediff originalPart)
+ {
+ CompHediffBodyPart comp = part.TryGetComp();
+ CompHediffBodyPart originalComp = originalPart.TryGetComp();
+
+ if (comp != null && originalComp != null)
+ {
+ // the string properties should be the same between both pawns anyways, besides the name of the owner
+ part.Severity = originalPart.Severity;
+ comp.SizeBase = originalComp.SizeBase;
+ comp.SizeOwner = originalComp.SizeOwner;
+ comp.EffSize = originalComp.EffSize;
+ comp.FluidAmmount = originalComp.FluidAmmount;
+ comp.FluidModifier = originalComp.FluidModifier;
+ }
+
+ HediffComp_Menstruation originalMenstruationComp = originalPart.GetMenstruationCompFromVagina();
+ if (originalMenstruationComp != null)
+ {
+ part.GetMenstruationCompFromVagina()?.CopyCycleProperties(originalMenstruationComp);
+ }
+ HediffComp_Breast originalBreastComp = originalPart.GetBreastComp();
+ if (originalBreastComp != null)
+ {
+ part.GetBreastComp()?.CopyBreastProperties(originalBreastComp);
+ }
+ }
+
+ private static void CopyBodyPartRecord(Pawn baby, Pawn original, BodyPartRecord babyBPR, BodyPartRecord originalBPR)
+ {
+ if (babyBPR == null || originalBPR == null) return;
+
+ Hediff_BasePregnancy.RemoveBabyParts(baby, Genital_Helper.get_PartsHediffList(baby, babyBPR));
+ foreach (Hediff originalPart in Genital_Helper.get_PartsHediffList(original, originalBPR))
+ {
+ Hediff part = SexPartAdder.MakePart(originalPart.def, baby, babyBPR);
+ CopyBodyPartProperties(part, originalPart);
+ baby.health.AddHediff(part, babyBPR);
+ }
+ }
+
+ // Baby is the sibling to be changed, original is the first of the set and the one to copy to the rest.
+ public static void ProcessIdenticalSibling(Pawn baby, Pawn original)
+ {
+ // They'll be the same pawnkind, which lets us make a lot of useful assumptions
+ // However, some RNG might still be involved in genital generation (e.g. futas), so the easiest method is to clear out and re-generate
+ // A bit wasteful since Hediff_BasePregnancy.PostBirth already redid the genitals
+ CopyBodyPartRecord(baby, original, Genital_Helper.get_genitalsBPR(baby), Genital_Helper.get_genitalsBPR(original));
+ CopyBodyPartRecord(baby, original, Genital_Helper.get_breastsBPR(baby), Genital_Helper.get_breastsBPR(original));
+ CopyBodyPartRecord(baby, original, Genital_Helper.get_uddersBPR(baby), Genital_Helper.get_uddersBPR(original));
+ CopyBodyPartRecord(baby, original, Genital_Helper.get_anusBPR(baby), Genital_Helper.get_anusBPR(original));
+ }
+
+ 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));
+ }
+ }
+}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj b/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
index 1a35c67..0266ab8 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
@@ -69,12 +69,14 @@
+
+
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
index 8534281..7b0862d 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
@@ -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();
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs
index 8a8e380..4d428a9 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs
@@ -172,8 +172,8 @@ namespace RJW_Menstruation
Pawn fetus = comp.GetFetus();
if (fetus != null && Utility.ShowFetusInfo())
{
- string feinfo = m.GetBabyInfo();
- string fainfo = m.GetFatherInfo() + " ";
+ string feinfo = PregnancyCommon.GetBabyInfo(m.babies);
+ string fainfo = PregnancyCommon.GetFatherInfo(m.babies, m.pawn, m.is_parent_known) + " ";
if (feinfo.Length + fainfo.Length > 45)
{
preginfoheight = fontheight + 2;
@@ -221,19 +221,36 @@ namespace RJW_Menstruation
{
if (p is Hediff_Pregnant hp && hp.Severity < 0.2f) cum = comp.GetCumIcon();
else cum = ContentFinder.Get("Womb/Empty", true);
- // TODO: Pregenerated babies (base on multiplepregnancy)
+ HediffComp_PregeneratedBabies babiescomp = p.TryGetComp();
if (Utility.ShowFetusInfo())
{
- preginfoheight = fontheight;
+ 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;
+ buttonstyle.alignment = TextAnchor.MiddleLeft;
+
+ }
+
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);
+ GUI.Box(preginfo, feinfo, buttonstyle);
+ GUI.Label(preginfo, fainfo, fontstyleright);
}
}
else cum = ContentFinder.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);
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs
index 73cdf7e..406a54c 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs
@@ -188,8 +188,8 @@ namespace RJW_Menstruation
return null;
}
}
- // TODO: Biotech pregenerated babies
- return null;
+ HediffComp_PregeneratedBabies babiescomp = comp.Pregnancy.TryGetComp();
+ return babiescomp?.babies?.FirstOrDefault();
}
public static void DrawBreastIcon(this Pawn pawn, Rect rect)
@@ -209,7 +209,7 @@ namespace RJW_Menstruation
nipple = ContentFinder.Get("Breasts/Breast_Breast00_Nipple00", false);
areola = ContentFinder.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.Get(icon, false);
areola = ContentFinder.Get(areolaicon, false);
nipple = ContentFinder.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.Get("Breasts/Breast_Breast00_Nipple00", false);
areola = ContentFinder.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;
+ }
+ }
}
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs
index 5e00858..7f368cc 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs
@@ -44,8 +44,24 @@ namespace RJW_Menstruation
public static readonly RecordDef AmountofCreampied = DefDatabase.GetNamed("AmountofCreampied");
public static readonly RecordDef AmountofFertilizedEggs = DefDatabase.GetNamed("AmountofFertilizedEggs");
public static readonly TaleDef TaleCameInside = DefDatabase.GetNamed("CameInside");
+ public static readonly GeneDef ShortEggLifetime = DefDatabase.GetNamed("Menstruation_ShortEggLifetime");
+ public static readonly GeneDef DoubleEggLifetime = DefDatabase.GetNamed("Menstruation_DoubleEggLifetime");
+ public static readonly GeneDef QuadEggLifetime = DefDatabase.GetNamed("Menstruation_QuadEggLifetime");
+ public static readonly GeneDef NeverEstrus = DefDatabase.GetNamed("Menstruation_NeverEstrus");
+ public static readonly GeneDef FullEstrus = DefDatabase.GetNamed("Menstruation_FullEstrus");
+ public static readonly GeneDef DoubleOvulation = DefDatabase.GetNamed("Menstruation_DoubleOvulation");
+ public static readonly GeneDef QuadOvulation = DefDatabase.GetNamed("Menstruation_QuadOvulation");
+ public static readonly GeneDef NoBleeding = DefDatabase.GetNamed("Menstruation_NoBleeding");
-
+ public static readonly HashSet WombGenes = new HashSet() {
+ ShortEggLifetime,
+ DoubleEggLifetime,
+ QuadEggLifetime,
+ NeverEstrus,
+ FullEstrus,
+ DoubleOvulation,
+ QuadOvulation,
+ NoBleeding };
private static List allraces = null;
private static List allkinds = null;
diff --git a/About/Manifest.xml b/About/Manifest.xml
index 13e6eed..015d8cc 100644
--- a/About/Manifest.xml
+++ b/About/Manifest.xml
@@ -1,7 +1,7 @@
RJW Menstruation
- 1.0.8.5
+ 1.0.8.6
diff --git a/changelogs.txt b/changelogs.txt
index c14cc2c..b2c69dd 100644
--- a/changelogs.txt
+++ b/changelogs.txt
@@ -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.