diff --git a/1.4/Assemblies/RJW_Menstruation.dll b/1.4/Assemblies/RJW_Menstruation.dll
index 09c9244..1e66766 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
index d430d3f..c62719a 100644
--- a/1.4/Defs/GeneDefs/GeneDefs_Menstruation.xml
+++ b/1.4/Defs/GeneDefs/GeneDefs_Menstruation.xml
@@ -21,6 +21,11 @@
UI/Genes/Placeholder
1
10
+
+
+ 0.75
+
+
@@ -30,6 +35,11 @@
UI/Genes/Placeholder
-1
12
+
+
+ 2.0
+
+
@@ -40,6 +50,11 @@
-2
1
16
+
+
+ 4.0
+
+
@@ -56,6 +71,11 @@
UI/Genes/Placeholder
1
20
+
+
+ true
+
+
@@ -66,6 +86,11 @@
-1
1
25
+
+
+ true
+
+
@@ -82,6 +107,11 @@
UI/Genes/Placeholder
-1
30
+
+
+ 2
+
+
@@ -91,6 +121,11 @@
UI/Genes/Placeholder
-1
35
+
+
+ 4
+
+
@@ -99,8 +134,13 @@
Menstruation
Carriers of this gene will not bleed at the end of their cycle.
UI/Genes/Placeholder
- 1
+ -1
40
+
+
+ true
+
+
diff --git a/1.4/Defs/ThingDefs/Apparel_Absorbers.xml b/1.4/Defs/ThingDefs/Apparel_Absorbers.xml
index c27e718..87fa765 100644
--- a/1.4/Defs/ThingDefs/Apparel_Absorbers.xml
+++ b/1.4/Defs/ThingDefs/Apparel_Absorbers.xml
@@ -59,9 +59,16 @@
Absorber
+
+ Worker
+ Soldier
+ Nudist
+ Slave
+
+ 0.2
false
true
10
@@ -116,6 +123,7 @@
+ 0.2
false
true
8
@@ -190,9 +198,15 @@
Absorber
+
+ Worker
+ Soldier
+ Slave
+
+ 0.04
true
false
Absorber_Pad_Dirty
@@ -254,6 +268,7 @@
+ 0.04
true
false
Absorber_Pad_Dirty
diff --git a/1.4/Languages/ChineseTraditional/DefInjected/HediffDef/Hediffs_Menstruation.xml b/1.4/Languages/ChineseTraditional/DefInjected/HediffDef/Hediffs_Menstruation.xml
index df23159..fef8db8 100644
--- a/1.4/Languages/ChineseTraditional/DefInjected/HediffDef/Hediffs_Menstruation.xml
+++ b/1.4/Languages/ChineseTraditional/DefInjected/HediffDef/Hediffs_Menstruation.xml
@@ -13,4 +13,10 @@
緩解源自於痛經及此類神經痛的苦楚。
環孢素
由於免疫抑製劑的作用,身體抵抗感染和疾病的能力受扼制。
+
+ 受費洛蒙影響
+ 受附近某人處於發情期之故,此人的性需求及娛樂需求正急遽上升。
+ 弱
+ 中
+ 強
diff --git a/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml b/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml
index b1eeb56..86e27de 100644
--- a/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml
+++ b/1.4/Languages/ChineseTraditional/DefInjected/ThoughtDefs/Thoughts_sex.xml
@@ -11,4 +11,13 @@
卵母細胞再生術
我可以繼續繁衍一小段時間了!
+
+ 內射了{0}
+ 讓她懷孕正是我的職責所在。
+ {0}內射了我
+ 我希望這次能懷上,讓我盡到責任。
+ {0}內射了我
+ 我知道我有生育的義務,但是難道非他不可嗎?
+ 服用避孕藥
+ 我的信仰要求我能夠懷孕。
diff --git a/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml b/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml
index 9e5a55e..d190877 100644
--- a/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml
+++ b/1.4/Languages/ChineseTraditional/Keyed/RJW_Menstruation.xml
@@ -154,4 +154,18 @@
(測試中!) 允許在「生機」(Biotech)追加的懷孕機制中出現多胞胎。
啟用這個選項將允許同卵或異卵雙胞胎出現在「生機」(Biotech)追加的懷孕機制中。
一併將啟用雜交系統;然而兩個類人(humanlikes)生物絕不可能生出動物。
+
+ 玩家小人刷新間隔
+ 殖民者、囚犯和奴隸的子宮狀態應該每隔多久刷新一次?
+較小的刷新間隔可以更精確地模擬真實子宮;較大的刷新間隔可以提升遊戲流暢度
+ 非玩家小人刷新間隔
+ 非玩家勢力控制下的小人的子宮應該每隔多久刷新一次?
+較小的刷新間隔可以更精確地模擬真實子宮;較大的刷新間隔可以提升遊戲流暢度
+ 動物子宮刷新間隔
+ 動物們的子宮應該多久刷新一次?
+較小的刷新間隔可以更精確地模擬真實子宮;較大的刷新間隔可以提升遊戲流暢度
+ 啟用費洛蒙機制
+ 擁有發情期的類人生物在發情期將刺激附近的雄性類人生物,使其性慾大增。
+ 動物費洛蒙效果
+ 選定擁有發情期的動物在發情期內對類人生物的影響。
diff --git a/1.4/Languages/English/Keyed/RJW_Menstruation.xml b/1.4/Languages/English/Keyed/RJW_Menstruation.xml
index 0c796b0..7aa650e 100644
--- a/1.4/Languages/English/Keyed/RJW_Menstruation.xml
+++ b/1.4/Languages/English/Keyed/RJW_Menstruation.xml
@@ -37,7 +37,7 @@
Unknown
-
+ Absorbed
Enable womb icon
diff --git a/1.4/Languages/Japanese/DefInjected/ApparelLayerDef/RJWMenstruation.xml b/1.4/Languages/Japanese/DefInjected/ApparelLayerDef/RJWMenstruation.xml
new file mode 100644
index 0000000..cf5232e
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/ApparelLayerDef/RJWMenstruation.xml
@@ -0,0 +1,4 @@
+
+
+ 性器
+
\ No newline at end of file
diff --git a/1.4/Languages/Japanese/DefInjected/Drugs/Pills_Menstruation.xml b/1.4/Languages/Japanese/DefInjected/Drugs/Pills_Menstruation.xml
new file mode 100644
index 0000000..a801670
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/Drugs/Pills_Menstruation.xml
@@ -0,0 +1,7 @@
+
+
+ 鎮痛剤
+ 生理痛を24時間和らげます。
その他の痛みにも効果あり。
+ シクロスポリン
+ 免疫抑制剤。
抗精子抗体を直すことができるが、24時間の間、体の免疫力は低下する。
+
diff --git a/1.4/Languages/Japanese/DefInjected/HediffDef/RJWMenstruation.xml b/1.4/Languages/Japanese/DefInjected/HediffDef/RJWMenstruation.xml
new file mode 100644
index 0000000..e066065
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/HediffDef/RJWMenstruation.xml
@@ -0,0 +1,14 @@
+
+
+
+ 生理中
+ 月経周期の終わりに膣からの出血。よく痛い。
+ 不快
+ 痒い
+ 痛い
+ 苦痛
+
+
+
+
+
\ No newline at end of file
diff --git a/1.4/Languages/Japanese/DefInjected/JobDef/RJWMenstruation.xml b/1.4/Languages/Japanese/DefInjected/JobDef/RJWMenstruation.xml
new file mode 100644
index 0000000..abd8a16
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/JobDef/RJWMenstruation.xml
@@ -0,0 +1,7 @@
+
+
+ 膣を洗っている
+
+
+
+
\ No newline at end of file
diff --git a/1.4/Languages/Japanese/DefInjected/StatDef/RJWMenstruation.xml b/1.4/Languages/Japanese/DefInjected/StatDef/RJWMenstruation.xml
new file mode 100644
index 0000000..c5ce3d0
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/StatDef/RJWMenstruation.xml
@@ -0,0 +1,7 @@
+
+
+ 吸収量
+ 吸収可能な液体の最大量。
+
+
+
\ No newline at end of file
diff --git a/1.4/Languages/Japanese/DefInjected/ThingDef/RJWMenstruation.xml b/1.4/Languages/Japanese/DefInjected/ThingDef/RJWMenstruation.xml
new file mode 100644
index 0000000..76f4ba9
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/ThingDef/RJWMenstruation.xml
@@ -0,0 +1,31 @@
+
+
+
+
+タンポン
+
+膣内の体液を吸収するタンポン。長時間に着けて感染症を引き起こすことがある。
+
+汚れたタンポン
+
+濡れた使用済みタンポン。そのままにしておくと感染症を引き起こす可能性がある。
+
+生理用品
+
+膣からの体液を吸収するためのナプキン。
+
+汚れた生理用品
+
+濡れた使用済みナプキン
+
+卵巣再生薬
+
+卵巣を回復させ、卵子の数をある程度を回復させる。
卵子がほとんど残っていない卵巣にはあまり効果がない。
更年期の回復はできない。
+
+排卵剤
+
+過排卵を誘発し、次の排卵で卵子を1~4個余分に産生させる。
更年期を早める可能性がある。
+
+混じった物
+
+
\ No newline at end of file
diff --git a/1.4/Languages/Japanese/DefInjected/ThoughtDefs/RJWMenstruation.xml b/1.4/Languages/Japanese/DefInjected/ThoughtDefs/RJWMenstruation.xml
new file mode 100644
index 0000000..7092dde
--- /dev/null
+++ b/1.4/Languages/Japanese/DefInjected/ThoughtDefs/RJWMenstruation.xml
@@ -0,0 +1,33 @@
+
+
+ ぽたぽた
+ これを吸収するものはないのかな?
+ {0}に中出した
+ ライバルに中出した
+ {0}に中出した
+ 気持ちよかった。
+ {0}に中出した
+ 妊娠するといいな。
+ {0}に中出された
+ あいつの子を妊娠したくない!
+ {0}に中出された
+ そんなことをさせるなんて、私は何を考えていたんだろう?
+ {0}に中出された
+ 可能性は低いけど、妊娠できるかどうか心配で...
+ {0}に中出された
+ 妊娠しないか心配なんだ。
+ {0}に中出された
+ 妊娠するとは思わないけど、妄想するのは楽しい。
+ {0}に中出された
+ 妊娠することはないだろうけど、やっぱり嫌だ。
+ 望まない妊娠
+ 赤ん坊の世話なんてできるか?どうすればいい?
+ 望まない妊娠
+ 赤ちゃんが生まれる。なんとかなるといいな。
+ 避妊ピルを飲んだ
+ もう大丈夫です。
+ 避妊ピルを飲んだ
+ 妊娠したい。
+ 卵巣復活を得た
+ もう少しの間、繁殖ことができる。
+
diff --git a/1.4/Languages/Japanese/Keyed/RJW_Menstruation.xml b/1.4/Languages/Japanese/Keyed/RJW_Menstruation.xml
new file mode 100644
index 0000000..538bdc3
--- /dev/null
+++ b/1.4/Languages/Japanese/Keyed/RJW_Menstruation.xml
@@ -0,0 +1,152 @@
+
+
+ RJW Menstruation Cycle
+
+ 経血
+ 空っぽ
+ 卵胞期
+ 排卵期
+ 黄体期
+ 月経期
+ 妊娠
+ 出産後
+ 無し
+ クリマクテリック
+ 更年期
+ 無発情期
+ 卵巣は卵子を放出するの準備をしています。この時期の終わりに排卵が起こります。
+ 卵巣は卵子を放出するの準備をしています。精液が子宮に入ると排卵が起こります。
+ 卵巣が卵子を子宮に放出しています。
+ 子宮は受精卵を受け入れる準備ができている。この時期が終る前に受精卵が着床すれば妊娠となります。
+ 子宮内膜は剥がれ落ち、着床できなかった受精卵を排出します。
+ 子宮に赤ちゃんがいます。時間とケアによって、この世界の新しい住人となる。
+ 子宮は最近の妊娠から回復しています。
+ 子宮は繁殖能力がなく、妊娠することはできない。
+ 卵巣が枯渇すると、月経周期が不規則になる。
+ 。卵巣が枯渇し、子宮が卵子を産み出せなくなる。
+ 繁殖期を過ぎた。時期が来れば発情周期は再開する。
+ ステータス
+ 自分を搾乳する
+ ステータス
+ 胎児
+ 父親
+ 精液リスト
+ 受精卵
+ 受精中
+ 排卵済み
+
+
+ 精液をバケッツに集める
+ 子宮に精液をためる
+ 不明
+
+
+
+ Enable womb icon
+ Enable button in health tab
+ Enable animal cycle
+ Simulate animal cycles.
Not recommended.
+ Implantation chance
+ Base implantation chance of fertilized egg
This value affects the chance of impregnation.
+ Fertilization chance
+ The fertilization chance per ml of sperm per hour
This value affects the chance of impregnation.
+ Cum decay ratio per hour
+ The amount of cum in the womb will drop by this amount every hour
This value affects the chance of impregnation.
+ Cum fertility decay ratio per hour
+ Cum will lose fertility by this amount every hour
This value affects fertilization chance indirectly.
+ Cycle acceleration
+ Accelerate menstruation cycle
This can cause early menopause and infertility.
Setting this lower than x12 is recommended.
Rimworld's timescale: x6(default)
+ Colonist update interval
+ How often the womb of each of your colonists, prisoners, and slaves update.
Lowering this will improve accuracy, increasing this can improve performance.
+ Non-colonist update interval
+ How often the womb of humans you don't control update.
Lowering this will improve accuracy, increasing this can improve performance.
+ Animal update interval
+ How often the womb of animals update.
Lowering this will improve accuracy, increasing this can improve performance.
+ Debug
+ Show debug information.
+ Womb status
+ Draw womb icon in status window.
+ Vagina and breast status
+ Draw vagina, anus and breast icons in the status window.
+ Fetus information level
+ Show all information about a fetus.
+ Show all information about a fetus after discovered pregnancy.
+ Show only image of a fetus after discovered pregnancy.
+ Do not show any information about a fetus.
+ Enable menopause
+ Enable menopause effect that makes pawn infertile when they run out of eggs
If you have problems with long lived races, turn off this option.
+ Use multiple pregnancy
+ Use multiple pregnancy instead RJW's default pregnancy
Disable this option if you are in trouble with impregnation
RJW pregnancy should be turned on.
+ Enable hetero ovular twins
+ Allow pregnancy from multiple eggs at the same time.
+ Enable enzygotic twins
+ Enable a single egg to result in multiple identical offspring.
+ Enzygotic twins chance
+ The chance of identical twins.
+ Max enzygotic twins
+ The maximum number of identical siblings.
+ Enable egg overlay
+ Enable egg overlay on womb icon.
+ Bleeding amount
+ Estimated total bleeding amount
+ The approximate bleeding amount.
The normal bleeding amount of a human is about 20~80ml per cycle.
+ Colonist
+ Prisoner
+ Allied Faction
+ Neutral
+ Hostile Faction
+ Target pawns:
+ The gizmo and button will appear for these pawns
+ Use hybrid extension
+ Overrides RJW and RaceSupport's hybrid definition.
Dominant hybrid extension determines whose definition used first. Not recommended to change this.
+ Dominant hybrid extension
+ 母
+ 父
+ Breast growth during pregnancy
+ Change how much a pregnant pawn's breasts will grow when pregnant. Some pawns will grow more than others.
+ Nipple change during pregnancy
+ Change how much a pregnant pawn's nipples will change during pregnancy.
+ Permanent nipple change after pregnancy
+ Adjusts approximately how much of a pregnant pawn's nipples will remain changed after the pregnancy ends.
+ Customize Hybrids
+ Open custom hybrid editor.
This will overrides hybrid definitions of XML files.
+ Allow shrink icon
+ Let icon become smaller if needed.
+ Egg lifespan multiplier
+ Multiply egg's lifespan.
All non-implanted eggs will die at end of luteal stage regardless of this setting.
+ Enable vagina morph after birth
+ Enable permanent vagina stretch after birth.
If you are using another mod handling this, turn off this option.
+ Morph power
+ Set morph power.
+ Enable gather cum gizmo
+ Estrus overrides RJW hookup settings
+ If enabled, a pawn in visible estrus will use these settings for potential impregnation hookups instead of the RJW settings.
All settings default to their RJW counterparts.
+ Hookup minimum fuckability in estrus
+ Hookup minimum attractability in estrus
+ Hookup minimum opinion in estrus
+ Estimated sperm lifespan
+ Estimated egg lifespan
+ 排卵 {0}
+ 排卵時に各卵が放出される確率。
+ 受精卵の着床確率。
この時間に受精する確率{0}%
+ 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
+
+ 精液を収集
+ 膣を洗う
+
+ Custom Hybrid Editor
+ Hybrids of {0}
+ When {0} breed with {1}, {2} will be born at {3} chance.
If both races have hybrid definitions for each other, the father's definition will be used.
+
+ 卵子がない
+ 子宮が必要
+ {PAWN_labelShort} has completed {PAWN_possessive} egg restoration cycle.
+
+
\ No newline at end of file
diff --git a/1.4/MilkModule/Assemblies/MilkModule.dll b/1.4/MilkModule/Assemblies/MilkModule.dll
deleted file mode 100644
index 95909f5..0000000
Binary files a/1.4/MilkModule/Assemblies/MilkModule.dll and /dev/null differ
diff --git a/1.4/MilkModule/Defs/JobDefs/Jobs_MilkSelf_MC.xml b/1.4/MilkModule/Defs/JobDefs/Jobs_MilkSelf_MC.xml
deleted file mode 100644
index 69cdc4d..0000000
--- a/1.4/MilkModule/Defs/JobDefs/Jobs_MilkSelf_MC.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- LactateSelf_MC
- MilkModule.JobDriver_MilkSelf_MC
- lactating self
- true
-
-
diff --git a/1.4/Patches/CycleDisabledGenes.xml b/1.4/Patches/CycleDisabledGenes.xml
new file mode 100644
index 0000000..18b4d83
--- /dev/null
+++ b/1.4/Patches/CycleDisabledGenes.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Alpha Genes
+
+
+ /Defs/GeneDef[defName="AG_Egglaying"]
+
+
+ true
+
+
+
+
+
+
+
+ Vanilla Races Expanded - Saurid
+
+
+ /Defs/GeneDef[defName="VRESaurids_Oviparous"]
+
+
+ true
+
+
+
+
+
+
+
+ Vanilla Races Expanded - Phytokin
+
+
+ /Defs/GeneDef[defName="VRE_SaplingBirth"]
+
+
+ true
+
+
+
+
+
+
+
+ Erin's Corvyia
+
+
+ /Defs/GeneDef[defName="ERN_EggLayer"]
+
+
+ true
+
+
+
+
+
+
+
+ Outland - Genetics
+
+
+ /Defs/GeneDef[defName="Outland_EggLayer"]
+
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/1.4/Patches/Hediffs_PrivateParts.xml b/1.4/Patches/Hediffs_PrivateParts.xml
index 6b6a570..58bd529 100644
--- a/1.4/Patches/Hediffs_PrivateParts.xml
+++ b/1.4/Patches/Hediffs_PrivateParts.xml
@@ -144,11 +144,5 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation.sln b/1.4/source/RJW_Menstruation/RJW_Menstruation.sln
index 701c76e..37d1010 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation.sln
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation.sln
@@ -5,8 +5,6 @@ VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RJW_Menstruation", "RJW_Menstruation\RJW_Menstruation.csproj", "{EED2F3B9-8C20-4194-919E-8D151B29F70B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MilkModule", "MilkModule\MilkModule.csproj", "{3591B3C1-EB57-44BF-AB69-A613E097A7F8}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -17,10 +15,6 @@ Global
{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EED2F3B9-8C20-4194-919E-8D151B29F70B}.Release|Any CPU.Build.0 = Release|Any CPU
- {3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3591B3C1-EB57-44BF-AB69-A613E097A7F8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
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 558031d..eacab7d 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
@@ -144,11 +144,13 @@ namespace RJW_Menstruation
Scribe_Values.Look(ref baseAlpha, "baseAlpha", baseAlpha, true);
Scribe_Values.Look(ref baseAreola, "baseAreola", baseAreola, true);
Scribe_Values.Look(ref baseNipple, "baseNipple", baseNipple, true);
+ if (Scribe.mode == LoadSaveMode.PostLoadInit)
+ Initialize();
}
public bool ShouldSimulate()
{
- if (!Configurations.EnableAnimalCycle && Pawn.IsAnimal()) return false;
+ if (!Pawn.ShouldCycle()) return false;
if (Pawn.SpawnedOrAnyParentSpawned || Pawn.IsCaravanMember() || PawnUtility.IsTravelingInTransportPodWorldObject(Pawn)) return true;
return false;
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 a32969c..3b4ab9c 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
@@ -30,7 +30,7 @@ namespace RJW_Menstruation
switch (CurrentVisibleStage)
{
case Stage.Follicular:
- return Translations.Stage_Follicular_Induced_Desc + (EggHealth < 1f ? Translations.Stage_Climacteric_Desc : "");
+ return Translations.Stage_Follicular_Induced_Desc + (EggHealth < 1f ? " " + Translations.Stage_Climacteric_Desc : "");
default:
return base.GetCurStageDesc;
}
@@ -106,19 +106,10 @@ namespace RJW_Menstruation
protected override bool ShouldBeInEstrus()
{
- if (!loaded)
- Initialize();
- switch (curStage)
- {
- case Stage.Follicular:
- return curStageTicks > currentIntervalTicks - Props.estrusDaysBeforeOvulation * GenDate.TicksPerDay;
- case Stage.Ovulatory:
- return true;
- case Stage.Luteal:
- return hadOvulatoryStage && curStageTicks < EggLifespanTicks;
- default:
- return false;
- }
+ if (curStage == Stage.Luteal && !hadOvulatoryStage) return false;
+ else return base.ShouldBeInEstrus();
}
+
+ protected override float RandomOvulationChance => 0;
}
}
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 e18dad4..f7793e1 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
@@ -127,7 +127,6 @@ namespace RJW_Menstruation
protected float implantationChanceCache = -1.0f;
protected int opcache = -1;
protected float antisperm = 0.0f;
- protected float? originvagsize = null;
// RJW pregnancy, or Biotech pregnancy/labor/laborpushing
protected Hediff pregnancy = null;
@@ -179,7 +178,8 @@ namespace RJW_Menstruation
public float HoursBetweenSimulations => (float)TickInterval / GenDate.TicksPerHour;
- public Hediff Pregnancy {
+ public Hediff Pregnancy
+ {
get
{
if (pregnancy == null) return null;
@@ -198,20 +198,9 @@ namespace RJW_Menstruation
get
{
if (opcache > 0) return opcache;
- float avglittersize;
- try
- {
- avglittersize = Mathf.Max(Rand.ByCurveAverage(Pawn.RaceProps.litterSizeCurve), 1.0f);
- }
- catch
- {
- // 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 *
+ AverageLitterSize() *
yearsBeforeMenopause *
(Pawn.RaceProps.lifeExpectancy / ThingDefOf.Human.race.lifeExpectancy));
if (opcache == 0) opcache = 1;
@@ -266,7 +255,7 @@ namespace RJW_Menstruation
public float TotalCum
{
- get => cums?.Sum(cum => cum.Volume) ?? 0;
+ get => cums?.Sum(cum => cum.Volume) ?? 0;
}
public float TotalFertCum
{
@@ -290,7 +279,7 @@ namespace RJW_Menstruation
{
get
{
- if (QuirkUtility.HasQuirk(Pawn, QuirkUtility.Quirks.Breeder)) return 0.5f;
+ if (Pawn.IsBreeder()) return 0.5f;
return 1.0f;
}
@@ -300,7 +289,7 @@ namespace RJW_Menstruation
private bool calculatingOvulationChance = false;
public bool CalculatingOvulationChance { get => calculatingOvulationChance; }
- protected float CalcuatedOvulationChance()
+ protected float CalculatedOvulationChance()
{
float ovulationChance = 1.0f;
if (EggHealth <= 0.0f) return 0.0f;
@@ -308,20 +297,14 @@ namespace RJW_Menstruation
if (ModsConfig.BiotechActive && xxx.is_human(Pawn))
{
if (Pawn.SterileGenes()) return 0.0f;
- // Replicate how rjw.PawnCapacityWorker_Fertility.CalculateCapacityLevel does it, but without the age factor
if (!Pawn.RaceHasFertility()) return 0.0f;
if (AndroidsCompatibility.IsAndroid(Pawn) && parent.def != Genital_Helper.archotech_vagina) return 0.0f;
- foreach (var part in StatDefOf.Fertility.parts)
- {
- if(part is StatPart_FertilityByGenderAge fertilityByAge)
- {
- float factor = 1.0f;
- fertilityByAge.TransformValue(StatRequest.For(Pawn), ref factor);
- if (factor <= 0.0f) return 0.0f; // Too young or too old
- }
- else part.TransformValue(StatRequest.For(Pawn), ref ovulationChance);
- }
- if (Pawn.HasQuirk(QuirkUtility.Quirks.Breeder)) ovulationChance *= 10.0f;
+
+ float ageFactor = 1.0f;
+ StatDefOf.Fertility.GetStatPart()?.TransformValue(StatRequest.For(Pawn), ref ageFactor);
+ if (ageFactor <= 0.0f) return 0.0f; // Too young or too old
+
+ if (Pawn.IsBreeder()) ovulationChance *= 10.0f;
try
{
calculatingOvulationChance = true;
@@ -332,20 +315,20 @@ namespace RJW_Menstruation
return ovulationChance;
}
- protected float CalcuatedImplantChance()
+ protected float CalculatedImplantChance()
{
- float factor = 1.0f;
if (ModsConfig.BiotechActive && xxx.is_human(Pawn))
{
// Implant factor will be based solely on pawn age, plus any rollover from ovulation chance
- StatPart_FertilityByGenderAge fertilityStatPart = StatDefOf.Fertility.GetStatPart();
- fertilityStatPart?.TransformValue(StatRequest.For(Pawn), ref factor);
+ float factor = 1.0f;
+ StatDefOf.Fertility.GetStatPart()?.TransformValue(StatRequest.For(Pawn), ref factor);
+ if (factor <= 0.0f) return 0.0f;
if (OvulationChance > 1.0f) factor *= OvulationChance;
return Props.baseImplantationChanceFactor * FertilityModifier * factor;
}
else
{
- return Pawn.health.capacities.GetLevel(xxx.reproduction) * Props.baseImplantationChanceFactor * FertilityModifier * factor;
+ return Pawn.health.capacities.GetLevel(xxx.reproduction) * Props.baseImplantationChanceFactor * FertilityModifier;
}
}
@@ -353,16 +336,17 @@ namespace RJW_Menstruation
{
get
{
- if (ovulationChanceCache < 0.0f) ovulationChanceCache = CalcuatedOvulationChance();
+ if (ovulationChanceCache < 0.0f) ovulationChanceCache = CalculatedOvulationChance();
return ovulationChanceCache;
}
}
+ // Before configuration setting
public float ImplantChance
{
get
{
- if (implantationChanceCache < 0.0f) implantationChanceCache = CalcuatedImplantChance();
+ if (implantationChanceCache < 0.0f) implantationChanceCache = CalculatedImplantChance();
return implantationChanceCache;
}
}
@@ -580,19 +564,6 @@ namespace RJW_Menstruation
}
}
- public float OriginVagSize
- {
- get
- {
- if (originvagsize == null)
- {
- originvagsize = parent.Severity;
- }
- return originvagsize ?? 0.1f;
- }
- set => originvagsize = value;
- }
-
public int CurStageIntervalTicks
{
get => currentIntervalTicks;
@@ -625,7 +596,7 @@ namespace RJW_Menstruation
else if (Pawn.story?.bodyType == BodyTypeDefOf.Female) discoveryTime = 0.35f;
// Estimated; there's no way to get the exact value after the fact without writing it into the save
float lutealProgressWhenImplanted = Math.Min(0.5f, maxImplantDelayHours / (Props.lutealIntervalDays * GenDate.HoursPerDay));
-
+
return GenMath.LerpDouble(0, discoveryTime, lutealProgressWhenImplanted, 1.0f, pregnancy.Severity);
}
}
@@ -673,9 +644,10 @@ namespace RJW_Menstruation
Scribe_Values.Look(ref ovarypower, "ovarypower", ovarypower, true);
Scribe_Values.Look(ref eggstack, "eggstack", 0);
Scribe_Values.Look(ref estrusflag, "estrusflag", false);
- Scribe_Values.Look(ref originvagsize, "originvagsize", originvagsize, true);
Scribe_Values.Look(ref DoCleanWomb, "DoCleanWomb", false);
Scribe_References.Look(ref pregnancy, "pregnancy");
+ if (Scribe.mode == LoadSaveMode.PostLoadInit)
+ Initialize();
}
@@ -693,25 +665,24 @@ namespace RJW_Menstruation
estrusLevel = Props.concealedEstrus ? EstrusLevel.Concealed : EstrusLevel.Visible;
ovulationFactor = 1f;
noBleeding = false;
-
+ opcache = -1;
+
if (Pawn.genes == null || !ModsConfig.BiotechActive) return;
-
- if (Pawn.genes.HasGene(VariousDefOf.ShortEggLifetime)) eggLifeSpanTicks = eggLifeSpanTicks * 3 / 4;
- else if (Pawn.genes.HasGene(VariousDefOf.DoubleEggLifetime)) eggLifeSpanTicks *= 2;
- else if (Pawn.genes.HasGene(VariousDefOf.QuadEggLifetime)) eggLifeSpanTicks *= 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);
+ foreach (MenstruationModExtension extension in Pawn.genes.GenesListForReading.Select(gene => gene.def.GetModExtension()).Where(ext => ext != null))
+ {
+ eggLifeSpanTicks = (int)(eggLifeSpanTicks * extension.eggLifeTimeFactor);
+ if (extension.alwaysEstrus) estrusLevel = EstrusLevel.Visible;
+ else if (extension.neverEstrus) estrusLevel = EstrusLevel.None;
+ ovulationFactor *= extension.ovulationFactor;
+ if (extension.noBleeding) noBleeding = true;
+ }
+ if (eggLifeSpanTicks < 0) eggLifeSpanTicks = 0;
+ if (ovulationFactor < 0f) ovulationFactor = 0f;
}
public bool ShouldSimulate()
{
- if (!Configurations.EnableAnimalCycle && Pawn.IsAnimal()) return false;
+ if (!Pawn.ShouldCycle()) return false;
if (Pawn.SpawnedOrAnyParentSpawned || Pawn.IsCaravanMember() || PawnUtility.IsTravelingInTransportPodWorldObject(Pawn)) return true;
return false;
@@ -733,6 +704,9 @@ namespace RJW_Menstruation
// If an exception makes it out, RW will remove the hediff, so catch it here
try
{
+ if (Pawn.IsHashIntervalTick(recalculateTickInterval)) TickInterval = -1; // Every so often, force TickInterval to be recalculated in case the pawn's status changed.
+ if (!Pawn.IsHashIntervalTick(TickInterval)) return;
+
if (!ShouldSimulate()) return;
// Initialize immediately if needed, but if there's an error, then don't spam it every tick
@@ -742,9 +716,6 @@ namespace RJW_Menstruation
Initialize();
}
- if (Pawn.IsHashIntervalTick(recalculateTickInterval)) TickInterval = -1; // Every so often, force TickInterval to be recalculated in case the pawn's status changed.
- if (!Pawn.IsHashIntervalTick(TickInterval)) return;
-
if (initError) Log.Warning($"Attempting to process {Pawn}'s womb uninitialized");
if (Pregnancy != null && curStage != Stage.Pregnant)
@@ -754,7 +725,7 @@ namespace RJW_Menstruation
}
BeforeSimulator();
-
+
if (ShouldBeInfertile()) GoNextStage(Stage.Infertile);
switch (curStage)
{
@@ -831,7 +802,7 @@ namespace RJW_Menstruation
tip.Append(": ");
tip.Append(GetCurStageLabel);
string fertInfo = GetFertilizingInfo;
- if(CurrentVisibleStage == Stage.Luteal && fertInfo.Length > 0)
+ if (CurrentVisibleStage == Stage.Luteal && fertInfo.Length > 0)
{
tip.AppendLine();
tip.Append(fertInfo);
@@ -842,7 +813,7 @@ namespace RJW_Menstruation
protected virtual int TicksToNextStage()
{
- return Math.Max(0,(currentIntervalTicks - curStageTicks) / Configurations.CycleAcceleration);
+ return Math.Max(0, (currentIntervalTicks - curStageTicks) / Configurations.CycleAcceleration);
}
public override string CompDebugString()
@@ -887,8 +858,8 @@ namespace RJW_Menstruation
if (!precum && fertility > 0 && IsDangerDay && cummer.relations.GetPregnancyApproachForPartner(Pawn) == PregnancyApproach.AvoidPregnancy)
{
float successChance = pulloutSuccessRate;
- if (cummer.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish)) successChance *= fetishPulloutSuccessModifier;
- if (Pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish)) successChance *= fetishPulloutSuccessModifier;
+ if (cummer.HasImpregnationFetish()) successChance *= fetishPulloutSuccessModifier;
+ if (Pawn.HasImpregnationFetish()) successChance *= fetishPulloutSuccessModifier;
if (Rand.Chance(successChance)) return;
}
if (Pawn.HasIUD()) fertility /= 100f;
@@ -900,7 +871,7 @@ namespace RJW_Menstruation
bool merged = false;
if (!cums.NullOrEmpty()) foreach (Cum cum in cums)
{
- if (cum.pawn.Equals(cummer))
+ if (cum.pawn?.Equals(cummer) ?? false)
{
cum.MergeWithCum(volume, fertility);
merged = true;
@@ -915,7 +886,7 @@ namespace RJW_Menstruation
bool merged = false;
if (!cums.NullOrEmpty()) foreach (Cum cum in cums)
{
- if (cum.pawn.Equals(cummer))
+ if (cum.pawn?.Equals(cummer) ?? false)
{
cum.MergeWithCum(volume, fertility);
merged = true;
@@ -952,7 +923,7 @@ namespace RJW_Menstruation
bool merged = false;
if (!cums.NullOrEmpty()) foreach (Cum cum in cums)
{
- if (cum.notcum && cum.pawn.Equals(cummer) && cum.notcumLabel.Equals(notcumlabel))
+ if (cum.notcum && (cum.pawn?.Equals(cummer) ?? false) && cum.notcumLabel.Equals(notcumlabel))
{
cum.MergeWithFluid(volume, decayresist, filthdef);
merged = true;
@@ -967,7 +938,7 @@ namespace RJW_Menstruation
bool merged = false;
if (!cums.NullOrEmpty()) foreach (Cum cum in cums)
{
- if (cum.notcum && cum.pawn.Equals(cummer) && cum.notcumLabel.Equals(notcumlabel))
+ if (cum.notcum && (cum.pawn?.Equals(cummer) ?? false) && cum.notcumLabel.Equals(notcumlabel))
{
cum.MergeWithFluid(volume, decayresist, filthdef);
merged = true;
@@ -1187,7 +1158,7 @@ namespace RJW_Menstruation
if (cycleSpeed < 0f) cycleSpeed = Utility.RandGaussianLike(0.8f, 1.2f);
if (cycleVariability < 0f) cycleVariability = MenstruationUtility.RandomVariabilityPercent();
-
+
InitOvary();
if (currentIntervalTicks < 0)
@@ -1221,6 +1192,21 @@ namespace RJW_Menstruation
{
}
+ protected float AverageLitterSize()
+ {
+ float avglittersize;
+ try
+ {
+ avglittersize = Mathf.Max(Rand.ByCurveAverage(Pawn.RaceProps.litterSizeCurve), 1.0f);
+ }
+ catch (NullReferenceException)
+ {
+ avglittersize = 1.0f;
+ }
+ avglittersize *= ovulationFactor;
+ return avglittersize;
+ }
+
protected virtual float RaceCyclesPerYear()
{
int breedingSeasons = 0;
@@ -1243,16 +1229,7 @@ namespace RJW_Menstruation
public int GetOvaryPowerByAge()
{
- float avglittersize;
- try
- {
- avglittersize = Mathf.Max(Rand.ByCurveAverage(Pawn.RaceProps.litterSizeCurve), 1.0f);
- }
- catch (NullReferenceException)
- {
- avglittersize = 1.0f;
- }
- avglittersize *= ovulationFactor;
+ float avglittersize = AverageLitterSize();
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);
@@ -1369,7 +1346,7 @@ namespace RJW_Menstruation
//float fertFailChancePerHour = Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor);
//float fertFailChancePerInterval = Mathf.Pow(fertFailChancePerHour, (float)TickInterval / GenDate.TicksPerHour);
float fertFailChancePerInterval = Mathf.Pow(1.0f - Configurations.FertilizeChance, totalFertPower * Props.basefertilizationChanceFactor * HoursBetweenSimulations);
-
+
if (Rand.Chance(fertFailChancePerInterval)) return null;
Pawn.records.AddTo(VariousDefOf.AmountofFertilizedEggs, 1);
@@ -1412,97 +1389,116 @@ namespace RJW_Menstruation
}
else if (Rand.Chance(Configurations.ImplantationChance * ImplantChance * InterspeciesImplantFactor(egg.fertilizer)))
{
- if (Configurations.Debug) Log.Message($"Implanting fertilized egg of {Pawn} into {parent}, father {egg.fertilizer}");
- if (pregnancy != null)
+ try
{
- if (Configurations.PregnancySource == Configurations.PregnancyType.Biotech && Configurations.EnableBiotechTwins && Configurations.EnableHeteroOvularTwins)
+ if (Configurations.Debug) Log.Message($"Implanting fertilized egg of {Pawn} into {parent}, father {egg.fertilizer}");
+ if (pregnancy == null)
{
- 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
+ Configurations.PregnancyType usePregnancy = xxx.is_human(Pawn) ? Configurations.PregnancySource : Configurations.PregnancyType.MultiplePregnancy;
+ switch (usePregnancy)
{
- comp.AddNewBaby(Pawn, egg.fertilizer);
- pregnant = true;
- deadeggs.Add(egg);
+ case Configurations.PregnancyType.BaseRJW:
+
+ if (Configurations.Debug) Log.Message($"Creating new base RJW pregnancy");
+ PregnancyHelper.AddPregnancyHediff(Pawn, egg.fertilizer);
+ // I hate having to do this, but it gets the newest pregnancy
+ List pregnancies = new List();
+ Pawn.health.hediffSet.GetHediffs(ref pregnancies);
+ pregnancy = pregnancies.MaxBy(hediff => hediff.loadID);
+ pregnant = true;
+ break;
+
+ case Configurations.PregnancyType.MultiplePregnancy:
+ if (Configurations.Debug) Log.Message($"Creating new menstruation pregnancy");
+ pregnancy = Hediff_BasePregnancy.Create(Pawn, egg.fertilizer);
+ pregnant = true;
+ deadeggs.Add(egg);
+ break;
+
+ 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;
}
- }
- else if (Configurations.PregnancySource == Configurations.PregnancyType.MultiplePregnancy && Configurations.EnableHeteroOvularTwins)
- {
- if (pregnancy is Hediff_MultiplePregnancy h)
+ if (pregnancy is Hediff_BasePregnancy rjw_preg)
{
- if (Configurations.Debug) Log.Message($"Adding to existing pregnancy {h}");
- h.AddNewBaby(Pawn, egg.fertilizer);
+ // TODO: advance biotech pregnancy
+ rjw_preg.p_start_tick -= egg.ticksSinceFertilization / Configurations.CycleAcceleration;
+ rjw_preg.p_end_tick -= egg.ticksSinceFertilization / Configurations.CycleAcceleration;
}
- pregnant = true;
- deadeggs.Add(egg);
}
else
{
- pregnant = true;
- break;
+ switch (pregnancy)
+ {
+ case Hediff_Pregnant vanillaPreg: // Not going to do the labor ones
+ if (!Configurations.EnableBiotechTwins || !Configurations.EnableHeteroOvularTwins) goto default;
+ if (Configurations.Debug) Log.Message($"Adding to existing Biotech pregnancy {vanillaPreg.GetUniqueLoadID()}");
+ HediffComp_PregeneratedBabies comp = vanillaPreg.TryGetComp();
+ if (comp == null) Log.Warning($"Trying to add Biotech egg to {Pawn}'s pregnancy without a pregenerated baby comp: {vanillaPreg.GetUniqueLoadID()}");
+ else
+ comp.AddNewBaby(Pawn, egg.fertilizer);
+ pregnant = true;
+ deadeggs.Add(egg);
+ break;
+ case Hediff_MultiplePregnancy multiPreg:
+ if (!Configurations.EnableHeteroOvularTwins) goto default;
+ if (Configurations.Debug) Log.Message($"Adding to existing pregnancy {multiPreg.GetUniqueLoadID()}");
+ multiPreg.AddNewBaby(Pawn, egg.fertilizer);
+ pregnant = true;
+ deadeggs.Add(egg);
+ break;
+ case Hediff_BasePregnancy _:
+ default:
+ pregnant = true;
+ deadeggs.Add(egg);
+ break;
+ }
}
}
- else
+ catch (Exception ex)
{
- Configurations.PregnancyType usePregnancy = xxx.is_human(Pawn) ? Configurations.PregnancySource : Configurations.PregnancyType.MultiplePregnancy;
- switch (usePregnancy)
- {
- case Configurations.PregnancyType.BaseRJW:
-
- if (Configurations.Debug) Log.Message($"Creating new base RJW pregnancy");
- PregnancyHelper.AddPregnancyHediff(Pawn, egg.fertilizer);
- // I hate having to do this, but it gets the newest pregnancy
- List pregnancies = new List();
- Pawn.health.hediffSet.GetHediffs(ref pregnancies);
- pregnancy = pregnancies.MaxBy(hediff => hediff.loadID);
- pregnant = true;
- break;
-
- case Configurations.PregnancyType.MultiplePregnancy:
- if (Configurations.Debug) Log.Message($"Creating new menstruation pregnancy");
- pregnancy = Hediff_BasePregnancy.Create(Pawn, egg.fertilizer);
- pregnant = true;
- deadeggs.Add(egg);
- break;
-
- 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)
- {
- // TODO: advance biotech pregnancy
- rjw_preg.p_start_tick -= egg.ticksSinceFertilization / Configurations.CycleAcceleration;
- rjw_preg.p_end_tick -= egg.ticksSinceFertilization / Configurations.CycleAcceleration;
- }
+ Log.Error($"Error creating pregnancy in {Pawn}'s womb, father {egg.fertilizer}: {ex}");
+ TakeLoosePregnancy();
+ deadeggs.Add(egg);
}
}
else
- {
+ {
if (Configurations.Debug)
{
- float implantChance = Configurations.ImplantationChance * ImplantChance * InterspeciesImplantFactor(egg.fertilizer);
- Log.Message($"Fertilized egg of {Pawn} failed to implant (chance {implantChance.ToStringPercent()}, father {egg.fertilizer})");
+ float interspeciesFactor = InterspeciesImplantFactor(egg.fertilizer);
+ float implantChance = Configurations.ImplantationChance * ImplantChance * interspeciesFactor;
+ Log.Message($"Fertilized egg of {Pawn} failed to implant (chance {implantChance.ToStringPercent()}, " +
+ (interspeciesFactor < 1.0f ? $"interspecies factor {interspeciesFactor.ToStringPercent()}, " : "") +
+ $"father {egg.fertilizer})");
}
deadeggs.Add(egg);
}
}
- if (pregnant &&
- (Configurations.PregnancySource != Configurations.PregnancyType.MultiplePregnancy || !Configurations.EnableHeteroOvularTwins) &&
- (Configurations.PregnancySource != Configurations.PregnancyType.Biotech || !Configurations.EnableBiotechTwins || !Configurations.EnableHeteroOvularTwins))
+ bool clearAllEggs = true;
+ switch (Configurations.PregnancySource)
{
- eggs.Clear();
- return true;
+ case Configurations.PregnancyType.BaseRJW:
+ clearAllEggs = true;
+ break;
+ case Configurations.PregnancyType.MultiplePregnancy:
+ clearAllEggs = !Configurations.EnableHeteroOvularTwins;
+ break;
+ case Configurations.PregnancyType.Biotech:
+ clearAllEggs = !(Configurations.EnableBiotechTwins && Configurations.EnableHeteroOvularTwins);
+ break;
}
+
+ if (pregnant && clearAllEggs)
+ eggs.Clear();
else
eggs.RemoveAll(egg => deadeggs.Contains(egg));
return pregnant;
@@ -1552,12 +1548,7 @@ namespace RJW_Menstruation
return amount;
}
absorber.absorbedfluids += amount;
- if (absorber.absorbedfluids > absorbable && !Pawn.apparel.IsLocked(absorber))
- {
- absorber.def = absorber.DirtyDef;
- //absorber.fluidColor = GetCumMixtureColor;
- absorber.dirty = true;
- }
+ absorber.CheckDirty();
return 0;
}
@@ -1571,9 +1562,6 @@ namespace RJW_Menstruation
return amount;
}
-
-
-
protected void EggDecay()
{
HashSet deadeggs = new HashSet();
@@ -1599,6 +1587,11 @@ namespace RJW_Menstruation
Pawn.health.AddHediff(hediff, parent.Part);
}
+ protected void AdvanceStageTime()
+ {
+ curStageTicks += TickInterval * Configurations.CycleAcceleration;
+ }
+
protected virtual void FollicularAction()
{
if (!IsBreedingSeason())
@@ -1613,13 +1606,12 @@ namespace RJW_Menstruation
}
else
{
- curStageTicks += TickInterval * Configurations.CycleAcceleration;
+ AdvanceStageTime();
if (!estrusflag && curStageTicks > currentIntervalTicks - Props.estrusDaysBeforeOvulation * GenDate.TicksPerDay)
{
estrusflag = true;
SetEstrus();
}
- StayCurrentStage();
}
}
@@ -1627,7 +1619,7 @@ namespace RJW_Menstruation
{
if (curStageTicks < currentIntervalTicks)
{
- curStageTicks += TickInterval * Configurations.CycleAcceleration;
+ AdvanceStageTime();
return;
}
estrusflag = false;
@@ -1642,11 +1634,11 @@ namespace RJW_Menstruation
}
catch (ArgumentException e)
{
- Log.Warning($"Invalid litterSizeCurve for {Pawn.def}: {e}");
+ Log.WarningOnce($"Invalid litterSizeCurve for {Pawn.def}: {e}", 642201874 + Pawn.thingIDNumber);
eggnum = 1f;
}
eggnum *= ovulationFactor;
- int toOvulate = (int)eggnum + eggstack;
+ int toOvulate = Math.Max(1, (int)eggnum + eggstack);
int ovulated = 0;
for (int i = 0; i < toOvulate; i++)
@@ -1657,7 +1649,7 @@ namespace RJW_Menstruation
}
ovarypower -= ovulated;
eggstack = 0;
- if (Configurations.Debug && ovulated != toOvulate)
+ if (Configurations.Debug && ovulated < toOvulate)
Log.Message($"{Pawn} ovulated {ovulated}/{toOvulate} eggs ({OvulationChance.ToStringPercent()} chance)");
GoNextStage(Stage.Luteal);
@@ -1687,21 +1679,19 @@ namespace RJW_Menstruation
}
else
{
- curStageTicks += TickInterval * Configurations.CycleAcceleration;
- StayCurrentStage();
+ AdvanceStageTime();
}
}
else
{
- curStageTicks += TickInterval * Configurations.CycleAcceleration;
- StayCurrentStage();
+ AdvanceStageTime();
}
}
protected virtual void BleedingAction()
{
- if (curStageTicks >= currentIntervalTicks)
+ if (curStageTicks >= currentIntervalTicks || noBleeding)
{
Hediff hediff = Pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.Hediff_MenstrualCramp);
if (hediff != null && !Pawn.GetMenstruationComps().Any(comp => comp != this && comp.curStage == Stage.Bleeding)) Pawn.health.RemoveHediff(hediff);
@@ -1710,15 +1700,13 @@ namespace RJW_Menstruation
GoOvulatoryStage();
else
{
- currentIntervalTicks = totalFollicularTicks - currentIntervalTicks; // I.e., the remaining follicular time equals the total minus the bleeding time elapsed
- GoNextStage(Stage.Follicular, false);
+ GoNextStage(Stage.Follicular, totalFollicularTicks - currentIntervalTicks); // I.e., the remaining follicular time equals the total minus the bleeding time elapsed
}
}
else
{
if (curStageTicks < currentIntervalTicks / 4) BleedOut();
- curStageTicks += TickInterval * Configurations.CycleAcceleration;
- StayCurrentStage();
+ AdvanceStageTime();
}
}
@@ -1731,16 +1719,10 @@ namespace RJW_Menstruation
Implant();
}
- if (pregnancy != null && Pawn.health.hediffSet.hediffs.Contains(pregnancy))
- {
+ if (Pregnancy != null)
curStageTicks += TickInterval;
- StayCurrentStageConst(Stage.Pregnant);
- }
else
- {
- if (pregnancy != null) pregnancy = null;
GoNextStage(Stage.Recover);
- }
}
protected virtual void RecoverAction()
@@ -1762,22 +1744,18 @@ namespace RJW_Menstruation
}
else
{
- curStageTicks += TickInterval * Configurations.CycleAcceleration;
- StayCurrentStage();
+ AdvanceStageTime();
}
}
protected virtual void InfertileAction()
{
if (ShouldBeInfertile())
- {
- StayCurrentStageConst(Stage.Infertile);
- }
+ return;
+ else if (IsBreedingSeason())
+ GoNextStage(Stage.Follicular);
else
- {
- bool breedingSeason = IsBreedingSeason();
- GoNextStage(breedingSeason ? Stage.Follicular : Stage.Anestrus, breedingSeason);
- }
+ GoNextStage(Stage.Anestrus);
}
protected virtual void AnestrusAction()
@@ -1786,10 +1764,6 @@ namespace RJW_Menstruation
{
GoFollicularOrBleeding();
}
- else
- {
- StayCurrentStage();
- }
}
protected virtual void ThoughtCumInside(Pawn cummer)
@@ -1799,7 +1773,7 @@ namespace RJW_Menstruation
MemoryThoughtHandler cummerMemories = cummer.needs.mood.thoughts.memories;
MemoryThoughtHandler pawnMemories = Pawn.needs.mood.thoughts.memories;
- if (cummer.IsProPregnancy(out Precept preceptm) || (cummer.HasQuirk(QuirkUtility.Quirks.Teratophile) != (Pawn.GetStatValue(StatDefOf.PawnBeauty) >= 0)))
+ if (cummer.IsProPregnancy(out Precept preceptm) || (cummer.IsTeratophile() != (Pawn.GetStatValue(StatDefOf.PawnBeauty) >= 0)))
{
if (cummer.relations.OpinionOf(Pawn) <= -5)
cummerMemories.TryGainMemory(VariousDefOf.HaterCameInsideM, Pawn);
@@ -1822,10 +1796,10 @@ namespace RJW_Menstruation
}
else pawnMemories.TryGainMemory(VariousDefOf.CameInsideFFetish, cummer);
}
- else if (Pawn.relations.OpinionOf(cummer) <= -5)
- pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideF, cummer);
- else if (Pawn.IsInEstrus() && Pawn.relations.OpinionOf(cummer) < RJWHookupSettings.MinimumRelationshipToHookup)
- pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideFEstrus, cummer);
+ else if (Pawn.relations.OpinionOf(cummer) <= -5)
+ pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideF, cummer);
+ else if (Pawn.IsInEstrus() && Pawn.relations.OpinionOf(cummer) < RJWHookupSettings.MinimumRelationshipToHookup)
+ pawnMemories.TryGainMemory(VariousDefOf.HaterCameInsideFEstrus, cummer);
else if (!Pawn.relations.DirectRelationExists(PawnRelationDefOf.Spouse, cummer) && !Pawn.relations.DirectRelationExists(PawnRelationDefOf.Fiance, cummer))
{
if (Pawn.health.capacities.GetLevel(xxx.reproduction) < 0.50f) pawnMemories.TryGainMemory(VariousDefOf.CameInsideFLowFert, cummer);
@@ -1851,10 +1825,10 @@ namespace RJW_Menstruation
TaleRecorder.RecordTale(VariousDefOf.TaleCameInside, new object[] { cummer, Pawn });
}
- public void GoNextStage(Stage nextstage, bool calculateHours = true)
+ public void GoNextStage(Stage nextstage, int? stageTicks = null)
{
curStageTicks = 0;
- if (calculateHours) currentIntervalTicks = PeriodRandomizer(nextstage);
+ currentIntervalTicks = stageTicks ?? PeriodRandomizer(nextstage);
curStage = nextstage;
}
@@ -1863,16 +1837,6 @@ namespace RJW_Menstruation
GoNextStage(Stage.Ovulatory);
}
- //stage can be interrupted in other reasons
- protected void StayCurrentStage()
- {
- }
-
- //stage never changes
- protected void StayCurrentStageConst(Stage curstage)
- {
- }
-
protected void GoFollicularOrBleeding()
{
if (Props.bleedingIntervalDays == 0 || noBleeding)
@@ -1932,10 +1896,13 @@ namespace RJW_Menstruation
else return Rand.Range(0.6f, 1.0f);
}
+ protected virtual float RandomOvulationChance => (float)Props.ovulationIntervalHours / GenDate.HoursPerDay;
+
protected Stage RandomStage()
{
Stage stage = Rand.ElementByWeight(
Stage.Follicular, Props.follicularIntervalDays - Props.bleedingIntervalDays,
+ Stage.Ovulatory, RandomOvulationChance,
Stage.Luteal, Props.lutealIntervalDays,
Stage.Bleeding, Props.bleedingIntervalDays);
@@ -1944,6 +1911,9 @@ namespace RJW_Menstruation
case Stage.Follicular:
curStageTicks = Rand.Range(0, (Props.follicularIntervalDays - Props.bleedingIntervalDays) * GenDate.TicksPerDay);
break;
+ case Stage.Ovulatory:
+ curStageTicks = Rand.Range(0, Props.ovulationIntervalHours * GenDate.TicksPerHour);
+ break;
case Stage.Luteal:
curStageTicks = Rand.Range(0, Props.lutealIntervalDays * GenDate.TicksPerDay);
break;
@@ -1983,7 +1953,7 @@ namespace RJW_Menstruation
public int EggsRestoredPerBiosculptor(float yearsWorth)
{
- return Math.Max(1, (int)((float)RaceCyclesPerYear() * yearsWorth));
+ return Math.Max(1, (int)(RaceCyclesPerYear() * yearsWorth * AverageLitterSize()));
}
public void RestoreEggs(float yearsWorth)
@@ -2002,7 +1972,7 @@ namespace RJW_Menstruation
public Egg()
{
fertilized = false;
- lifeSpanTicks = (int)(96 * GenDate.TicksPerHour * Configurations.EggLifespanMultiplier);
+ lifeSpanTicks = (int)(VariousDefOf.HumanVaginaCompProperties.eggLifespanDays * GenDate.TicksPerDay * Configurations.EggLifespanMultiplier);
fertilizer = null;
ageTicks = 0;
}
@@ -2044,28 +2014,6 @@ namespace RJW_Menstruation
public class HediffComp_Anus : HediffComp
{
- protected float? originanussize;
-
- public float OriginAnusSize
- {
- get
- {
- if (originanussize == null)
- {
- originanussize = parent.Severity;
- }
- return originanussize ?? 0.1f;
- }
- }
-
- public override void CompExposeData()
- {
- base.CompExposeData();
- Scribe_Values.Look(ref originanussize, "originanussize", originanussize, true);
- }
-
- public override void CompPostTick(ref float severityAdjustment)
- {
- }
+ public CompProperties_Anus Props => (CompProperties_Anus)props;
}
}
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 ab5b2e2..e663ec2 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
@@ -29,14 +29,14 @@ namespace RJW_Menstruation
protected override void InitializeExtraValues()
{
- base.InitializeExtraValues();
+ base.InitializeExtraValues();
if (averageCycleIntervalTicks < 0)
{
averageCycleIntervalTicks = (int)(Props.cycleIntervalDays.RandomInRange * GenDate.TicksPerDay / cycleSpeed);
if (ticksToNextCycle < -50000)
ticksToNextCycle = Rand.Range(0, averageCycleIntervalTicks);
// 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)
+ if ((curStage == Stage.Follicular || curStage == Stage.Ovulatory || curStage == Stage.Luteal || curStage == Stage.Bleeding)
&& (averageCycleIntervalTicks - ticksToNextCycle) / 2 >= GenDate.TicksPerDay * (Props.follicularIntervalDays + Props.lutealIntervalDays) / cycleSpeed)
GoNextStage(Stage.Anestrus);
}
@@ -73,7 +73,7 @@ namespace RJW_Menstruation
protected override int TicksToNextStage()
{
- if (curStage == Stage.Anestrus && ticksToNextCycle > 0) return ticksToNextCycle / Configurations.CycleAcceleration;
+ if (curStage == Stage.Anestrus && ticksToNextCycle > 0) return ticksToNextCycle / Configurations.CycleAcceleration;
else return base.TicksToNextStage();
}
@@ -104,13 +104,11 @@ namespace RJW_Menstruation
protected override void AnestrusAction()
{
- if (ticksToNextCycle <= 0)
+ if (ticksToNextCycle <= 0 && IsBreedingSeason())
{
ticksToNextCycle = (int)(averageCycleIntervalTicks * (1 + Rand.Range(-cycleVariability, cycleVariability)));
- if (IsBreedingSeason()) GoNextStage(Stage.Follicular);
- return;
+ GoNextStage(Stage.Follicular);
}
- StayCurrentStage();
}
public override void CopyCycleProperties(HediffComp_Menstruation original)
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Pheromones.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Pheromones.cs
index 8462b19..42b2aac 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Pheromones.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Pheromones.cs
@@ -40,7 +40,7 @@ namespace RJW_Menstruation
}
catch (Exception ex)
{
- Log.Error($"Error when trying to emit pheromones: {ex}");
+ Log.Error($"Error when trying to emit pheromones from pawn {Pawn}: {ex}");
}
}
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
index ce0efe9..79c13a9 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs
@@ -179,7 +179,7 @@ namespace RJW_Menstruation
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");
+ if (GeneratePawn?.ReturnType != typeof(Pawn)) throw new InvalidOperationException("GeneratePawn not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(GeneratePawn))
@@ -233,7 +233,7 @@ namespace RJW_Menstruation
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");
+ if (ApplyBirthOutcome?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(ApplyBirthOutcome))
@@ -283,8 +283,8 @@ namespace RJW_Menstruation
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 (ApplyBirthOutcome?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found");
+ foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(ApplyBirthOutcome))
yield return CodeInstruction.Call(typeof(Ritual_ChildBirth_Apply_Patch), nameof(Ritual_ChildBirth_Apply_Patch.ApplyBirthLoop));
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 ffd37aa..2092d1f 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/HediffComps/MenstruationUtility.cs
@@ -22,7 +22,7 @@ namespace RJW_Menstruation
public static IEnumerable GetMenstruationComps(this Pawn pawn)
{
- List hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll(h => VariousDefOf.AllVaginas.Contains(h.def));
+ List hedifflist = pawn.health.hediffSet.hediffs.FindAll(h => VariousDefOf.AllVaginas.Contains(h.def));
if (hedifflist == null) yield break;
foreach (Hediff hediff in hedifflist)
{
@@ -63,17 +63,7 @@ namespace RJW_Menstruation
public static HediffComp_Anus GetAnusComp(this Pawn pawn)
{
- List hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn))?.FindAll((Hediff h) => h.def.defName.ToLower().Contains("anus"));
- HediffComp_Anus result;
- if (!hedifflist.NullOrEmpty())
- {
- foreach (Hediff h in hedifflist)
- {
- result = h.TryGetComp();
- if (result != null) return result;
- }
- }
- return null;
+ return pawn.health.hediffSet.hediffs.FirstOrDefault((Hediff h) => VariousDefOf.AllAnuses.Contains(h.def))?.TryGetComp();
}
[Obsolete("This method is obsolete and can cause ambiguity. Use GetMenstruationCompFromVagina or GetMenstruationCompFromPregnancy instead.", true)]
@@ -151,7 +141,7 @@ namespace RJW_Menstruation
else if (gestationProgress < 0.8f) icon = fetustex + "04";
else icon = fetustex + "05";
- return TryGetTwinsIcon(icon, babycount) ?? ContentFinder.Get((icon), true);
+ return TryGetTwinsIcon(icon, babycount) ?? ContentFinder.Get(icon, true);
}
public static Texture2D TryGetTwinsIcon(string path, int babycount)
@@ -170,7 +160,7 @@ namespace RJW_Menstruation
List insectEggs = new List();
comp.Pawn.health.hediffSet.GetHediffs(ref insectEggs);
- if (!insectEggs.NullOrEmpty() && insectEggs.Sum(hediff => hediff.eggssize) > 1.0f) return null; // same logic as "Stuffed" in GetInsectEggedIcon
+ if (insectEggs?.Sum(hediff => hediff.eggssize) > 1.0f) return null; // same logic as "Stuffed" in GetInsectEggedIcon
string icon = comp.WombTex;
float cumpercent = comp.TotalCumPercent;
@@ -193,7 +183,7 @@ namespace RJW_Menstruation
else if (cumpercent < 0.89f) icon += "_Cum_15";
else if (cumpercent < 0.95f) icon += "_Cum_16";
else icon += "_Cum_17";
- Texture2D cumtex = ContentFinder.Get((icon), true);
+ Texture2D cumtex = ContentFinder.Get(icon, true);
return cumtex;
}
public static Texture2D GetInsectEggedIcon(this HediffComp_Menstruation comp)
@@ -316,15 +306,13 @@ namespace RJW_Menstruation
}
- public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp, bool drawOrigin = false)
+ public static Texture2D GetGenitalIcon(this Pawn pawn, HediffComp_Menstruation comp)
{
Hediff hediff = comp?.parent;
if (hediff == null) return ContentFinder.Get("Genitals/Vagina00", true);
//HediffComp_Menstruation comp = hediff.GetMenstruationComp();
string icon;
- float severity;
- if (drawOrigin) severity = comp.OriginVagSize;
- else severity = hediff.Severity;
+ float severity = hediff.Severity;
if (comp != null) icon = comp.VagTex;
else icon = "Genitals/Vagina";
@@ -341,30 +329,18 @@ namespace RJW_Menstruation
else if (severity < 1.01f) icon += "10"; //cavernous
else icon += "11"; //abyssal
- return ContentFinder.Get((icon), true);
+ return ContentFinder.Get(icon, true);
}
- public static Texture2D GetAnalIcon(this Pawn pawn, bool drawOrigin = false)
+ public static Texture2D GetAnalIcon(this Pawn pawn)
{
- Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ??
- Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault(h => h.def.defName.ToLower().Contains("anus"));
- if (hediff == null) return ContentFinder.Get(("Genitals/Anal00"), true);
+ Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ??
+ pawn.health.hediffSet.hediffs.FirstOrDefault(h => h.def.defName.ToLower().Contains("anus"));
+ if (hediff == null) return ContentFinder.Get("Genitals/Anal00", true);
+
+ string icon = ((CompProperties_Anus)hediff.GetAnusComp()?.props)?.analTex ?? "Genitals/Anal";
+ float severity = hediff.Severity;
- string icon;
- float severity;
- HediffComp_Anus comp = hediff.GetAnusComp();
- if (comp != null)
- {
- CompProperties_Anus Props = (CompProperties_Anus)comp.props;
- icon = Props.analTex ?? "Genitals/Anal";
- if (drawOrigin) severity = comp.OriginAnusSize;
- else severity = hediff.Severity;
- }
- else
- {
- icon = "Genitals/Anal";
- severity = hediff.Severity;
- }
if (severity < 0.20f) icon += "00"; //micro
else if (severity < 0.40f) icon += "01"; //tight
else if (severity < 0.60f) icon += "02"; //average
@@ -372,7 +348,7 @@ namespace RJW_Menstruation
else if (severity < 1.01f) icon += "04"; //cavernous
else icon += "05"; //abyssal
- return ContentFinder.Get((icon), true);
+ return ContentFinder.Get(icon, true);
}
public static float GestationHours(this Hediff hediff)
@@ -403,6 +379,18 @@ namespace RJW_Menstruation
else return variability;
}
+ public static bool ShouldCycle(this Pawn pawn)
+ {
+ if (!Configurations.EnableAnimalCycle && pawn.IsAnimal()) return false;
+ if (pawn.GetComp() != null) return false;
+ if (pawn.RaceHasOviPregnancy()) return false;
+
+ if (ModsConfig.BiotechActive && pawn.genes != null &&
+ pawn.genes.GenesListForReading.Select(gene => gene.def).Intersect(VariousDefOf.EggLayerGenes).Any()) return false;
+
+ return true;
+ }
+
public static bool IsInEstrus(this Pawn pawn, bool visible = true)
{
if (pawn.Dead) return false;
@@ -450,8 +438,8 @@ namespace RJW_Menstruation
}
if (precept != null) return true;
- else return pawn.HasQuirk(QuirkUtility.Quirks.Breeder) ||
- pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish);
+ else return pawn.IsBreeder() ||
+ pawn.HasImpregnationFetish();
}
public static float DamagePants(this Pawn pawn, float fluidAmount)
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 2cc6646..61ce541 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Hediff_MultiplePregnancy.cs
@@ -23,7 +23,7 @@ namespace RJW_Menstruation
{
if (is_discovered ||
!xxx.is_human(pawn) ||
- pawn.HasQuirk(QuirkUtility.Quirks.Breeder) || (pawn.Ideo?.HasPrecept(VariousDefOf.Pregnancy_Required) ?? false) ||
+ pawn.IsBreeder() || (pawn.Ideo?.HasPrecept(VariousDefOf.Pregnancy_Required) ?? false) ||
(pawn.relations?.DirectRelations?.Find(x => x.def.Equals(PawnRelationDefOf.Spouse) ||
x.def.Equals(PawnRelationDefOf.Fiance))) != null)
return;
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/MenstruationModExtension.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/MenstruationModExtension.cs
new file mode 100644
index 0000000..c3a8fbe
--- /dev/null
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/MenstruationModExtension.cs
@@ -0,0 +1,15 @@
+using Verse;
+
+namespace RJW_Menstruation
+{
+ public class MenstruationModExtension : DefModExtension
+ {
+ public float eggLifeTimeFactor = 1.0f;
+ public bool neverEstrus = false;
+ public bool alwaysEstrus = false;
+ public float ovulationFactor = 1.0f;
+ public bool noBleeding = false;
+
+ public bool disableCycle = 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 4bd3cef..eb8777a 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
@@ -155,7 +155,7 @@ namespace RJW_Menstruation
public static IEnumerable Transpiler(IEnumerable instructions)
{
- if (GetPregnancyHediff == null || GetPregnancyHediff.ReturnType != typeof(Hediff)) throw new InvalidOperationException("GetPregnancyHediff not found");
+ if (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)
{
@@ -192,23 +192,6 @@ namespace RJW_Menstruation
}
}
- [HarmonyPatch(typeof(Pawn_GeneTracker), "AddGene", new Type[] { typeof(Gene), typeof(bool) })]
- public class AddGene_Patch
- {
- public static bool Prefix(ref Gene __result, Gene gene, Pawn ___pawn)
- {
- if (!VariousDefOf.WombGenes.Contains(gene.def)) return true;
- bool keepGene;
- if (PawnGenerator.IsBeingGenerated(___pawn))
- // During pawn generation, the vagina hediff doesn't exist yet, so use gender to decide instead
- // Not the most accurate, but close enough
- keepGene = ___pawn.gender == Gender.Female;
- else keepGene = ___pawn.GetMenstruationComps().Any();
- if (!keepGene) __result = null;
- return keepGene;
- }
- }
-
[HarmonyPatch(typeof(Pawn_GeneTracker), "Notify_GenesChanged")]
public class Notify_GenesChanged_Patch
{
@@ -219,6 +202,17 @@ namespace RJW_Menstruation
}
}
+ [HarmonyPatch(typeof(StatPart_FertilityByGenderAge), "AgeFactor")]
+ public class AgeFactor_Patch
+ {
+ public static void Postfix(ref float __result, Pawn pawn)
+ {
+ if (__result <= 0.0f) return;
+ if (pawn.GetMenstruationComps().Any(comp => comp.CalculatingOvulationChance))
+ __result = 1.0f;
+ }
+ }
+
//[HarmonyPatch(typeof(ChildcareUtility), nameof(ChildcareUtility.SuckleFromLactatingPawn))]
//public class GreedyConsume_Patch
//{
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 86ef4d9..b0ab1a3 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
@@ -43,6 +43,8 @@ namespace RJW_Menstruation
private static Gizmo CreateGizmo_WombStatus(Pawn pawn, HediffComp_Menstruation comp)
{
+ if (!comp.loaded)
+ comp.Initialize();
Texture2D icon, icon_overlay;
StringBuilder description = new StringBuilder();
if (Configurations.Debug)
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs
index 616f591..98e5997 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs
@@ -1,5 +1,6 @@
using HarmonyLib;
using RimWorld;
+using rjw;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -36,10 +37,6 @@ namespace RJW_Menstruation
if (t.Pawn == pawn && pawn.HasMenstruationComp()) opts.AddDistinct(MakeSelfMenu(pawn, t));
break;
}
-
-
-
-
}
public static FloatMenuOption MakeSelfMenu(Pawn pawn, LocalTargetInfo target)
@@ -53,60 +50,28 @@ namespace RJW_Menstruation
}
}
- //[HarmonyPatch(typeof(HealthCardUtility), "DrawHediffListing")]
- //public class DrawHediffListing_Patch
- //{
- // public const float buttonWidth = 80f;
- // public const float buttonHeight = 20f;
- //
- // public static void Postfix(Rect rect, Pawn pawn, bool showBloodLoss)
- // {
- // if (Configurations.EnableButtonInHT && pawn.HasMenstruationComp())
- // {
- // Rect buttonrect = new Rect(rect.xMax - buttonWidth, rect.yMax - buttonHeight, buttonWidth, buttonHeight);
- // if (Widgets.ButtonText(buttonrect, "Status"))
- // {
- // Dialog_WombStatus.ToggleWindow(pawn,pawn.GetMenstruationComp());
- // }
- // }
- //
- //
- // }
- //}
-
- [HarmonyPatch(typeof(HealthCardUtility), "DrawHediffRow")]
- public class DrawHediffRow_Patch
+ [HarmonyPatch(typeof(HealthCardUtility), "DrawOverviewTab")]
+ public class DrawOverviewTab_Patch
{
public const float buttonWidth = 50f;
public const float buttonHeight = 20f;
- private static HediffComp_Menstruation GetFirstMenstruation(IEnumerable diffs)
+ public static void Prefix(Rect leftRect, Pawn pawn, float curY)
{
- foreach (Hediff diff in diffs)
+ if (Configurations.EnableButtonInHT && pawn.ShowStatus() && pawn.ShouldCycle())
{
- HediffComp_Menstruation comp = diff.GetMenstruationCompFromVagina();
- if (comp != null) return comp;
- }
- return null;
- }
-
- public static void Prefix(Rect rect, Pawn pawn, IEnumerable diffs, ref float curY)
- {
- if (Configurations.EnableButtonInHT && pawn.ShowStatus())
- {
- HediffComp_Menstruation comp = GetFirstMenstruation(diffs);
+ HediffComp_Menstruation comp = pawn.GetFirstMenstruationComp();
if (comp != null)
{
- Rect buttonrect = new Rect((rect.xMax) / 2 - 5f, curY + 2f, buttonWidth, buttonHeight);
- if (Widgets.ButtonText(buttonrect, Translations.Button_HealthTab))
+ Text.Font = GameFont.Tiny;
+ Rect buttonRect = new Rect(leftRect.xMax - buttonWidth - 8f, curY + 4f, buttonWidth, buttonHeight);
+ if (Widgets.ButtonText(buttonRect, Translations.Button_HealthTab))
{
Dialog_WombStatus.ToggleWindow(pawn, comp);
}
}
}
-
}
-
}
[HarmonyPatch(typeof(CompBiosculpterPod), nameof(CompBiosculpterPod.CannotUseNowPawnCycleReason), new Type[] { typeof(Pawn), typeof(Pawn), typeof(CompBiosculpterPod_Cycle), typeof(bool) })]
@@ -120,4 +85,28 @@ namespace RJW_Menstruation
__result = Translations.CannotNoWomb;
}
}
+
+ // Doesn't cover everything, but at least it'll get the auto equip
+ [HarmonyPatch(typeof(Apparel), nameof(Apparel.PawnCanWear))]
+ public class PawnCanWear_Patch
+ {
+ public static void Postfix(ref bool __result, Apparel __instance, Pawn pawn)
+ {
+ if (__result && __instance is Absorber)
+ {
+ __result = pawn.ShouldCycle() && pawn.GetMenstruationComps().Any();
+ }
+ }
+ }
+
+ // Might cause issues when it comes to caravans
+ //[HarmonyPatch(typeof(JobGiver_OptimizeApparel), nameof(JobGiver_OptimizeApparel.ApparelScoreRaw))]
+ //public class ApparelScoreRaw_Patch
+ //{
+ // public static void Postfix(ref float __result, Pawn pawn, Apparel ap)
+ // {
+ // if (__result > 0f && ap is Absorber && !pawn.GetMenstruationComps().Any(comp => comp.TotalCum > 0))
+ // __result = -10f;
+ // }
+ //}
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs
index fdb90d9..eb776e3 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs
@@ -24,14 +24,14 @@ namespace RJW_Menstruation
if (sextype != xxx.rjwSextype.Vaginal && sextype != xxx.rjwSextype.DoublePenetration) return true;
- if (partner.IsAnimal() && !Configurations.EnableAnimalCycle) return true;
+ if (!partner.ShouldCycle()) return true;
if (!InteractionCanCausePregnancy(props)) return false;
List pawnparts = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn));
HediffComp_Menstruation comp;
- if (pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish) || partner.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish) || partner.IsInEstrus())
+ if (pawn.HasImpregnationFetish() || partner.HasImpregnationFetish() || partner.IsInEstrus())
comp = partner.GetFertileMenstruationComp();
else comp = partner.GetRandomMenstruationComp();
if (comp == null) return true;
@@ -100,9 +100,9 @@ namespace RJW_Menstruation
{
public static bool Prefix(Pawn pawn, Pawn partner) // partner has vagina
{
- if (partner.IsAnimal() && !Configurations.EnableAnimalCycle) return true;
+ if (!partner.ShouldCycle()) return true;
HediffComp_Menstruation comp;
- if (pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish) || partner.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish) || partner.IsInEstrus())
+ if (pawn.HasImpregnationFetish() || partner.HasImpregnationFetish() || partner.IsInEstrus())
comp = partner.GetFertileMenstruationComp();
else comp = partner.GetRandomMenstruationComp();
if (comp == null)
@@ -125,14 +125,14 @@ namespace RJW_Menstruation
{
private static bool PregnancyBlocksImpregnation(this Pawn pawn, bool _)
{
- if (!Configurations.EnableAnimalCycle && pawn.IsAnimal()) return pawn.IsPregnant();
+ if (!pawn.ShouldCycle()) return pawn.IsPregnant();
else if (pawn.GetMenstruationComps().Any()) return false;
else return pawn.IsPregnant();
}
private static readonly MethodInfo IsPregnant = AccessTools.Method(typeof(PawnExtensions), nameof(PawnExtensions.IsPregnant), new System.Type[] { typeof(Pawn), typeof(bool) });
public static IEnumerable Transpiler(IEnumerable instructions)
{
- if (IsPregnant == null || IsPregnant.ReturnType != typeof(bool)) throw new System.InvalidOperationException("IsPregnant not found");
+ if (IsPregnant?.ReturnType != typeof(bool)) throw new System.InvalidOperationException("IsPregnant not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(IsPregnant))
@@ -179,7 +179,7 @@ namespace RJW_Menstruation
{
// Awkward, but it'll have to do
Pawn pawn = props.pawn;
- if (__result == 0 || !pawn.HasQuirk(QuirkUtility.Quirks.ImpregnationFetish) || !props.hasPartner()) return;
+ if (__result == 0 || !pawn.HasImpregnationFetish() || !props.hasPartner()) return;
// Check if the existing code would have added the count
Pawn partner = props.partner;
@@ -238,7 +238,7 @@ namespace RJW_Menstruation
private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup));
public static IEnumerable Transpiler(IEnumerable instructions)
{
- if (MinimumFuckabilityToHookup == null || MinimumFuckabilityToHookup.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumFuckabilityToHookup not found");
+ if (MinimumFuckabilityToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumFuckabilityToHookup not found");
bool first_fuckability = true;
foreach (CodeInstruction instruction in instructions)
{
@@ -274,8 +274,8 @@ namespace RJW_Menstruation
private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup));
public static IEnumerable Transpiler(IEnumerable instructions)
{
- if (MinimumAttractivenessToHookup == null || MinimumAttractivenessToHookup.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumAttractivenessToHookup not found");
- if (MinimumRelationshipToHookup == null || MinimumRelationshipToHookup.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumRelationshipToHookup not found");
+ if (MinimumAttractivenessToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumAttractivenessToHookup not found");
+ if (MinimumRelationshipToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumRelationshipToHookup not found");
LocalBuilder pawn_index = null;
// Like in the last one, we switch the arguments around for the second load
bool first_attractiveness = true;
@@ -342,10 +342,12 @@ namespace RJW_Menstruation
{
if (!pawn.IsHashIntervalTick(__instance.ticks_between_thrusts)) return;
xxx.rjwSextype sextype = __instance.Sexprops.sexType;
- if (!(target is Pawn partner) || pawn == partner) return;
+ if (!(target is Pawn partner)) return;
if (sextype != xxx.rjwSextype.Vaginal && sextype != xxx.rjwSextype.DoublePenetration) return;
if (__instance.Sexprops.usedCondom) return;
+ if (AndroidsCompatibility.IsAndroid(pawn)) return;
if (!Impregnate_Patch.InteractionCanCausePregnancy(__instance.Sexprops)) return;
+ if (!partner.ShouldCycle()) return;
// Archotech penises have more control. Or something.
CompHediffBodyPart penisComp = pawn.GetGenitalsList()?.Find(genital => (genital as Hediff_PartBaseNatural)?.def.defName.ToLower().Contains("penis") ?? false)?.TryGetComp();
@@ -372,26 +374,14 @@ namespace RJW_Menstruation
}
}
- [HarmonyPatch(typeof(PawnCapacityWorker_Fertility), nameof(PawnCapacityWorker_Fertility.CalculateCapacityLevel))]
- public static class PawnCapacityWorker_Fertility_Patch
+ [HarmonyPatch(typeof(PawnCapacityWorker_Fertility), "CalculateAgeImpact")]
+ public static class PawnCapacityWorker_Fertility_Age_Patch
{
- private static float GetFertilityStatOrOne(Thing thing, StatDef stat, bool applyPostProcess, int cacheStaleAfterTicks)
+ public static void Postfix(ref float __result, Pawn pawn)
{
- Pawn pawn = (Pawn)thing;
+ if (__result <= 0.0f) return;
if (pawn.GetMenstruationComps().Any(comp => comp.CalculatingOvulationChance))
- return 1.0f;
- else return thing.GetStatValue(stat, applyPostProcess, cacheStaleAfterTicks);
- }
- private static readonly MethodInfo GetStatValue = AccessTools.Method(typeof(StatExtension), "GetStatValue", new System.Type[] { typeof(Thing), typeof(StatDef), typeof(bool), typeof(int) });
- public static IEnumerable Transpiler(IEnumerable instructions)
- {
- if (GetStatValue == null || GetStatValue.ReturnType != typeof(float)) throw new System.InvalidOperationException("GetStatValue not found");
- foreach (CodeInstruction instruction in instructions)
- {
- if (instruction.Calls(GetStatValue))
- yield return CodeInstruction.Call(typeof(PawnCapacityWorker_Fertility_Patch), nameof(GetFertilityStatOrOne));
- else yield return instruction;
- }
+ __result = 1.0f;
}
}
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
index 7cbf28c..9b9bdad 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs
@@ -20,9 +20,8 @@ namespace RJW_Menstruation
StringBuilder res = new StringBuilder();
- IEnumerable babiesdistinct = babies.Distinct(new RaceComparer());
int iteration = 0;
- foreach (Pawn baby in babiesdistinct)
+ foreach (Pawn baby in babies.Distinct(new RaceComparer()))
{
int num = babies.Where(x => x.def.Equals(baby.def)).Count();
if (iteration > 0) res.Append(", ");
@@ -43,9 +42,8 @@ namespace RJW_Menstruation
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)
+ foreach (Pawn baby in babies.Distinct(new FatherComparer(mother)))
{
if (iteration > 0) res.Append(", ");
res.Append(Utility.GetFather(baby, mother)?.LabelShort ?? Translations.Dialog_FatherUnknown);
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/QuirkUtility.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/QuirkUtility.cs
index c8c2352..409d3d7 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/QuirkUtility.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/QuirkUtility.cs
@@ -6,14 +6,14 @@ namespace RJW_Menstruation
public static class QuirkUtility
{
// All quirks used in Menstruation
- public enum Quirks
+ private enum Quirks
{
Breeder,
ImpregnationFetish,
Messy,
Teratophile,
}
- public static bool HasQuirk(this Pawn pawn, Quirks quirk)
+ private static bool HasQuirk(Pawn pawn, Quirks quirk)
{
switch (quirk)
{
@@ -29,5 +29,9 @@ namespace RJW_Menstruation
return false;
}
}
+ public static bool IsBreeder(this Pawn pawn) => HasQuirk(pawn, Quirks.Breeder);
+ public static bool HasImpregnationFetish(this Pawn pawn) => HasQuirk(pawn, Quirks.ImpregnationFetish);
+ public static bool IsMessy(this Pawn pawn) => HasQuirk(pawn, Quirks.Messy);
+ public static bool IsTeratophile(this Pawn pawn) => HasQuirk(pawn, Quirks.Teratophile);
}
}
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 0c4aa45..33cf9ec 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/RJW_Menstruation.csproj
@@ -74,6 +74,7 @@
+
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs
index 5e4dd91..c95454a 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Things.cs
@@ -1,6 +1,7 @@
using RimWorld;
using rjw;
using System.Collections.Generic;
+using System.Text;
using System.Xml;
using UnityEngine;
using Verse;
@@ -186,6 +187,7 @@ namespace RJW_Menstruation
}
public class AbsorberModExtension : DefModExtension
{
+ public float passiveAbsorptionPerHour = 0.1f;
public bool leakAfterDirty = false;
public bool effectsAfterDirty = false;
public ThingDef dirtyDef = null;
@@ -198,7 +200,7 @@ namespace RJW_Menstruation
public float absorbedfluids = 0;
public bool dirty = false;
public int wearTicks = 0;
- protected virtual float PassiveAbsorptionPerHour => 0.1f;
+ public virtual float PassiveAbsorptionPerHour => def.GetModExtension().passiveAbsorptionPerHour;
public virtual bool LeakAfterDirty => def.GetModExtension().leakAfterDirty;
public virtual bool EffectAfterDirty => def.GetModExtension().effectsAfterDirty;
public virtual ThingDef DirtyDef => def.GetModExtension().dirtyDef;
@@ -211,9 +213,25 @@ namespace RJW_Menstruation
public virtual void WearEffect(int tickInterval)
{
absorbedfluids += PassiveAbsorptionPerHour * tickInterval / GenDate.TicksPerHour;
+ CheckDirty();
if (dirty) wearTicks += tickInterval;
}
+ public void CheckDirty()
+ {
+ if (absorbedfluids > this.GetStatValue(VariousDefOf.MaxAbsorbable) && !(Wearer?.apparel?.IsLocked(this) ?? false) && DirtyDef != def && DirtyDef != null)
+ {
+ bool oldHasStats = !def.equippedStatOffsets.NullOrEmpty();
+ bool newHasStats = !DirtyDef.equippedStatOffsets.NullOrEmpty();
+ def = DirtyDef;
+ dirty = true;
+ Wearer.outfits?.forcedHandler?.SetForced(this, false);
+ if (oldHasStats || newHasStats)
+ Wearer.health.capacities.Notify_CapacityLevelsDirty();
+ Wearer.apparel.Notify_ApparelChanged();
+ }
+ }
+
public override Color DrawColorTwo => fluidColor;
public override void ExposeData()
@@ -231,15 +249,30 @@ namespace RJW_Menstruation
Scribe_Values.Look(ref fluidColor, "fluidColor", Color.white);
}
+ public override string DescriptionDetailed
+ {
+ get
+ {
+ StringBuilder text = new StringBuilder(base.DescriptionDetailed);
+ text.AppendLine();
+ text.Append(Translations.Description_Absorbed);
+ text.Append(": ");
+ text.Append(absorbedfluids.ToStringDecimalIfSmall());
+ text.Append("/");
+ text.Append(this.GetStatValue(VariousDefOf.MaxAbsorbable).ToStringDecimalIfSmall());
+ text.Append("ml");
+
+ return text.ToString();
+ }
+ }
}
public class Absorber_Tampon : Absorber
{
- protected override float PassiveAbsorptionPerHour => 0.5f;
public override void DirtyEffect(int tickInterval)
{
- if (wearTicks > MinHrstoDirtyEffect * GenDate.TicksPerHour && Rand.MTBEventOccurs(100.0f, GenDate.TicksPerHour, tickInterval) && !Wearer.apparel.IsLocked(this))
+ if (wearTicks > MinHrstoDirtyEffect * GenDate.TicksPerHour && Rand.MTBEventOccurs(100.0f, GenDate.TicksPerHour, tickInterval) && !(Wearer.apparel?.IsLocked(this) ?? false))
{
Wearer.health.AddHediff(HediffDefOf.WoundInfection, Genital_Helper.get_genitalsBPR(Wearer));
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
index 0da2b3c..6c511cc 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Translations.cs
@@ -44,6 +44,7 @@ namespace RJW_Menstruation
public static readonly string Dialog_WombInfo08 = "Dialog_WombInfo08".Translate();
public static readonly string Dialog_WombInfo09 = "Dialog_WombInfo09".Translate();
public static readonly string Dialog_WombInfo10 = "Dialog_WombInfo10".Translate();
+ public static readonly string Description_Absorbed = "Description_Absorbed".Translate();
public static readonly string Option1_Label_1 = "Option1_Label_1".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 0448aac..0affda5 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
@@ -388,10 +388,9 @@ namespace RJW_Menstruation
Rect genitalIconRect = new Rect(rect.x, rect.y + fontheight, genitalRectWidth, genitalRectHeight);
Rect genitalVaginaLabelRect = new Rect(rect.x, rect.y + 10f, genitalRectWidth, fontheight);
Rect genitalAnusLabelRect = new Rect(rect.x, rect.y + fontheight + genitalRectHeight, genitalRectWidth, fontheight);
- bool showOrigin = Mouse.IsOver(genitalIconRect) && Input.GetMouseButton(0);
- vagina = pawn.GetGenitalIcon(comp, showOrigin);
- anal = pawn.GetAnalIcon(showOrigin);
+ vagina = pawn.GetGenitalIcon(comp);
+ anal = pawn.GetAnalIcon();
GUI.color = new Color(1.00f, 0.47f, 0.47f, 1);
GUI.Box(rect, "", boxstyle);
GUI.color = Utility.SafeSkinColor(pawn);
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs
index db91411..ae2cb4a 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/Utility.cs
@@ -86,7 +86,7 @@ namespace RJW_Menstruation
{
res = 0.0f;
}
- if (pawn.HasQuirk(QuirkUtility.Quirks.Messy)) res *= Rand.Range(4.0f, 8.0f);
+ if (pawn.IsMessy()) res *= Rand.Range(4.0f, 8.0f);
return res;
}
@@ -95,16 +95,7 @@ namespace RJW_Menstruation
public static HediffComp_Breast GetBreastComp(this Pawn pawn)
{
- List hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn))?.FindAll(h => VariousDefOf.AllBreasts.Contains(h.def));
- if (hedifflist.NullOrEmpty()) hedifflist = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_uddersBPR(pawn))?.FindAll(h => VariousDefOf.AllBreasts.Contains(h.def));
- if (hedifflist.NullOrEmpty()) return null;
- HediffComp_Breast result;
- foreach (Hediff h in hedifflist)
- {
- result = h.TryGetComp();
- if (result != null) return result;
- }
- return null;
+ return pawn.health.hediffSet.hediffs.FirstOrDefault((Hediff h) => VariousDefOf.AllBreasts.Contains(h.def))?.TryGetComp();
}
public static HediffComp_Breast GetBreastComp(this Hediff hediff)
@@ -192,8 +183,7 @@ namespace RJW_Menstruation
public static void DrawBreastIcon(this Pawn pawn, Rect rect)
{
- Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def)) ??
- Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_uddersBPR(pawn)).FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def));
+ Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def));
Texture2D breast, nipple, areola;
if (hediff != null)
{
@@ -351,20 +341,19 @@ namespace RJW_Menstruation
public static string GetVaginaLabel(this Pawn pawn)
{
- Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)).Find(h => VariousDefOf.AllVaginas.Contains(h.def));
+ Hediff hediff = pawn.health.hediffSet.hediffs.Find(h => VariousDefOf.AllVaginas.Contains(h.def));
return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")" + "\n" + xxx.CountOfSex.LabelCap.CapitalizeFirst() + ": " + pawn.records.GetAsInt(xxx.CountOfSex);
}
public static string GetAnusLabel(this Pawn pawn)
{
- Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ??
+ Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllAnuses.Contains(h.def)) ??
Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn)).FirstOrDefault(h => h.def.defName.ToLower().Contains("anus"));
if (hediff != null) return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")";
else return "";
}
public static string GetBreastLabel(this Pawn pawn)
{
- Hediff hediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_breastsBPR(pawn)).FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def)) ??
- Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_uddersBPR(pawn)).FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def));
+ Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => VariousDefOf.AllBreasts.Contains(h.def));
if (hediff != null) return hediff.LabelBase.CapitalizeFirst() + "\n(" + hediff.LabelInBrackets + ")";
else return "";
}
@@ -416,7 +405,7 @@ namespace RJW_Menstruation
{
Pawn res = pawn.GetFather();
if (res != null) return res;
- else res = pawn.relations?.GetFirstDirectRelationPawn(PawnRelationDefOf.Parent, x => x != mother) ?? null;
+ else res = pawn.relations?.GetFirstDirectRelationPawn(PawnRelationDefOf.Parent, x => x != mother);
return res;
}
@@ -448,7 +437,7 @@ namespace RJW_Menstruation
{
if (!Configurations.EnableWombIcon) return false;
if (pawn.Drafted && !Configurations.EnableDraftedIcon) return false;
- if (pawn.IsAnimal() && !Configurations.EnableAnimalCycle) return false;
+ if (!pawn.ShouldCycle()) return false;
return true;
}
diff --git a/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs b/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs
index cd4bb56..16903b2 100644
--- a/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs
+++ b/1.4/source/RJW_Menstruation/RJW_Menstruation/VariousDefOf.cs
@@ -40,44 +40,26 @@ namespace RJW_Menstruation
public static readonly ThoughtDef TookContraceptivePill = DefDatabase.GetNamed("TookContraceptivePill");
public static readonly ThoughtDef HateTookContraceptivePill = DefDatabase.GetNamed("HateTookContraceptivePill");
public static readonly ThoughtDef EggRestorationReceived = DefDatabase.GetNamed("EggRestorationReceived");
- public static readonly CompProperties_Menstruation HumanVaginaCompProperties = (CompProperties_Menstruation)Genital_Helper.average_vagina.comps.FirstOrDefault(x => x is CompProperties_Menstruation);
+ public static readonly CompProperties_Menstruation HumanVaginaCompProperties = Genital_Helper.average_vagina.CompProps();
public static readonly KeyBindingDef OpenStatusWindowKey = DefDatabase.GetNamed("OpenStatusWindow");
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;
private static HashSet allvaginas = null;
private static HashSet allanuses = null;
private static HashSet allbreasts = null;
+ private static HashSet egglayergenes = null;
public static List AllRaces
{
get
{
if (allraces != null) return allraces;
+ allraces = DefDatabase.AllDefsListForReading.Where(thingdef => thingdef.race?.IsFlesh ?? false).ToList();
- List allThings = DefDatabase.AllDefsListForReading;
- allraces = allThings.FindAll(x => x.race != null && x.race.IsFlesh);
return allraces;
}
}
@@ -86,9 +68,8 @@ namespace RJW_Menstruation
get
{
if (allkinds != null) return allkinds;
+ allkinds = DefDatabase.AllDefsListForReading.Where(pawnkinddef => pawnkinddef.race != null).ToList();
- List allKinds = DefDatabase.AllDefsListForReading;
- allkinds = allKinds.FindAll(x => x.race != null);
return allkinds;
}
}
@@ -161,6 +142,16 @@ namespace RJW_Menstruation
return allbreasts;
}
}
+ public static HashSet EggLayerGenes
+ {
+ get
+ {
+ if (egglayergenes != null) return egglayergenes;
+ egglayergenes = DefDatabase.AllDefsListForReading.Where(geneDef => geneDef.GetModExtension()?.disableCycle ?? false).ToHashSet();
+
+ return egglayergenes;
+ }
+ }
// Defs from Milkable Colonists
public static readonly HediffDef Hediff_Lactating_Drug = DefDatabase.GetNamedSilentFail("Lactating_Drug");
diff --git a/About/About.xml b/About/About.xml
index 9c10224..c4c11a0 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -1,7 +1,9 @@
+ rjw.menstruation
RJW Menstruation Cycle
lutepickle
+ https://gitgud.io/lutepickle/rjw_menstruation/
1.2
1.3
@@ -28,13 +30,17 @@
Abraxas.RJW.RaceSupport
rjw.milk.humanoid
- rjw.menstruation
+
+
+ conit.thebirdsandthebees
+
+
Adds menstruation mechanics to vaginas:
Wombs cycle between follicular, luteal, and bleeding phases
Tracks eggs ovulated and cum in wombs to determine pregnancy
Womb icon and status window
-Estrus effects
+Estrus and pheromone effects
Race-specific fetus images for many vanilla animals
Pregnancies from multiple eggs and different fathers
Identical siblings
diff --git a/About/Manifest.xml b/About/Manifest.xml
index 028cc7b..09e409c 100644
--- a/About/Manifest.xml
+++ b/About/Manifest.xml
@@ -1,7 +1,7 @@
RJW Menstruation
- 1.0.9.1
+ 1.0.9.4
diff --git a/LoadFolders.xml b/LoadFolders.xml
index 1707748..f711d5c 100644
--- a/LoadFolders.xml
+++ b/LoadFolders.xml
@@ -14,6 +14,5 @@
1.4
1.4/RJW Menstruation Race Support
-
\ No newline at end of file
diff --git a/changelogs.txt b/changelogs.txt
index 96315e4..e21994a 100644
--- a/changelogs.txt
+++ b/changelogs.txt
@@ -1,8 +1,36 @@
+Version 1.0.9.4
+ - Pawns with the egglaying genes from Erin's Corvyia and Outland - Genetics no longer have a menstrual cycle.
+
+Version 1.0.9.3
+ - The biosculptor egg restoration cycle will now give more eggs to races that ovulate more than one egg at a time.
+ - All pawns can now use all menstruation genes, regardless of gender or having a womb.
+ - Egglaying animals no longer have a menstrual cycle.
+ - Fix bug preventing absorbers from becoming dirty.
+
+Version 1.0.9.2
+ - Updated Traditional Chinese translation by Hydrogen.
+ - Fixed the no bleeding gene having positive metabolic efficiency instead of negative.
+ - Fixed ovulation chance not accounting for genes or precepts.
+ - Better handle wombs that are not in the genitals body part.
+ - Handle errors more gracefully when starting a pregnancy.
+ - Fix implanting multiple eggs in an animal when configured to use Biotech pregnancies.
+ - An equipped tampon or pad will now show how much fluid it has absorbed in its tooltip.
+ - Passive absorption will now make a tampon or pad dirty after enough time, even if no fluid was added.
+ - It will take a cloth tampon about 2 days to become dirty passively. A cloth pad will take about 10 days.
+ - An absorber that was force worn will no longer be forced once it becomes dirty.
+ - Pawns without a menstrual cycle will no longer equip absorbers.
+ - Egglaying races no longer have a menstrual cycle, regardless of vagina type.
+ - Pawns with the egglaying genes from Alpha Genes, VE Saurids, or Phytokin no longer have a menstrual cycle.
+ - The womb status button will now appear in a pawn's health tab when using Compact Hediffs, with thanks to Fern.
+ - Tampons and pads are now allowed by default in the worker, soldier, and slave starting outfits.
+
Version 1.0.9.1
+ - Japanese translation for most text by Lokuzt.
- New womb, cum, and fetus graphics by Euldrop.
- Add new ideology-related thoughts with the sexperience-ideology mod.
- New pheromone system: Pawns in visible estrus will increase the sex drive of nearby males. Can be disabled in the options.
- Using the egg restoration biosculptor cycle will give a small mood buff.
+ - Fix some errors related to precum.
- Periodic ovulators that don't bleed will properly enter anestrus after their luteal stage.
- Climacteric/menopausal pawns will have their sex need slow properly when the womb's tick rate is non-default.