diff --git a/About/About.xml b/About/About.xml
index 5d46796..a2eca98 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -19,14 +19,12 @@
steam://url/CommunityFilePage/2009463077
https://github.com/pardeike/HarmonyRimWorld/releases/latest
-
rim.job.world
diff --git a/About/Manifest.xml b/About/Manifest.xml
new file mode 100644
index 0000000..b99a84a
--- /dev/null
+++ b/About/Manifest.xml
@@ -0,0 +1,19 @@
+
+
+ RJW-Genes
+ 1.1.0
+
+ RimJobWorld
+ HugsLib
+
+
+
+ RimJobWorld
+ HugsLib
+
+
+ RJW-LicentiaLabs
+
+ https://github.com/vegapnk/RJW-Genes/tree/main/About/Manifest.xml
+ https://github.com/vegapnk/RJW-Genes
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fce2807..a0963a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,81 @@
+# 1.1.0 (2023-03-04)
+
+1.1.0-beta-1 was released on 05.02.2023.
+
+Changes since beta: Typos, Icons & Merge of Anal & Vaginal Absorber.
+
+## Features:
+
+- Succubus, other Fertilin Xenotypes (see below)
+- Orgasm Rush got a Hediff
+- Unbreakable Gene
+- Age-Transfer and Youth-Fountain per Sex Gene
+- Bisexual and Homosexual Genes with Placeholder Icon
+- Balancing some Genes by changing metabolism and complexity
+- Pheromone Gene (#13, Shabakur)
+- RJW Race-Support Compatibility (#12,#13, Shabakur)
+- Animal Gene Inheritance Gene-Chance Multiplier per Setting (#13, Shabakur)
+- Lots of Debug-Only Logging for Animal Gene Inheritance
+- Patches for some popular Xenotype Mods (Nyaron, Kijin3, Roos Minotaurs, VRE Phytokin)
+- Generous Donor Cheatmode
+- Mod-Settings
+
+## Fertilin:
+
+Big news ! We got a system similar to hemogen running, labelled *Fertilin*.
+
+Pawns gain Fertilin through various sources, and can spend them on various abilities and loose it over time.
+
+Fertilin-Sources:
+
+- Vaginal & Anal Absorption (Through sex in respective types)
+- Cum-Eater (through oral sex, eating cum from Sexperience, or cunnilinguing (?) cumflated pawns)
+- Sex Drain, after Sex apply a debuff to the fucked pawn
+- Cock-Eater, bite off the wiener of downed enemies, own colonists, animals, slaves, not sure about visitors but let me know what you think.
+
+Animals give less Fertilin as a source, configurable in the Mod Settings.
+The Vaginal, Anal and CumEater interactions *empty* the pawns balls and the pawn needs to *recharge*. Gain and recharge are based on cum-production.
+The drainer is a flag - undrained pawns can be drained, drained pawns will not get any debuff and will not give any fertilin.
+
+Fertilin-Abilities:
+
+- Heal Pussy; Rape someone to tend their wounds.
+- Seduce; Target Pawn needs to follow the caster, engaging in sex on collision.
+- Paralysing Kiss; Stun someone in meele range.
+- Naked Prowess; When the pawn is naked, get a 3h buff on meele stats and armor.
+
+Other than that, the Xenotypes tend to have other buffs from base-game to make up for their insatiable hunger.
+
+Xenotypes:
+
+**Succubi** absorb Fertilin through sex and can use it for paralyzing kiss and seduce.
+
+**Incubi** are their male parallels, but gaining fertilin through draining.
+
+**Cumazones** are female only martial fighters, that can only gain fertilin through biting cocks. Be sure to have enough supply before you hire one of these bad bitches.
+
+Incubi and Succubi can spawn in a special event at night when pawns have low sex need. Cumazones can just appear randomly.
+
+**_On Inheritance:_**
+
+We realized that it's not nice if the Succubi Babies do not have all Succubi Genes, and have Fertilin with no use for it or look like wookies instead. Hence, we changed the Fertilin Xenotypes to be Xenogenes (non-inheritable) *BUT* we recommend using the [dominant-gene](https://steamcommunity.com/sharedfiles/filedetails/?id=2884110898) mod.
+If the dominant-gene mod is loaded, our xenotypes will spawn with it, making Succubus Babies Succubi.
+In case you do not want that behaviour, look for the Patch `Patch_Dominant_Gene.xml` and delete it.
+
+**_On Making your own Succubi_:**
+
+Currently Succubi and Incubi only spawn through a special event determined by their xenotype def name. So if you make your own, they will not spawn with this event. Make sure that you have a way to get your custom xenotypes appear. You might want to "just alter" the xenotype xml provided by us, then they will spawn with the event.
+
+## Fixes:
+
+- Issue with Breast-Size (#8) fixed by lowercasing breast-match (Shabakur)
+- Error on Game Load when Licentia Genes are tried to be added to Xenotypes for players without Licentia (#5,#17)
+- Futa Gene only triggers if Pawn is not a futa already (#2)
+- Genitalia Resizing triggers on 20th Birthday (#11)
+- RJW-Gene-Inheritance Settings now do things (#13, Shabakur)
+- Check for Animals in Orgasm Rush, no Orgasm Rush for and from Animals (#15)
+- Using Character Editor, it can happen that the Genes fired twice. I hoped to harden this issue by checking better (#19)
+
# 1.0.1 (2022-12-20)
- Fix issue with Orgasm Rush throwing an Error on Animal Orgasm (Thanks Shabakur)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0e2154e..486a3b9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,6 +16,7 @@ But please consider also the following:
## Contributors
- Shabalox (MechBreeding, InsectBreeding, Animal Gene Inheritance)
+- WasMachenDennSachen (Various Icons)
## Other Credits
@@ -23,4 +24,6 @@ But please consider also the following:
- Many of the Icons I made (e.g. Genitalia Types) include things from [OpenMoji](https://openmoji.org/) which is awesome
- Placeholder, Rapist, Necrophile come from [RJW-Sexperience Ideology](https://gitgud.io/amevarashi/rjw-sexperience-ideology/)
-- Hypersexual & Zoophile comes from [RJW](https://gitgud.io/Ed86/rjw)
\ No newline at end of file
+- Hypersexual & Zoophile comes from [RJW](https://gitgud.io/Ed86/rjw)
+- Cockeater & Naked Prowess come from *WasMachenDennSachen* but I copied it from Discord Chat.
+- Fertilin, Fertilin Drain, Healpussy, Succubus Wing & Tail come from Shabakur
\ No newline at end of file
diff --git a/Common/Assemblies/0Harmony.dll b/Common/Assemblies/0Harmony.dll
deleted file mode 100644
index 86fc5eb..0000000
Binary files a/Common/Assemblies/0Harmony.dll and /dev/null differ
diff --git a/Common/Assemblies/Rjw-Genes.dll b/Common/Assemblies/Rjw-Genes.dll
index 9eef3ca..6ec9a86 100644
Binary files a/Common/Assemblies/Rjw-Genes.dll and b/Common/Assemblies/Rjw-Genes.dll differ
diff --git a/Common/Defs/AbilityDefs/Ability_CockEater.xml b/Common/Defs/AbilityDefs/Ability_CockEater.xml
new file mode 100644
index 0000000..d333c1d
--- /dev/null
+++ b/Common/Defs/AbilityDefs/Ability_CockEater.xml
@@ -0,0 +1,34 @@
+
+
+
+ rjw_genes_cockeater
+ Eat Cock
+ Eat the cock of another pawn, restoring fertilin based on the size of the cock.
+ Things/Mote/Heart
+ true
+ true
+ false
+ Mote_CoagulateStencil
+ Coagulate
+ Coagulate_Cast
+ CastAbilityOnThingMelee
+ 402
+
+ Verb_CastAbilityTouch
+ false
+ -1
+ 10
+
+ true
+ false
+ false
+ false
+ true
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/AbilityDefs/Ability_Flight.xml b/Common/Defs/AbilityDefs/Ability_Flight.xml
new file mode 100644
index 0000000..82e6537
--- /dev/null
+++ b/Common/Defs/AbilityDefs/Ability_Flight.xml
@@ -0,0 +1,28 @@
+
+
+
+ rjw_genes_flight
+ fly
+ Fly to a short location using your wings.
+ Genes/Icons/Succubus_Wings
+ 1250
+ false
+
+ Verb_CastAbilityJump
+ fly
+ false
+ false
+ 0.5
+ 19.9
+ true
+ Longjump_Jump
+ Longjump_Land
+
+ true
+ false
+ false
+
+
+ CastJump
+
+
\ No newline at end of file
diff --git a/Common/Defs/AbilityDefs/Ability_NakedProwess.xml b/Common/Defs/AbilityDefs/Ability_NakedProwess.xml
new file mode 100644
index 0000000..82d5bd8
--- /dev/null
+++ b/Common/Defs/AbilityDefs/Ability_NakedProwess.xml
@@ -0,0 +1,47 @@
+
+
+
+ rjw_genes_naked_prowess
+ naked prowess
+ Enhance the strength and resilience of your naked body with fertilin.
+ Genes/Icons/rjw_naked_prowess
+ Things/Mote/Heart
+ CastAbilityOnThing
+ False
+ False
+ True
+
+ 126
+ 0
+
+
+ Verb_CastAbility
+ 2
+ 0
+ False
+ False
+
+ true
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+ CompAbilityEffect_GiveHediff
+ rjw_genes_naked_prowess
+ True
+ true
+
+
+
+ 0.1
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml b/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml
new file mode 100644
index 0000000..8fd3eec
--- /dev/null
+++ b/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml
@@ -0,0 +1,44 @@
+
+
+
+ rjw_genes_paralysingkiss
+ paralysing kiss
+ Paralyse someone briefly with a kiss.
+ Genes/Icons/rjw_genes_lips
+ true
+ true
+ false
+
+ 5
+
+ Mote_CoagulateStencil
+ Coagulate
+ Coagulate_Cast
+ 402
+
+ Verb_CastAbilityTouch
+ false
+ -1
+ 1
+
+ true
+ false
+ false
+ false
+ true
+
+
+
+
+ CompAbilityEffect_Stun
+ -15
+
+
+ rjw_genes_lips
+
+
+ 0.05
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/AbilityDefs/Ability_PussyHeal.xml b/Common/Defs/AbilityDefs/Ability_PussyHeal.xml
new file mode 100644
index 0000000..8f97b60
--- /dev/null
+++ b/Common/Defs/AbilityDefs/Ability_PussyHeal.xml
@@ -0,0 +1,49 @@
+
+
+
+ rjw_genes_pussyheal
+ SexHeal
+ Rape another pawn, so you can heal them with your vagina's special healing power.
+ Things/Mote/Heart
+ false
+ true
+ false
+ Mote_CoagulateStencil
+ Coagulate
+ Coagulate_Cast
+ rjw_genes_lifeforce_healpussy
+ 401
+
+ Verb_CastAbilityTouch
+ false
+ -1
+ 0
+
+ true
+ false
+ false
+ false
+ true
+
+
+
+
+ 0.2
+
+
+ 0.4~0.8
+
+
+
+
+ Rape
+
+
+
+ Vagina
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/AbilityDefs/Ability_Seduce.xml b/Common/Defs/AbilityDefs/Ability_Seduce.xml
new file mode 100644
index 0000000..3310595
--- /dev/null
+++ b/Common/Defs/AbilityDefs/Ability_Seduce.xml
@@ -0,0 +1,43 @@
+
+
+
+ rjw_genes_seduce
+ seduce
+ Seduce the target to approach the caster.
+ Genes/Icons/seduce
+ True
+ true
+ true
+ false
+
+ 10
+
+ Mote_CoagulateStencil
+ Coagulate
+ Coagulate_Cast
+
+ Verb_CastAbility
+ 10
+ 1
+
+ false
+ false
+ false
+ false
+ true
+
+
+
+
+ RJW_Genes.CompAbilityEffect_Seduce
+ Caster
+
+
+ Heart
+
+
+ 0.1
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/DutyDefs/Duties_Succubus.xml b/Common/Defs/DutyDefs/Duties_Succubus.xml
new file mode 100644
index 0000000..bd67a24
--- /dev/null
+++ b/Common/Defs/DutyDefs/Duties_Succubus.xml
@@ -0,0 +1,67 @@
+
+
+
+ rjw_genes_flirt
+
+
+
+
+ SatisfyingNeeds
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.05
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Common/Defs/Effects/Fleck_Lifeforce.xml b/Common/Defs/Effects/Fleck_Lifeforce.xml
new file mode 100644
index 0000000..53ac7b5
--- /dev/null
+++ b/Common/Defs/Effects/Fleck_Lifeforce.xml
@@ -0,0 +1,14 @@
+
+
+
+ rjw_genes_lips
+
+ Genes/Icons/rjw_genes_lips
+
+ MetaOverlays
+ 0.08
+ 1.4
+ 1.5
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneCategories.xml b/Common/Defs/GeneDefs/GeneCategories.xml
similarity index 88%
rename from Common/Defs/Genes/GeneCategories.xml
rename to Common/Defs/GeneDefs/GeneCategories.xml
index ab92117..06b31cc 100644
--- a/Common/Defs/Genes/GeneCategories.xml
+++ b/Common/Defs/GeneDefs/GeneCategories.xml
@@ -37,6 +37,12 @@
15
+
+ rjw_genes_fertilin
+ Fertilin
+ 14
+
+
rjw_genes_breeding
Breeding
@@ -57,8 +63,10 @@
rjw_genes_special
- Genital Related Damage
+ Genital Based Special Abilities
8
+
+
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_Breeding.xml b/Common/Defs/GeneDefs/GeneDefs_Breeding.xml
similarity index 84%
rename from Common/Defs/Genes/GeneDefs_Breeding.xml
rename to Common/Defs/GeneDefs/GeneDefs_Breeding.xml
index fa65c52..bd201cc 100644
--- a/Common/Defs/Genes/GeneDefs_Breeding.xml
+++ b/Common/Defs/GeneDefs/GeneDefs_Breeding.xml
@@ -8,7 +8,9 @@
Pawns with this gene are able to birth mechanoids unharmed.
World/WorldObjects/Expanding/Mechanoids
51
- rjw_genes_breeding
+ rjw_genes_breeding
+ 1
+ -1
@@ -17,7 +19,9 @@
Pawns with this gene are able to hold more insect eggs.
Genes/Icons/More_Egg_Space
52
- rjw_genes_breeding
+ rjw_genes_breeding
+ 1
+ -1
@@ -27,6 +31,8 @@
World/WorldObjects/Expanding/Insects
53
rjw_genes_breeding
+ 1
+ -1
diff --git a/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml b/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml
new file mode 100644
index 0000000..a5cd0ca
--- /dev/null
+++ b/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml
@@ -0,0 +1,69 @@
+
+
+
+ Miscellaneous
+ true
+
+ Wing
+
+
+ Tailbone
+
+
+
+
+ rjw_genes_succubus_wings
+ succubus wings
+ Carriers of this gene grow succubus wings.
+ Genes/Icons/Succubus_Wings
+ (0.75, 0.75, 0.75)
+ 1000
+
+ rjw_genes_flight
+
+
+ rjw_genes_flight
+
+ 1
+ -1
+
+ Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings
+ Skin
+ 2
+ (0.0, 0.01, -0.1)
+ (0.0, 0.0, -0.1)
+ (0.1, 0.0, 0.0)
+
+
+
+
+ rjw_genes_succubus_tail
+ succubus tail
+ Carriers of this gene grow a slender tail ending with a heart that can act as a dexterous fifth limb.
+ Genes/Icons/Succubus_Tail
+ (1, 0, 0)
+ 1000
+
+
+ Manipulation
+ 0.05
+
+
+ 1
+ -1
+
+
+ Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1
+ Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1
+ Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2
+ Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2
+
+ Skin
+ 2
+ (0, 0.2, -0.1)
+ (0, -0.1, 0.1)
+ (0.2, 0.2, 0.1)
+
+ true
+
+
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_Cum.xml b/Common/Defs/GeneDefs/GeneDefs_Cum.xml
similarity index 100%
rename from Common/Defs/Genes/GeneDefs_Cum.xml
rename to Common/Defs/GeneDefs/GeneDefs_Cum.xml
diff --git a/Common/Defs/GeneDefs/GeneDefs_Damage.xml b/Common/Defs/GeneDefs/GeneDefs_Damage.xml
new file mode 100644
index 0000000..f2b0e07
--- /dev/null
+++ b/Common/Defs/GeneDefs/GeneDefs_Damage.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ rjw_genes_elasticity
+ Elasticity
+ rjw_genes_damage
+ This Xenotype cannot get stretched by huge penetrators.
+ Genes/Icons/Elasticity
+ RJW_Genes.Gene_Elasticity
+ -1
+ 1
+ 1
+
+
+
+ rjw_genes_unbreakable
+ Unbreakable
+ rjw_genes_damage
+ This Gene makes the Carrier unable to get mood or social penalties from being raped and they cannot be broken for a long period of time.
+ UI/Icons/Rituals/TrialDefend
+ 2
+ -1
+ 1
+
+ RJW_Genes.Gene_Unbreakable
+
+ FeelingBroken
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_ExtraGenitalia.xml b/Common/Defs/GeneDefs/GeneDefs_ExtraGenitalia.xml
similarity index 100%
rename from Common/Defs/Genes/GeneDefs_ExtraGenitalia.xml
rename to Common/Defs/GeneDefs/GeneDefs_ExtraGenitalia.xml
diff --git a/Common/Defs/Genes/GeneDefs_GenitaliaSizes.xml b/Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml
similarity index 79%
rename from Common/Defs/Genes/GeneDefs_GenitaliaSizes.xml
rename to Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml
index 89bc7f9..cc26c04 100644
--- a/Common/Defs/Genes/GeneDefs_GenitaliaSizes.xml
+++ b/Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml
@@ -9,7 +9,7 @@
rjw_genes_big_male_genitalia
Big Male Genitaliasize
- Penises of this Xenotype are bigger.
+ Penises of this Xenotype are bigger.(Resizing takes place at 20th Birthday)
Genes/Icons/Small_Male_Genitalia
RJW_Genes.Gene_BigMaleGenitalia
751
@@ -21,7 +21,7 @@
rjw_genes_small_male_genitalia
Small Male Genitaliasize
- Penises of this Xenotype are smaller.
+ Penises of this Xenotype are smaller. (Resizing takes place at 20th Birthday)
Genes/Icons/Big_Male_Genitalia
RJW_Genes.Gene_SmallMaleGenitalia
753
@@ -34,7 +34,7 @@
rjw_genes_loose_female_genitalia
Loose Female Genitalia
- Vaginas of this Xenotype are quite spacy.
+ Vaginas of this Xenotype are quite spacy. (Resizing takes place at 20th Birthday)
Genes/Icons/Loose_Female_Genitalia
RJW_Genes.Gene_LooseFemaleGenitalia
754
@@ -46,7 +46,7 @@
rjw_genes_tight_female_genitalia
Tight Female Genitalia
- Vaginas of this Xenotype are pretty tight.
+ Vaginas of this Xenotype are pretty tight.(Resizing takes place at 20th Birthday)
Genes/Icons/Tight_Female_Genitalia
RJW_Genes.Gene_TightFemaleGenitalia
756
@@ -59,7 +59,7 @@
rjw_genes_big_breasts
Big Breasts
- Females of this Xenotype have big honkers.
+ Females of this Xenotype have big honkers.(Resizing takes place at 20th Birthday)
Genes/Icons/Big_Breasts
RJW_Genes.Gene_BigBreasts
757
@@ -71,7 +71,7 @@
rjw_genes_small_breasts
Small Breasts
- Females of this Xenotype have smaller breasts.
+ Females of this Xenotype have smaller breasts.(Resizing takes place at 20th Birthday)
Genes/Icons/Small_Breasts
RJW_Genes.Gene_SmallBreasts
759
@@ -84,7 +84,7 @@
rjw_genes_loose_anus
Loose Anus
- The Anus of this Xenotype is roomy.
+ The Anus of this Xenotype is roomy.(Resizing takes place at 20th Birthday)
Genes/Icons/Loose_Anus
RJW_Genes.Gene_LooseAnus
760
@@ -96,7 +96,7 @@
rjw_genes_tight_anus
Tight Anus
- The anus of this Xenotype is small.
+ The anus of this Xenotype is small.(Resizing takes place at 20th Birthday)
Genes/Icons/Tight_Anus
RJW_Genes.Gene_TightAnus
762
diff --git a/Common/Defs/Genes/GeneDefs_GenitaliaTypes.xml b/Common/Defs/GeneDefs/GeneDefs_GenitaliaTypes.xml
similarity index 97%
rename from Common/Defs/Genes/GeneDefs_GenitaliaTypes.xml
rename to Common/Defs/GeneDefs/GeneDefs_GenitaliaTypes.xml
index f7ab982..7333a5e 100644
--- a/Common/Defs/Genes/GeneDefs_GenitaliaTypes.xml
+++ b/Common/Defs/GeneDefs/GeneDefs_GenitaliaTypes.xml
@@ -22,7 +22,7 @@
rjw_genes_canine_genitalia
canine genitalia
Carriers of this gene develop canine genitalia.
- Genes/Icons/Genitalia_Canine_2
+ Genes/Icons/Genitalia_Canine
RJW_Genes.Gene_CanineGenitalia
803
diff --git a/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml b/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml
new file mode 100644
index 0000000..cc70eae
--- /dev/null
+++ b/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml
@@ -0,0 +1,205 @@
+
+
+
+ rjw_genes_lifeforce
+ fertilin
+ Carriers of this gene have a reserve of biological strength powered by a resource called fertilin. The resource can be gained and spent in various ways, some of which are unlocked by other genes.\n\nCarriers lose 5 fertilin per day from biological entropy. \n\nGene is inactive until carrier is able to have sex.
+ RJW_Genes.Gene_LifeForce
+ RJW_Genes.GeneGizmo_ResourceLifeForce
+ fertilin
+
+ 0.25
+ 0.5
+ 0.75
+
+ true
+ true
+ A reserve of biological strength which can be gained and spent in a variety of ways. \n\nFertilin can be increased by absorbing cum, typically through oral sex or stored cum. \n\nIf fertilin reaches zero, {PAWN_nameDef} will become very unhappy and may try to obtain some forcefully.
+ Genes/Icons/FertilinAlt
+ 0
+ rjw_genes_fertilin
+ -2
+
+ Gives fertilin supply.
+
+
+
+ fert
+
+
+ 0.05
+ 1
+ 1
+
+
+
+ rjw_genes_lifeforce_drain
+ fertilin drain
+ draining
+ Carriers lose an additional 15 fertilin per day from biological entropy.
+ fertilin
+ RJW_Genes.Gene_LifeForceDrain
+ Genes/Icons/FertilinDrainAlt
+ rjw_genes_lifeforce
+ 0.15
+ rjw_genes_fertilin
+ -1
+ 1
+ 6
+
+
+
+ rjw_genes_pussyhealing
+ Pussy Healer
+ pussyhealer
+ Carriers of this gene are able use vaginal sex to tend to other's wounds.
+ Genes/Icons/Healpussy
+ rjw_genes_lifeforce
+ 9
+ rjw_genes_fertilin
+
+ rjw_genes_pussyheal
+
+
+ rjw_genes_pussyheal
+
+ 1
+ -1
+
+
+ life
+ pussy
+ heal
+
+
+
+
+
+ rjw_genes_cockeater
+ Cockeater
+ cockeater
+ Carriers of this gene are able eat cocks to restore their fertilin supply. Cocks are consumed during that process.
+ Genes/Icons/cockeater
+ rjw_genes_lifeforce
+ 11
+ rjw_genes_fertilin
+
+ rjw_genes_cockeater
+
+
+ rjw_genes_cockeater
+
+ 1
+ -1
+
+
+ life
+ cock
+ eat
+
+
+
+
+
+ rjw_genes_paralysingkiss
+ paralysing kiss
+ paralysing kiss
+ Carriers of this gene are able to briefly stun an enemy with a kiss.
+ Genes/Icons/rjw_genes_lips
+ rjw_genes_lifeforce
+ 12
+ rjw_genes_fertilin
+
+ rjw_genes_paralysingkiss
+
+
+ rjw_genes_paralysingkiss
+
+ 1
+ -1
+
+
+ stun
+ kiss
+
+
+
+
+
+ rjw_genes_seduce
+ seduction
+ seduction
+ Carriers of this gene are able to seduce a pawn into having sex with them.
+ Genes/Icons/seduce
+ rjw_genes_lifeforce
+ 13
+ rjw_genes_fertilin
+
+ rjw_genes_seduce
+
+
+ rjw_genes_seduce
+
+ 1
+ -1
+
+
+
+ stun
+ kiss
+
+
+
+
+
+ rjw_genes_naked_prowess
+ naked prowess
+ Carriers of this gene are able to temporarily increase their strength and resilience, while they are naked.
+ Genes/Icons/rjw_naked_prowess
+ rjw_genes_lifeforce
+ 13
+ rjw_genes_fertilin
+
+ rjw_genes_naked_prowess
+
+
+ rjw_genes_naked_prowess
+
+ 1
+ -1
+
+
+
+ rjw_genes_cum_eater
+ Cum eater
+ Carriers of this gene are able to absorb fertilin through eating cum. This includes oral sex, eating cum for food or sucking out cumflated pawns.
+ Genes/Icons/cumeater
+ rjw_genes_lifeforce
+ 1
+ rjw_genes_fertilin
+ 1
+
+
+
+ rjw_genes_fertilin_absorber
+ Fertilin Absorber
+ Carriers of this gene are able to absorb the fertilin inside sperm through their vagina and anus.
+ Genes/Icons/Vaginal_cum_absorption
+ rjw_genes_lifeforce
+ 2
+ rjw_genes_fertilin
+ 1
+
+
+
+ rjw_genes_drainer
+ vitality drainer
+ Carriers of this gene are able to absorb a great amount of fertilin by draining the vitality of the partner. This is done passively through having sex with a non-drained pawn that does not have this gene.
+ Things/Mote/Heart
+ rjw_genes_lifeforce
+ 4
+ rjw_genes_fertilin
+ 1
+ -1
+
+
\ No newline at end of file
diff --git a/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml b/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml
new file mode 100644
index 0000000..97fb937
--- /dev/null
+++ b/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml
@@ -0,0 +1,69 @@
+
+
+
+
+ rjw_genes_hypersexual
+ Hypersexuality
+ Reproduction
+ Xenotypes with this Gene are Hypersexual (Nymphs).
+ Genes/Icons/Hypersexual
+ 1
+
+
+ Nymphomaniac
+
+
+
+
+
+ rjw_genes_rapist
+ Rapist
+ Reproduction
+ Xenotypes with this Gene are Rapists.
+ Genes/Icons/Rape
+ 1
+ 2
+
+
+ Rapist
+
+
+
+
+
+ rjw_genes_homosexual
+ Homosexual
+ Reproduction
+ This Gene makes you gay.
+ UI\Ideoligions\Universal\RoundC
+ 0
+ 3
+
+
+ Gay
+
+
+
+ rjw_genes_sexual_orientation
+
+
+
+
+ rjw_genes_bisexual
+ Bisexual
+ Reproduction
+ Carriers of this Gene are Bisexual.
+ UI\Ideoligions\Universal\RoundC
+ 0
+ 4
+
+
+ Bisexual
+
+
+
+ rjw_genes_sexual_orientation
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml b/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml
new file mode 100644
index 0000000..1e0e8c9
--- /dev/null
+++ b/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml
@@ -0,0 +1,48 @@
+
+
+
+ rjw_genes_orgasm_rush
+ Orgasm Rush
+ rjw_genes_special
+ On Orgasm, carriers of this gene get a boost in activity. (rest-need is partially filled)
+ 1
+ -2
+ UI/Memes/FleshPurity
+ 1
+
+
+
+ rjw_genes_youth_fountain
+ Youth Fountain
+ rjw_genes_special
+ Having sex with a carrier of this gene makes the partner slightly younger. (Partner stays adult)
+ 2
+ -2
+ UI/Ideoligions/FireLeaves
+ 2
+
+
+
+ rjw_genes_sex_age_drain
+ Sexual Age Drain
+ rjw_genes_special
+ Having sex transfers some of the partners life-time to themselves. (Pawn stays adult)
+ 2
+ -1
+ UI/Icons/ColonistBar/Idle
+ 3
+
+
+
+ rjw_genes_aphrodisiac_pheromones
+ Aphrodisiac Pheromones
+ rjw_genes_special
+ RJW_Genes.Gene_Aphrodisiac_Pheromones
+ Pheremones of this pawn induce an incressed sexdrive to others nearby.
+ UI/Memes/FleshPurity
+ 4
+ 1
+ 1
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_SpecifiedGender.xml b/Common/Defs/GeneDefs/GeneDefs_SpecifiedGender.xml
similarity index 100%
rename from Common/Defs/Genes/GeneDefs_SpecifiedGender.xml
rename to Common/Defs/GeneDefs/GeneDefs_SpecifiedGender.xml
diff --git a/Common/Defs/GeneDefs/Xenotype_Lifeforce.xml b/Common/Defs/GeneDefs/Xenotype_Lifeforce.xml
new file mode 100644
index 0000000..38dfa28
--- /dev/null
+++ b/Common/Defs/GeneDefs/Xenotype_Lifeforce.xml
@@ -0,0 +1,137 @@
+
+
+
+
+ rjw_genes_succubus
+ Succubus
+ Succubi are strongly enhanced xenohumans. These overnaturally beautiful creatures strive parasitically on the Fertilin found in semen.
+ Succubi are beautiful and extremely hungry Xenohumans. They strive on having sex and extracting their victims life-force through this.
+ UI/Icons/Xenotypes/Sanguophage
+ PawnBecameSanguophage
+ 0.5
+ 0.1~140
+ 1
+ -1000
+ 0.005
+ false
+
+ 0.02
+ 0.02
+ 0.02
+ 0.02
+ 0.02
+ 0.02
+
+
+ rjw_genes_bisexual
+ rjw_genes_hypersexual
+ rjw_genes_female_only
+ rjw_genes_lifeforce
+ rjw_genes_lifeforce_drain
+ rjw_genes_demonic_genitalia
+
+ rjw_genes_cum_eater
+ rjw_genes_fertilin_absorber
+
+ rjw_genes_paralysingkiss
+ rjw_genes_seduce
+
+ rjw_genes_succubus_wings
+ rjw_genes_succubus_tail
+ rjw_genes_aphrodisiac_pheromones
+ Beauty_Pretty
+ MoveSpeed_Quick
+ AptitudeStrong_Social
+ Ears_Pointed
+ Headbone_MiniHorns
+ Skin_Purple
+
+
+
+
+ rjw_genes_incubus
+ Incubus
+ Incubi are strongly enhanced xenohumans. These overnaturally beautiful creatures strive parasitically on the Fertilin found in semen.
+ Incubi are beautiful and extremely hungry Xenohumans. They strive on having sex and extracting their victims life-force through this.
+ UI/Icons/Xenotypes/Sanguophage
+ PawnBecameSanguophage
+ 0.5
+ 0.1~140
+ 1
+ -1000
+ 0.005
+ false
+
+ 0.02
+ 0.02
+ 0.02
+ 0.02
+ 0.02
+ 0.02
+
+
+ rjw_genes_hypersexual
+ rjw_genes_male_only
+ rjw_genes_lifeforce
+ rjw_genes_lifeforce_drain
+ rjw_genes_drainer
+ rjw_genes_demonic_genitalia
+
+ rjw_genes_seduce
+ rjw_genes_succubus_wings
+ rjw_genes_succubus_tail
+ rjw_genes_aphrodisiac_pheromones
+
+ Beauty_Pretty
+ MoveSpeed_Quick
+ Robust
+ UVSensitivity_Intense
+ AptitudeStrong_Intellectual
+ Ears_Pointed
+ Headbone_CenterHorn
+ Skin_InkBlack
+
+
+
+
+ rjw_genes_cumazone
+ Cumazone
+ Cumazone are a female only xenotype that excel at meele combat. Originally created as bodyguards for glitterworld amazon communities, they spred to other systems by mere strength and providing for some fetishes. They can use Fertilin to enhance their skin to overpower any combatant in meele. Their only source for Fertilin is biting of male genitalia - so be sure to have a steady supply of victim males or prepare to raid unsuspecting men of the rim.
+ Female only, strong meele fighters, that use Fertilin from bitten-off cocks for powerful buffs.
+ UI/Icons/Xenotypes/Neanderthal
+ 0.5
+ 0.1~140
+ 2.5
+ -1000
+ 0.01
+ false
+
+ WoundHealing_Fast
+ NakedSpeed
+ Aggression_Aggressive
+ MeleeDamage_Strong
+ KillThirst
+ Robust
+ Pain_Reduced
+ Beauty_Ugly
+ Hair_BaldOnly
+ Hair_ShortOnly
+ Brow_Heavy
+ Body_Hulk
+ AptitudeStrong_Shooting
+ AptitudeRemarkable_Melee
+ AptitudePoor_Crafting
+ AptitudePoor_Artistic
+ Unstoppable
+ rjw_genes_rapist
+ rjw_genes_female_only
+ rjw_genes_lifeforce
+ rjw_genes_lifeforce_drain
+ rjw_genes_pussyhealing
+ rjw_genes_cockeater
+ rjw_genes_naked_prowess
+ rjw_genes_orgasm_rush
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_Damage.xml b/Common/Defs/Genes/GeneDefs_Damage.xml
deleted file mode 100644
index b3c21ef..0000000
--- a/Common/Defs/Genes/GeneDefs_Damage.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- rjw_genes_elasticity
- Elasticity
- rjw_genes_damage
- This Xenotype cannot get stretched by huge penetrators.
- Genes/Icons/Elasticity
- RJW_Genes.Gene_Elasticity
- 1
-
-
-
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_Reproduction.xml b/Common/Defs/Genes/GeneDefs_Reproduction.xml
deleted file mode 100644
index ef348fd..0000000
--- a/Common/Defs/Genes/GeneDefs_Reproduction.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
- rjw_genes_hypersexual
- Hypersexuality
- Reproduction
- Xenotypes with this Gene are Hypersexual (Nymphs).
- Genes/Icons/Hypersexual
- 1
-
-
- Nymphomaniac
-
-
-
-
-
- rjw_genes_rapist
- Rapist
- Reproduction
- Xenotypes with this Gene are Rapists.
- Genes/Icons/Rape
- 2
-
-
- Rapist
-
-
-
-
\ No newline at end of file
diff --git a/Common/Defs/Genes/GeneDefs_SexSpecial.xml b/Common/Defs/Genes/GeneDefs_SexSpecial.xml
deleted file mode 100644
index 51d4269..0000000
--- a/Common/Defs/Genes/GeneDefs_SexSpecial.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- rjw_genes_orgasm_rush
- Orgasm Rush
- rjw_genes_special
- On Orgasm, carriers of this gene get a boost in activity. (rest-need is partially filled)
- 1
- UI/Memes/FleshPurity
- 1
-
-
-
\ No newline at end of file
diff --git a/Common/Defs/HediffDefs/Hediffs_Aphrodisiac.xml b/Common/Defs/HediffDefs/Hediffs_Aphrodisiac.xml
new file mode 100644
index 0000000..3d1048c
--- /dev/null
+++ b/Common/Defs/HediffDefs/Hediffs_Aphrodisiac.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+ rjw_genes_aphrodisiac_pheromone
+ HediffWithComps
+ induced libido
+ sex drive increasing due to smelling aphrodisiac pheromones.
+ (1,0,0.5)
+ 1.0
+
+
+ -4.0
+
+
+
+
+ wearing off
+
+ 1.25
+
+
+
+ 0.35
+ moderate
+
+
+ 1.8
+
+
+
+ 0.9
+ strong
+
+
+ 2.5
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/HediffDefs/Hediffs_Fertilin.xml b/Common/Defs/HediffDefs/Hediffs_Fertilin.xml
new file mode 100644
index 0000000..d8ee3db
--- /dev/null
+++ b/Common/Defs/HediffDefs/Hediffs_Fertilin.xml
@@ -0,0 +1,166 @@
+
+
+
+
+ rjw_genes_fertilin_lost
+ Hediff_HemogenCraving
+ lost fertilin
+ Percentage of fertilin lost.
+ (1,1,1)
+ 1
+
+
+ -0.5
+
+
+
+
+ true
+
+
+
+
+
+ rjw_genes_succubus_drained
+ HediffWithComps
+ Drained
+ The vitality of this pawn has been drained. Cannot be drained again until fully recovered.
+ (1,0,0.5)
+ 1.0
+ 1.0
+
+
+ -0.25
+
+
+
+
+ minor
+
+
+ Consciousness
+ -0.1
+
+
+ 0.1
+
+ -0.1
+
+
+
+ 0.5
+ moderate
+
+
+ Consciousness
+ -0.2
+
+
+ 0.05
+ 0.20
+
+ -0.1
+
+
+
+ 0.8
+ severe
+
+
+ Consciousness
+ -0.3
+
+
+
+ -0.2
+
+ 0.05
+ 0.1
+ 0.35
+
+
+
+
+
+ rjw_genes_fertilin_craving
+ fertilin craving
+ Hediff_HemogenCraving
+ weakened due to running out of fertilin.
+ (1,0,0.5)
+ 1.0
+ 0.01
+
+
+ minor
+ 0.05
+
+
+ Consciousness
+ 0.9
+
+
+
+
+ moderate
+ 0.35
+ 0.1
+
+
+ Consciousness
+ 0.8
+
+
+
+
+ major
+ 0.7
+ 0.15
+
+
+ Consciousness
+ 0.5
+
+
+
+
+
+
+ 0.05
+ -0.1
+
+
+
+
+
+ rjw_genes_naked_prowess
+ naked prowss
+ Driven by fertilin, this person has greatly increased strength and resilience.
+ HediffWithComps
+
+
+
+
+ 0.5
+ 0.5
+ 0.5
+
+
+
+ 0.5
+ 1.5
+
+
+
+
+
+ True
+ 5000
+
+
+
+
+ false
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/HediffDefs/Hediffs_OrgasmRush.xml b/Common/Defs/HediffDefs/Hediffs_OrgasmRush.xml
new file mode 100644
index 0000000..f68663f
--- /dev/null
+++ b/Common/Defs/HediffDefs/Hediffs_OrgasmRush.xml
@@ -0,0 +1,78 @@
+
+
+
+
+ rjw_genes_orgasm_rush_hediff
+ HediffWithComps
+ Orgasm Rush
+ Xenotypes with this Gene are pushed beyond normal limits when they have an orgasm.
+ (240,200,110)
+ false
+ 1.0
+ false
+ false
+
+
+ -0.75
+
+
+
+
+ pumped
+
+ 4
+ 4
+
+
+
+ Consciousness
+ 0.05
+
+
+
+
+ charged
+ 0.4
+
+ 8
+ 8
+
+
+
+ Moving
+ 0.08
+
+
+ Consciousness
+ 0.08
+
+
+
+
+ super-charged
+ 0.7
+
+ 10
+ 10
+
+
+
+ Moving
+ 0.1
+
+
+ Consciousness
+ 0.1
+
+
+ BloodPumping
+ 0.1
+
+
+
+
+
+
+
+
+
diff --git a/Common/Defs/IncidentsDefs/Incidents_LifeForce.xml b/Common/Defs/IncidentsDefs/Incidents_LifeForce.xml
new file mode 100644
index 0000000..297aca5
--- /dev/null
+++ b/Common/Defs/IncidentsDefs/Incidents_LifeForce.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ SuccubusDreamVisit
+ dirty dreams
+ Misc
+
+ Map_PlayerHome
+
+ RJW_Genes.IncidentWorker_SuccubusDreamVisit
+ 1.0
+ 10
+ false
+
+
\ No newline at end of file
diff --git a/Common/Defs/InteractionDef/Interactions_Flirt.xml b/Common/Defs/InteractionDef/Interactions_Flirt.xml
new file mode 100644
index 0000000..27c5408
--- /dev/null
+++ b/Common/Defs/InteractionDef/Interactions_Flirt.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ rjw_genes_flirt
+ flirt
+ Things/Mote/SpeechSymbols/Chitchat
+
+
+ r_logentry->[INITIATOR_nameDef] and [RECIPIENT_nameDef] [talkedabout] [TalkTopicLight].
+ r_logentry->[INITIATOR_nameDef] [talkedabout] [TalkTopicLight] with [RECIPIENT_nameDef].
+ r_logentry(p=0.8)->[INITIATOR_nameDef] [commentedabout] [TalkTopicLight] to [RECIPIENT_nameDef].
+
+ talkedabout(p=4)->chatted about
+ talkedabout->shared a word about
+ talkedabout->spoke about
+ talkedabout->gabbed about
+ talkedabout->talked about
+ talkedabout->joked about
+ talkedabout->quipped about
+
+ commentedabout->said something about
+ commentedabout->said a word about
+ commentedabout->made a comment about
+ commentedabout->commented about
+ commentedabout->told a joke about
+
+
+
+
+
diff --git a/Common/Defs/InteractionDef/Rape/Rape_SuccubusTail.xml b/Common/Defs/InteractionDef/Rape/Rape_SuccubusTail.xml
new file mode 100644
index 0000000..1fa8d91
--- /dev/null
+++ b/Common/Defs/InteractionDef/Rape/Rape_SuccubusTail.xml
@@ -0,0 +1,153 @@
+
+
+
+
+ Rape_SuccubusTail_Tailjob
+ succubustail tailjob
+
+
+ r_logentry->Was given tailjob by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave tailjob to [INITIATOR_nameDef].
+
+
+
+
+ Tailjob
+ Handjob
+
+ DomSuccubusTail_Tailjob_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Rape
+
+
+
+ CanPenetrate
+
+
+
+
+
+
+
+
+
+
+ Rape_SuccubusTail_Vaginal
+ succubustail vaginal
+
+
+ r_logentry->Gave vaginal tailsex to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given vaginal tailsex by [INITIATOR_nameDef].
+
+
+
+
+ Vaginal Tailsex
+ Vaginal
+
+ DomSuccubusTail_Vaginal_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Rape
+
+
+
+
+
+ Vagina
+
+
+
+
+
+
+
+ Rape_SuccubusTail_Anal
+ succubustail anal
+
+
+ r_logentry->Gave anal tailsex to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given anal tailsex by [INITIATOR_nameDef].
+
+
+
+
+ Anal Tailsex
+ Anal
+
+ DomSuccubusTail_Anal_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Rape
+
+
+
+
+
+ Anus
+
+
+
+
+
+
+
+
+ Rape_SuccubusTail_Envelop
+ succubustail envelop
+
+
+ r_logentry->Was given special tailjob by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave special tailjob to [INITIATOR_nameDef].
+
+
+
+
+ Envelop
+ Vaginal
+
+ DomSuccubusTail_Envelop_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Rape
+
+
+
+ CanPenetrate
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/InteractionDef/Rape/Reverse/Rape_Reverse_SuccubusTail.xml b/Common/Defs/InteractionDef/Rape/Reverse/Rape_Reverse_SuccubusTail.xml
new file mode 100644
index 0000000..a600908
--- /dev/null
+++ b/Common/Defs/InteractionDef/Rape/Reverse/Rape_Reverse_SuccubusTail.xml
@@ -0,0 +1,159 @@
+
+
+
+
+ Rape_SuccubusTail_Reverse_Tailjob
+ succubustail tailjob
+
+
+ r_logentry->Gave tailjob to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given tailjob by [INITIATOR_nameDef].
+
+
+
+
+ Tailjob
+ Handjob
+
+ SubSuccubusTail_Tailjob_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Rape
+
+
+
+
+
+
+ CanPenetrate
+
+
+
+
+
+
+
+ Rape_SuccubusTail_Reverse_Vaginal
+ succubustail vaginal
+
+
+ r_logentry->Was given vaginal tailsex by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave vaginal tailsex to [INITIATOR_nameDef].
+
+
+
+
+ Vaginal Tailsex
+ Vaginal
+
+ DomSuccubusTail_Vaginal_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Rape
+
+
+
+ Vagina
+
+
+
+
+
+
+
+
+
+
+ Rape_SuccubusTail_Reverse_Anal
+ succubustail anal
+
+
+ r_logentry->Was given anal tailsex by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave anal tailsex to [INITIATOR_nameDef].
+
+
+
+
+ Anal Tailsex
+ Anal
+
+ DomSuccubusTail_Anal_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Rape
+
+
+
+ Anus
+
+
+
+
+
+
+
+
+
+
+
+ Rape_SuccubusTail_Reverse_Envelop
+ succubustail envelop
+
+
+ r_logentry->Gave special tailjob to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given special tailjob by [INITIATOR_nameDef].
+
+
+
+
+ Envelop
+ Vaginal
+
+ DomSuccubusTail_Envelop_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Rape
+
+
+
+
+
+ CanPenetrate
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/InteractionDef/Sex/Reverse/Sex_Reverse_SuccubusTail.xml b/Common/Defs/InteractionDef/Sex/Reverse/Sex_Reverse_SuccubusTail.xml
new file mode 100644
index 0000000..a6e98c5
--- /dev/null
+++ b/Common/Defs/InteractionDef/Sex/Reverse/Sex_Reverse_SuccubusTail.xml
@@ -0,0 +1,159 @@
+
+
+
+
+ Sex_SuccubusTail_Reverse_Tailjob
+ succubustail tailjob
+
+
+ r_logentry->Gave tailjob to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given tailjob by [INITIATOR_nameDef].
+
+
+
+
+ Tailjob
+ Handjob
+
+ SubSuccubusTail_Tailjob_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Consensual
+
+
+
+
+
+
+ CanPenetrate
+
+
+
+
+
+
+
+ Sex_SuccubusTail_Reverse_Vaginal
+ succubustail vaginal
+
+
+ r_logentry->Was given vaginal tailsex by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave vaginal tailsex to [INITIATOR_nameDef].
+
+
+
+
+ Vaginal Tailsex
+ Vaginal
+
+ DomSuccubusTail_Vaginal_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Consensual
+
+
+
+ Vagina
+
+
+
+
+
+
+
+
+
+
+ Sex_SuccubusTail_Reverse_Anal
+ succubustail anal
+
+
+ r_logentry->Was given anal tailsex by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave anal tailsex to [INITIATOR_nameDef].
+
+
+
+
+ Anal Tailsex
+ Anal
+
+ DomSuccubusTail_Anal_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Consensual
+
+
+
+ Anus
+
+
+
+
+
+
+
+
+
+
+
+ Sex_SuccubusTail_Reverse_Envelop
+ succubustail envelop
+
+
+ r_logentry->Gave special tailjob to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given special tailjob by [INITIATOR_nameDef].
+
+
+
+
+ Envelop
+ Vaginal
+
+ DomSuccubusTail_Envelop_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Reverse
+ Consensual
+
+
+
+
+
+ CanPenetrate
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/InteractionDef/Sex/Sex_SuccubusTail.xml b/Common/Defs/InteractionDef/Sex/Sex_SuccubusTail.xml
new file mode 100644
index 0000000..dda1ffe
--- /dev/null
+++ b/Common/Defs/InteractionDef/Sex/Sex_SuccubusTail.xml
@@ -0,0 +1,154 @@
+
+
+
+
+ Sex_SuccubusTail_Tailjob
+ succubustail tailjob
+
+
+ r_logentry->Was given tailjob by [RECIPIENT_nameDef].
+
+
+
+
+
+ r_logentry->Gave tailjob to [INITIATOR_nameDef].
+
+
+
+
+ Tailjob
+ Handjob
+
+ DomSuccubusTail_Tailjob_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Consensual
+
+
+
+ CanPenetrate
+
+
+
+
+
+
+
+
+
+
+ Sex_SuccubusTail_Vaginal
+ succubustail vaginal
+
+
+ r_logentry->Gave vaginal tailsex to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given vaginal tailsex by [INITIATOR_nameDef].
+
+
+
+
+ Vaginal Tailsex
+ Vaginal
+
+ DomSuccubusTail_Vaginal_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Consensual
+
+
+
+
+
+ Vagina
+
+
+
+
+
+
+
+ Sex_SuccubusTail_Anal
+ succubustail anal
+
+
+ r_logentry->Gave anal tailsex to [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Was given anal tailsex by [INITIATOR_nameDef].
+
+
+
+
+ Anal Tailsex
+ Anal
+
+ DomSuccubusTail_Anal_RP
+
+
+
+ DomSuccubusTailCustomRequirementHandler
+
+ Consensual
+
+
+
+
+
+ Anus
+
+
+
+
+
+
+
+
+ Sex_SuccubusTail_Envelop
+ succubustail envelop
+
+
+ r_logentry->Was given special tailjob by [RECIPIENT_nameDef].
+
+
+
+
+ r_logentry->Gave special tailjob to [INITIATOR_nameDef].
+
+
+
+
+ Envelop
+ Vaginal
+
+ DomSuccubusTail_Envelop_RP
+
+
+
+ SubSuccubusTailCustomRequirementHandler
+
+ Consensual
+
+
+
+ CanPenetrate
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/JobDefs/Jobs_LifeForce.xml b/Common/Defs/JobDefs/Jobs_LifeForce.xml
new file mode 100644
index 0000000..13dd1e3
--- /dev/null
+++ b/Common/Defs/JobDefs/Jobs_LifeForce.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ rjw_genes_lifeforce_randomrape
+ rjw.JobDriver_RandomRape
+ Raping
+ false
+
+
+
+ rjw_genes_lifeforce_healpussy
+ RJW_Genes.JobDriver_CastAbilityAfterSex
+ Tending someones wounds with sex.
+ false
+
+
+
+ rjw_genes_lifeforce_seduced
+ RJW_Genes.JobDriver_Seduced
+ Seduced.
+ false
+ false
+
+
+
+ rjw_genes_flirt
+ RJW_Genes.JobDriver_Flirt
+ Seduced.
+ false
+
+
\ No newline at end of file
diff --git a/Common/Defs/JobDefs/Jobs_SexOnSpot.xml b/Common/Defs/JobDefs/Jobs_SexOnSpot.xml
new file mode 100644
index 0000000..e904f3e
--- /dev/null
+++ b/Common/Defs/JobDefs/Jobs_SexOnSpot.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ sex_on_spot
+ RJW_Genes.JobDriver_SexOnSpot
+ Making love on the spot.
+ false
+
+
+
+ sex_on_spot_reciever
+ RJW_Genes.JobDriver_SexOnSpotReciever
+ lovin'.
+ false
+
+
\ No newline at end of file
diff --git a/Common/Defs/MentalStateDefs/MentalState_Lifeforce.xml b/Common/Defs/MentalStateDefs/MentalState_Lifeforce.xml
new file mode 100644
index 0000000..392407b
--- /dev/null
+++ b/Common/Defs/MentalStateDefs/MentalState_Lifeforce.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ rjw_genes_lifeforce_randomrape
+ rjw_genes_lifeforce_randomrape
+ 1.5
+ Extreme
+ RJW_Genes.LifeForceMentalBreakWorker
+
+
+
+ rjw_genes_lifeforce_randomrape
+ RJW_Genes.LifeForceMentalState
+ RJW_Genes.LifeForceMentalStateWorker
+ random rape
+ Malicious
+ true
+ false
+ 30000
+ 0.8
+ 80000
+ (0.5, 0.9, 0.5)
+ random rape
+ {0} has run out of lifeforce and is looking to obtain some.
+ ThreatSmall
+ {0} is no longer raping randomly.
+ Mental state: Random Rape
+ true
+
+
\ No newline at end of file
diff --git a/Common/Defs/PawnKindDefs/PawnKind_LifeForce.xml b/Common/Defs/PawnKindDefs/PawnKind_LifeForce.xml
new file mode 100644
index 0000000..9d48cdc
--- /dev/null
+++ b/Common/Defs/PawnKindDefs/PawnKind_LifeForce.xml
@@ -0,0 +1,87 @@
+
+
+
+
+ rjw_genes_succubus
+ succubus
+ 50
+ Human
+
+
+ 999
+
+
+ 0.5
+ false
+ 18
+ 27
+ Poor
+ 0.0
+ false
+
+ 0.3
+ 0.9
+
+ true
+
+ Tribal
+
+
+ 0
+ 0
+
+ 0
+
+ 0
+ 0
+
+
+ Poor
+
+ 0.0
+ 2~4
+ 28~44
+
+
+
+ rjw_genes_incubus
+ succubus
+ 50
+ Human
+
+
+ 999
+
+
+ 0.5
+ false
+ 18
+ 27
+ Poor
+ 0.0
+ false
+
+ 0.3
+ 0.9
+
+ true
+
+ Tribal
+
+
+ 0
+ 0
+
+ 0
+
+ 0
+ 0
+
+
+ Poor
+
+ 0.0
+ 2~4
+ 28~44
+
+
\ No newline at end of file
diff --git a/Common/Defs/RaceGeneDefs/RaceGeneDefs_Vanilla_Racegroups.xml b/Common/Defs/RaceGeneDefs/RaceGeneDefs_Vanilla_Racegroups.xml
index fb9e576..45cb430 100644
--- a/Common/Defs/RaceGeneDefs/RaceGeneDefs_Vanilla_Racegroups.xml
+++ b/Common/Defs/RaceGeneDefs/RaceGeneDefs_Vanilla_Racegroups.xml
@@ -2,7 +2,12 @@
Canine
- Canine_Group
+
+ Canine_Group
+ CanineAnimal
+ CanineSingleGenderAnimal
+ CanineSkinAnimal
+
Ears_Floppy
@@ -38,7 +43,11 @@
Insect
- Insect_Group
+
+ Insect_Group
+ ArthropodOvipositorAnimal
+ ArthropodOvipositorHornyAnimal
+
Beauty_Ugly
@@ -117,7 +126,14 @@
Feline
- Feline_Group
+
+ Feline_Group
+ FelineAnimal
+ FelineHornyAnimal
+ FelineSingleGenderAnimal
+ AA_SandProwlerAnimal
+
+
VoiceRoar
@@ -184,7 +200,10 @@
Equine
- Equine_Group
+
+ Equine_Group
+ HorseAnimal
+
Furskin
@@ -227,7 +246,12 @@
Dragon
- Dragon_Group
+
+ Dragon_Group
+ ThrumboAnimal
+ DragonAnimal
+ DragonSingleGenderAnimal
+
Unstoppable
@@ -250,7 +274,7 @@
0.1
- rjw_genes_draconic_genitalia
+ rjw_genes_dragon_genitalia
0.6
@@ -290,7 +314,12 @@
Rodent
- Rodent_Group
+
+ Rodent_Group
+ RodentAnimal
+ RodentSingleGenderAnimal
+ DragonSingleGenderAnimal
+
Furskin
@@ -345,7 +374,10 @@
Racoon
- Raccon_Group
+
+ Raccon_Group
+ RaccoonAnimal
+
Furskin
diff --git a/Common/Defs/RaceGeneDefs/RaceGeneDefs_template.xml b/Common/Defs/RaceGeneDefs/RaceGeneDefs_template.xml
index 20be765..b092257 100644
--- a/Common/Defs/RaceGeneDefs/RaceGeneDefs_template.xml
+++ b/Common/Defs/RaceGeneDefs/RaceGeneDefs_template.xml
@@ -1,12 +1,17 @@
-
-
+this is to disable the xml, remove it for your own xml -->
-
+
+
+this is to disable the xml, remove it for your own xml -->
\ No newline at end of file
diff --git a/Common/Defs/RulePackDefs/Sex/RulePacks_SuccubTail.xml b/Common/Defs/RulePackDefs/Sex/RulePacks_SuccubTail.xml
new file mode 100644
index 0000000..21e75a1
--- /dev/null
+++ b/Common/Defs/RulePackDefs/Sex/RulePacks_SuccubTail.xml
@@ -0,0 +1,77 @@
+
+
+
+
+ DomSuccubusTail_Tailjob_RP
+
+
+ sent-> [INITIATOR_nameDef] gave [RECIPIENT_nameDef] a tailjob.
+
+
+
+
+
+ DomSuccubusTail_Vaginal_RP
+
+
+ sent-> [INITIATOR_nameDef] [INITIATOR_possessive] tail was vaginally inserted into [RECIPIENT_nameDef].
+
+
+
+
+
+ DomSuccubusTail_Anal_RP
+
+
+ sent-> [INITIATOR_nameDef] [INITIATOR_possessive] tail was anally inserted into [RECIPIENT_nameDef].
+
+
+
+
+
+
+ DomSuccubusTail_Envelop_RP
+
+
+ sent-> [RECIPIENT_nameDef] dick was enveloped by [INITIATOR_nameDef] [INITIATOR_possessive] tail.
+
+
+
+
+
+ SubSuccubusTail_Tailjob_RP
+
+
+ sent-> [RECIPIENT_nameDef] gave [INITIATOR_nameDef] a tailjob.
+
+
+
+
+
+ SubSuccubusTail_Vaginal_RP
+
+
+ sent-> [RECIPIENT_nameDef] [RECIPIENT_possessive] tail was vaginally inserted into [INITIATOR_nameDef].
+
+
+
+
+
+ SubSuccubusTail_Anal_RP
+
+
+ sent-> [RECIPIENT_nameDef] [RECIPIENT_possessive] tail was anally inserted into [INITIATOR_nameDef].
+
+
+
+
+
+
+ SubSuccubusTail_Envelop_RP
+
+
+ sent-> [INITIATOR_nameDef] dick was enveloped by [RECIPIENT_nameDef] [RECIPIENT_possessive] tail.
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/ThinkTreeDefs/ThinkTrees_LifeForce.xml b/Common/Defs/ThinkTreeDefs/ThinkTrees_LifeForce.xml
new file mode 100644
index 0000000..574fe0f
--- /dev/null
+++ b/Common/Defs/ThinkTreeDefs/ThinkTrees_LifeForce.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+ SuccubusGetLifeForce
+ Humanlike_PostMain
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Defs/ThoughtDefs/Thoughts_LifeForce.xml b/Common/Defs/ThoughtDefs/Thoughts_LifeForce.xml
new file mode 100644
index 0000000..f7a3d6b
--- /dev/null
+++ b/Common/Defs/ThoughtDefs/Thoughts_LifeForce.xml
@@ -0,0 +1,56 @@
+
+
+
+
+ rjw_genes_cock_eaten
+ Thought_Memory
+ 30.0
+ 100
+ 0.4
+
+
+ cock eaten
+ My cock was eaten directly of my body, I am devestated. This is not what good head feels like.
+ -30
+
+
+
+
+
+ rjw_genes_seduced
+ Thought_Memory
+ 10.0
+ 100
+ 0.4
+
+
+ seduced
+ I was seduced into having sex. I regret what happened.
+ -10
+
+
+
+
+
+ rjw_genes_critical_fertilin
+ ThoughtWorker_Hediff
+ rjw_genes_fertilin_craving
+
+
+ fertilin craving
+ My bones ache. I really need fertilin.
+ -10
+
+
+ fertilin craving
+ This hurts bad and I can't stop thinking about sex. I would do anything for some cum.
+ -15
+
+
+ fertilin craving
+ Can't think. Sex. Sex. Must. Have. Cum.
+ -20
+
+
+
+
diff --git a/Common/Defs/TipSetDefs/Tips.xml b/Common/Defs/TipSetDefs/Tips.xml
new file mode 100644
index 0000000..7147147
--- /dev/null
+++ b/Common/Defs/TipSetDefs/Tips.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ RJWGenesTips
+
+
+ Succubi and Incubi can spawn at a rare event when a horny pawn is sleeping alone in the night.
+
+ Cumazones need to regularly bite of cocks. This hunger can be stilled by animals - but they will need much more this way!
+
+ Succubi drain Fertilin through sex. The drained pawn will give less Fertilin in consequent acts until they are recovered.
+
+ Incubi 'tap' pawns they have sex with to gain fertilin. Incubi cannot gain further Fertilin this way until the pawn is fully recovered.
+
+ The Xenotypes added by RJW_Genes require a lot of human resources - have yourself a big colony or lots of prisoners before you keep their company!
+
+ Succubi receive their fertilin from cum. Make sure to have enough juice around to keep them happy.
+
+ The gene 'cumeater' allows you to drain cumflation by cunnilingus. ... Cool, huh?
+
+ Some animals carry rare genes - you can try to breed them and create your own super-hybrids! (No warranty provided for cat girls or genetic waste)
+
+ The Settings for Animal-Gene Inheritance are distributed between RJW-Pregnancy-Settings and their own Mod-Options.
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Languages/English/Keyed/Lifeforce.xml b/Common/Languages/English/Keyed/Lifeforce.xml
new file mode 100644
index 0000000..5b0520d
--- /dev/null
+++ b/Common/Languages/English/Keyed/Lifeforce.xml
@@ -0,0 +1,17 @@
+
+
+
+ Pawn doesn't have required fertilin gene.
+ Not enough fertilin to cast.
+ This happened because of low fertilin.
+
+ Low fertilin
+ A colonist has low fertilin. At this point they are becoming desperate enough to consider rape and bestiality to obtain fertilin (if they didn't already). At zero fertilin they will lose all sense and start raping randomly
+
+
+
+ {0} has fed enough on your colonists and will now leave.
+
+ Dirty dreams
+ The dirty dreams of your colonists have attracted succubi.\n\nThey will hang around for a couple of days trying to seduce your colonists. They may decide to join your colony, if they are impressed by your colonists's sexual prowess.
+
\ No newline at end of file
diff --git a/Common/Patches/Genes/Patch_Unbreakable.xml b/Common/Patches/Genes/Patch_Unbreakable.xml
new file mode 100644
index 0000000..a2d674a
--- /dev/null
+++ b/Common/Patches/Genes/Patch_Unbreakable.xml
@@ -0,0 +1,68 @@
+
+
+
+
+ Defs/ThoughtDef[defName="FeelingBroken"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
+
+ Defs/ThoughtDef[defName="GotRaped"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
+ Defs/ThoughtDef[defName="GotAnalRaped"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
+ Defs/ThoughtDef[defName="GotAnalRapedByFemale"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
+ Defs/ThoughtDef[defName="GotRapedUnconscious"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
+ Defs/ThoughtDef[defName="HateMyRapist"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
+ Defs/ThoughtDef[defName="AllowedMeToGetRaped"]
+
+
+ rjw_genes_unbreakable
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/ThingDefs/RJW_Used_Condoms.xml b/Common/Patches/ThingDefs/RJW_Used_Condoms.xml
new file mode 100644
index 0000000..d04bcb1
--- /dev/null
+++ b/Common/Patches/ThingDefs/RJW_Used_Condoms.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ RimJobWorld
+
+
+ /Defs/ThingDef[defName="UsedCondom"]/ingestible
+
+
+
+ 1
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/ThingDefs/Sexperience_Cum.xml b/Common/Patches/ThingDefs/Sexperience_Cum.xml
new file mode 100644
index 0000000..b905d4b
--- /dev/null
+++ b/Common/Patches/ThingDefs/Sexperience_Cum.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ RJW Sexperience
+
+
+ /Defs/ThingDef[defName="GatheredCum"]/ingestible/outcomeDoers
+
+
+ 1
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/ThinkTree/MentalStateCritical_LifeForceRandomRape.xml b/Common/Patches/ThinkTree/MentalStateCritical_LifeForceRandomRape.xml
new file mode 100644
index 0000000..9532df8
--- /dev/null
+++ b/Common/Patches/ThinkTree/MentalStateCritical_LifeForceRandomRape.xml
@@ -0,0 +1,35 @@
+
+
+
+
+ Defs/ThinkTreeDef[defName="MentalStateCritical"]/thinkRoot[@Class="ThinkNode_Tagger"]/subNodes
+
+
+ rjw_genes_lifeforce_randomrape
+
+
+ Rest
+ 0.05
+ true
+
+
+
+
+
+ 0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/GenitaliaUpdate.xml b/Common/Patches/Xenotypes/FromOtherMods/GenitaliaUpdate.xml
similarity index 60%
rename from Common/Patches/Xenotypes/GenitaliaUpdate.xml
rename to Common/Patches/Xenotypes/FromOtherMods/GenitaliaUpdate.xml
index f0af1b5..fd6e360 100644
--- a/Common/Patches/Xenotypes/GenitaliaUpdate.xml
+++ b/Common/Patches/Xenotypes/FromOtherMods/GenitaliaUpdate.xml
@@ -1,44 +1,6 @@
-
-
-
Defs/XenotypeDef[defName="Neanderthal"]/genes
@@ -74,10 +36,23 @@
Defs/XenotypeDef[defName="Highmate"]/genes
rjw_genes_hypersexual
- rjw_genes_likes_cumflation
+
+
+
+ LustLicentia.RJWLabs
+
+
+ Defs/XenotypeDef[defName="Highmate"]/genes
+
+ rjw_genes_likes_cumflation
+
+
+
+
Defs/XenotypeDef[defName="Genie"]/genes
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchBiotechNyaron.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchBiotechNyaron.xml
new file mode 100644
index 0000000..50ad15f
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchBiotechNyaron.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ Biotech Nyaron
+
+
+ Defs/XenotypeDef[defName="Nyaron"]/genes
+
+ rjw_genes_feline_genitalia
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchKijinRace3.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchKijinRace3.xml
new file mode 100644
index 0000000..de2b840
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchKijinRace3.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ Kijin Race 3.0
+
+
+ Defs/XenotypeDef[defName="KijinXenotype"]/genes
+
+ rjw_genes_demonic_genitalia
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchNarai.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchNarai.xml
new file mode 100644
index 0000000..51ee9d8
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchNarai.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ NaraiXenotype
+
+
+ Defs/XenotypeDef[defName="Narai"]/genes
+
+ rjw_genes_canine_genitalia
+ rjw_genes_zoophile
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchNyaron.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchNyaron.xml
new file mode 100644
index 0000000..9145200
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchNyaron.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ Biotech Nyaron
+
+
+ Defs/XenotypeDef[defName="Nyaron"]/genes
+
+ rjw_genes_tight_female_genitalia
+ rjw_genes_feline_genitalia
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchPapou.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchPapou.xml
new file mode 100644
index 0000000..e46b8e8
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchPapou.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Papou Race : emotional birds
+
+
+ Defs/XenotypeDef[defName="papago"]/genes
+
+ rjw_genes_orgasm_rush
+ rjw_genes_tight_female_genitalia
+ rjw_genes_tight_anus
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchRoosMinotaur.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchRoosMinotaur.xml
new file mode 100644
index 0000000..f59bcc2
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchRoosMinotaur.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ Roo's Minotaur Xenotype
+
+
+ Defs/XenotypeDef[defName="RBM_Minotaur"]/genes
+
+ rjw_genes_much_cum
+ rjw_genes_cumflation_immunity
+ rjw_genes_loose_female_genitalia
+ rjw_genes_big_male_genitalia
+ rjw_genes_equine_genitalia
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchSaurid.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchSaurid.xml
new file mode 100644
index 0000000..c1fd626
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchSaurid.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ Vanilla Races Expanded - Saurid
+
+
+ Defs/XenotypeDef[defName="VRESaurids_Saurid"]/genes
+
+ rjw_genes_dragon_genitalia
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromOtherMods/PatchVREPhytokin.xml b/Common/Patches/Xenotypes/FromOtherMods/PatchVREPhytokin.xml
new file mode 100644
index 0000000..af7d43c
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromOtherMods/PatchVREPhytokin.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+ Vanilla Races Expanded - Phytokin
+
+
+ Defs/XenotypeDef[defName="VRE_Poluxkin"]/genes
+
+ rjw_genes_tight_female_genitalia
+ rjw_genes_tight_anus
+ rjw_genes_elasticity
+ rjw_genes_bisexual
+
+
+
+
+
+ Vanilla Races Expanded - Phytokin
+
+
+ Defs/XenotypeDef[defName="VRE_Gauranlenkin"]/genes
+
+ rjw_genes_tight_female_genitalia
+ rjw_genes_tight_anus
+ rjw_genes_elasticity
+ rjw_genes_bisexual
+
+
+
+
+
+
+ Vanilla Races Expanded - Phytokin
+
+
+ Defs/XenotypeDef[defName="VRE_Animakin"]/genes
+
+ rjw_genes_tight_female_genitalia
+ rjw_genes_tight_anus
+ rjw_genes_elasticity
+ rjw_genes_bisexual
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromRJWGenes/PatchLicentiaLabs.xml b/Common/Patches/Xenotypes/FromRJWGenes/PatchLicentiaLabs.xml
new file mode 100644
index 0000000..5c85681
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromRJWGenes/PatchLicentiaLabs.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ LustLicentia.RJWLabs
+
+
+ Defs/XenotypeDef[defName="rjw_genes_succubus"]/genes
+
+ rjw_genes_elasticity
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromRJWGenes/Patch_Dominant_Gene.xml b/Common/Patches/Xenotypes/FromRJWGenes/Patch_Dominant_Gene.xml
new file mode 100644
index 0000000..15b6f3f
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromRJWGenes/Patch_Dominant_Gene.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ Dominant Gene
+
+
+ Defs/XenotypeDef[defName="rjw_genes_succubus"]/genes
+
+ DominantGene
+
+
+
+
+
+ Dominant Gene
+
+
+ Defs/XenotypeDef[defName="rjw_genes_incubus"]/genes
+
+ DominantGene
+
+
+
+
+
+
+ Dominant Gene
+
+
+ Defs/XenotypeDef[defName="rjw_genes_cumazone"]/genes
+
+ DominantGene
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Patches/Xenotypes/FromRJWGenes/Patch_Sexperience_SexSkill.xml b/Common/Patches/Xenotypes/FromRJWGenes/Patch_Sexperience_SexSkill.xml
new file mode 100644
index 0000000..419eeb2
--- /dev/null
+++ b/Common/Patches/Xenotypes/FromRJWGenes/Patch_Sexperience_SexSkill.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ RJW Sexperience
+
+
+ Defs/XenotypeDef[defName="rjw_genes_succubus"]/genes
+
+ AptitudeRemarkable_Sex
+
+
+
+
+
+ RJW Sexperience
+
+
+ Defs/XenotypeDef[defName="rjw_genes_incubus"]/genes
+
+ AptitudeRemarkable_Sex
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Textures/Genes/Icons/Big_Breasts.png b/Common/Textures/Genes/Icons/Big_Breasts.png
index 904613e..5061ee5 100644
Binary files a/Common/Textures/Genes/Icons/Big_Breasts.png and b/Common/Textures/Genes/Icons/Big_Breasts.png differ
diff --git a/Common/Textures/Genes/Icons/Big_Male_Genitalia.png b/Common/Textures/Genes/Icons/Big_Male_Genitalia.png
index ed4810d..fe6d86e 100644
Binary files a/Common/Textures/Genes/Icons/Big_Male_Genitalia.png and b/Common/Textures/Genes/Icons/Big_Male_Genitalia.png differ
diff --git a/Common/Textures/Genes/Icons/FertilinAlt.png b/Common/Textures/Genes/Icons/FertilinAlt.png
new file mode 100644
index 0000000..f89bc2d
Binary files /dev/null and b/Common/Textures/Genes/Icons/FertilinAlt.png differ
diff --git a/Common/Textures/Genes/Icons/FertilinDrainAlt.png b/Common/Textures/Genes/Icons/FertilinDrainAlt.png
new file mode 100644
index 0000000..adb198b
Binary files /dev/null and b/Common/Textures/Genes/Icons/FertilinDrainAlt.png differ
diff --git a/Common/Textures/Genes/Icons/Genitalia_Canine.png b/Common/Textures/Genes/Icons/Genitalia_Canine.png
index 84df9d2..7631681 100644
Binary files a/Common/Textures/Genes/Icons/Genitalia_Canine.png and b/Common/Textures/Genes/Icons/Genitalia_Canine.png differ
diff --git a/Common/Textures/Genes/Icons/Genitalia_Canine_2.png b/Common/Textures/Genes/Icons/Genitalia_Canine_2.png
deleted file mode 100644
index a9d6c1d..0000000
Binary files a/Common/Textures/Genes/Icons/Genitalia_Canine_2.png and /dev/null differ
diff --git a/Common/Textures/Genes/Icons/Genitalia_Equine.png b/Common/Textures/Genes/Icons/Genitalia_Equine.png
index 51c7c1c..efb9bab 100644
Binary files a/Common/Textures/Genes/Icons/Genitalia_Equine.png and b/Common/Textures/Genes/Icons/Genitalia_Equine.png differ
diff --git a/Common/Textures/Genes/Icons/Healpussy.png b/Common/Textures/Genes/Icons/Healpussy.png
new file mode 100644
index 0000000..46a11a3
Binary files /dev/null and b/Common/Textures/Genes/Icons/Healpussy.png differ
diff --git a/Common/Textures/Genes/Icons/No_Breasts.png b/Common/Textures/Genes/Icons/No_Breasts.png
index 28729b8..5566734 100644
Binary files a/Common/Textures/Genes/Icons/No_Breasts.png and b/Common/Textures/Genes/Icons/No_Breasts.png differ
diff --git a/Common/Textures/Genes/Icons/RJW-Genes_Endogene_Background (Not in use now).png b/Common/Textures/Genes/Icons/RJW-Genes_Endogene_Background (Not in use now).png
new file mode 100644
index 0000000..9973e24
Binary files /dev/null and b/Common/Textures/Genes/Icons/RJW-Genes_Endogene_Background (Not in use now).png differ
diff --git a/Common/Textures/Genes/Icons/RJW-Genes_Rodent_Genitalia (Not in use now).png b/Common/Textures/Genes/Icons/RJW-Genes_Rodent_Genitalia (Not in use now).png
new file mode 100644
index 0000000..507684a
Binary files /dev/null and b/Common/Textures/Genes/Icons/RJW-Genes_Rodent_Genitalia (Not in use now).png differ
diff --git a/Common/Textures/Genes/Icons/RJW-Genes_Xenogene_Background (Not in use now).png b/Common/Textures/Genes/Icons/RJW-Genes_Xenogene_Background (Not in use now).png
new file mode 100644
index 0000000..f902c39
Binary files /dev/null and b/Common/Textures/Genes/Icons/RJW-Genes_Xenogene_Background (Not in use now).png differ
diff --git a/Common/Textures/Genes/Icons/Small_Breasts.png b/Common/Textures/Genes/Icons/Small_Breasts.png
index bfae844..b32f1d3 100644
Binary files a/Common/Textures/Genes/Icons/Small_Breasts.png and b/Common/Textures/Genes/Icons/Small_Breasts.png differ
diff --git a/Common/Textures/Genes/Icons/Small_Male_Genitalia.png b/Common/Textures/Genes/Icons/Small_Male_Genitalia.png
index 58aa367..b4d7194 100644
Binary files a/Common/Textures/Genes/Icons/Small_Male_Genitalia.png and b/Common/Textures/Genes/Icons/Small_Male_Genitalia.png differ
diff --git a/Common/Textures/Genes/Icons/Succubus_Tail.png b/Common/Textures/Genes/Icons/Succubus_Tail.png
new file mode 100644
index 0000000..cc86056
Binary files /dev/null and b/Common/Textures/Genes/Icons/Succubus_Tail.png differ
diff --git a/Common/Textures/Genes/Icons/Succubus_Wings.png b/Common/Textures/Genes/Icons/Succubus_Wings.png
new file mode 100644
index 0000000..0665f1a
Binary files /dev/null and b/Common/Textures/Genes/Icons/Succubus_Wings.png differ
diff --git a/Common/Textures/Genes/Icons/Vaginal_cum_absorption.png b/Common/Textures/Genes/Icons/Vaginal_cum_absorption.png
new file mode 100644
index 0000000..4148bde
Binary files /dev/null and b/Common/Textures/Genes/Icons/Vaginal_cum_absorption.png differ
diff --git a/Common/Textures/Genes/Icons/cockeater.png b/Common/Textures/Genes/Icons/cockeater.png
new file mode 100644
index 0000000..fa9577b
Binary files /dev/null and b/Common/Textures/Genes/Icons/cockeater.png differ
diff --git a/Common/Textures/Genes/Icons/cumeater.png b/Common/Textures/Genes/Icons/cumeater.png
new file mode 100644
index 0000000..3150a18
Binary files /dev/null and b/Common/Textures/Genes/Icons/cumeater.png differ
diff --git a/Common/Textures/Genes/Icons/rjw_genes_lips.png b/Common/Textures/Genes/Icons/rjw_genes_lips.png
new file mode 100644
index 0000000..13062a1
Binary files /dev/null and b/Common/Textures/Genes/Icons/rjw_genes_lips.png differ
diff --git a/Common/Textures/Genes/Icons/rjw_naked_prowess.png b/Common/Textures/Genes/Icons/rjw_naked_prowess.png
new file mode 100644
index 0000000..468fc60
Binary files /dev/null and b/Common/Textures/Genes/Icons/rjw_naked_prowess.png differ
diff --git a/Common/Textures/Genes/Icons/seduce.png b/Common/Textures/Genes/Icons/seduce.png
new file mode 100644
index 0000000..635132c
Binary files /dev/null and b/Common/Textures/Genes/Icons/seduce.png differ
diff --git a/Common/Textures/Genes/Icons/vagina_base.png b/Common/Textures/Genes/Icons/vagina_base.png
new file mode 100644
index 0000000..3f300a0
Binary files /dev/null and b/Common/Textures/Genes/Icons/vagina_base.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_east.png
new file mode 100644
index 0000000..7f51811
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_east.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_north.png
new file mode 100644
index 0000000..25c4097
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_north.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_south.png
new file mode 100644
index 0000000..60aae1e
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_south.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_east.png
new file mode 100644
index 0000000..f3be513
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_east.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_north.png
new file mode 100644
index 0000000..7a54823
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_north.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_south.png
new file mode 100644
index 0000000..91b5641
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_south.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_east.png
new file mode 100644
index 0000000..e08f0b3
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_east.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_north.png
new file mode 100644
index 0000000..60aae1e
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_north.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_south.png
new file mode 100644
index 0000000..0c9df93
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_south.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_east.png
new file mode 100644
index 0000000..ea33158
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_east.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_north.png
new file mode 100644
index 0000000..30e0e28
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_north.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_south.png
new file mode 100644
index 0000000..a9f56d7
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_south.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png
new file mode 100644
index 0000000..71e3f53
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png
new file mode 100644
index 0000000..ac55d17
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png differ
diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png
new file mode 100644
index 0000000..ac55d17
Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png differ
diff --git a/KNOWN_BUGS.md b/KNOWN_BUGS.md
index 3fe7439..3ce055e 100644
--- a/KNOWN_BUGS.md
+++ b/KNOWN_BUGS.md
@@ -2,6 +2,40 @@
Collection of Known Bugs and reasons for their origin.
+## Pawn does not refresh empty Fertilin!
+
+Issue: A pawn has 0 (or low) Fertilin, and a mood debuff. But they do not do anything about it.
+
+Reason: Pawns might go on a mental break when their fertilin is low to rape people. However, if your pawn is generally happy, they will not have a mental break. Then they run around with low fertilin.
+
+Workarounds / Solutions: Depending on your Gene-Setup, you might consider a cum-based diet. You can also tweak sex-settings for more sex need and hookups. Lastly, you can edit the xml to give higher mood penalties, which will lead to more mental breakdowns.
+
+In general, I am happy to hear your feedback. If you have other ideas how to change this to be a bit tricky but not too punishing please let me know.
+
+## Fertilin does not go up after Sex!
+
+Error: An Incubus or Succubus had sex with another pawn, but did not gain Fertilin.
+
+Things to consider:
+
+1. Please read descriptions of the respective genes - did you have "the right sex?"
+2. Check Hediffs of the fucked pawn - was it already drained?
+3. Did you fuck an animal? Check Settings for Fertilin-Multiplier
+4. Did the pawns really *finish* ? In case they throw up or get drafted there is no gain.
+
+There also is a known mod-conflict with `rjw Animations patch` (See #18), so make sure you use up-to-date versions of everything.
+
+## Seduce aborts on sex-start!
+
+Error: You have a succubus using seduce on a hostile pawn, they start sex but immediately abort.
+
+Things to Consider:
+
+1. Is your Succubus drafted? If not, they might have a flight-mode set and are scared of the enemy.
+2. Do you have mods changing combat AI? (CAI5000 or Combat Extended)
+
+It seems that things changing Enemy Combat AI also affect this. One report was about CAI5000 and we also expect Combat Extended to be incompatible.
+
## Random Vaginas for Goblins
Error: Pawns have different genitalia than expected, e.g. if the "no vagina" gene is specified there are pawns with vaginas AND a penis.
@@ -48,7 +82,7 @@ RimWorld.GeneMaker:MakeGene (Verse.GeneDef,Verse.Pawn)
Reason:
-RJW covers some corner cases when the pawn is changed before creation.
+RJW covers some corner cases when the pawn is changed before creation. This seems a bit legacy and related to Royalty-Content.
Current Solution:
@@ -56,10 +90,25 @@ Ignore this. The pawns seem to have the right sex and genitalia, I cannot "catch
Aimed Solution:
-Patch ChangeSex to skip for pawns with the two genes producing this.
+Patch RJW ChangeSex upstream to skip for pawns with the two genes producing this.
+
+## Error on Game Load: Verse.GeneDef named rjw_genes_human_genitalia (wanter=genes)
+
+Error: Issue #4, Game throws a warning on load that some Genes were not found.
+
+Reason: (Likely) because I removed some genes from Pre-Release to 1.0.0. Now some players have unknown definitions in their safe-files and Xenotype Defs.
+The removed Genes were the ones that performed default behaviour (e.g. normal breast size, normal penis size, ...)
+
+Solution: Should be safe to ignore, when you get this on safe-load make a quick new safe. new safe should not throw the error. For Self-Made Xenotypes remove the Genes.
+
+Sorry about this one, I know removal can break things but hey you were playing with the Prerelease!
## Insect Breeder does not fertilize
+Update:
+
+We changed behaviour in [1.0.1](https://github.com/vegapnk/RJW-Genes/releases/tag/1.0.1) and it seems to work now. Please tell us if you still encounter this.
+
Error:
A pawn with insect breeder fucks a pawn with unfertilized insect eggs, but the eggs stay unfertilized.
@@ -71,4 +120,4 @@ So testing this is super hard.
One thing - you need to have anal or vaginal sex for this to work. Any other sex type is currently not supported.
-For anything else, please help me gather information on this what you did and how things look. I reworked it once but I think it should work now.
\ No newline at end of file
+For anything else, please help me gather information on this what you did and how things look. I reworked it once but I think it should work now.
diff --git a/README.md b/README.md
index ec21dd7..cd3012d 100644
--- a/README.md
+++ b/README.md
@@ -2,17 +2,16 @@
This mod adds genes related and based on RJW to Rimworld.
-This is my first Mod I started from scratch so any feedback is very welcome.
-
## Current Features
- Different Genitalia Types
- Genitalia Size Scaling
- Extra Genitalia (and a Futa Attempt)
-- Some Traits, Cumflation Immunity, Elasticity
-- Cum-Amount Changes, Transfer Nutrition
-- Mech Breeding / Insect Breeding Support
+- Most RJW Traits, Cumflation Immunity, Elasticity
+- Cum-Amount Changes, Transfer Nutrition Boosts
+- Mech Breeding / Insect Breeding Additions
- Human-Animal Gene Inheritance merged from [Shabakur](https://github.com/Shabakur/RJW_Animal_Gene_Inheritance)
+- Succubi, Incubi & Cumazones that utilize Fertilin, similar to Hemogen
See [planned things](TODOS.md) and feel free to contribute.
With the Human-Animal-Gene Inheritance we have a lot of XML that you can contribute!
@@ -31,8 +30,7 @@ One of the main motivations was to have genes being added to the xenotypes that
## Load Order / Deps
-Please load this after any mod adding genes, and after the used RJW-Mods (Licentia, Sexperience).
-
-Should not be used with the original RJW_Animal_Gene_Inheritance anymore.
-
-There was an issue with other "Male-Only / Female-Only" Mods --- for which we provide our own Genes now.
\ No newline at end of file
+1. Please load this after any mod adding genes, and after the used RJW-Mods (Licentia, Sexperience).
+2. Should not be used with the original RJW_Animal_Gene_Inheritance anymore.
+3. There was an issue with other "Male-Only / Female-Only" Mods --- for which we provide our own Genes now.
+4. CAI5000 will not crash, but will make *Seduce*-Ability fail. I think same goes for Combat Extended.
\ No newline at end of file
diff --git a/Rjw-Genes.sln b/Rjw-Genes.sln
index 858f9a2..3706653 100644
--- a/Rjw-Genes.sln
+++ b/Rjw-Genes.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rjw-Genes", "Source\Rjw-Genes.csproj", "{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FB09ADF4-FC35-4C1F-9135-2B4C4E4ED347}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/Source/Animal_Inheritance/BestialityGeneInheritanceDef.cs b/Source/Animal_Inheritance/BestialityGeneInheritanceDef.cs
deleted file mode 100644
index 04a9735..0000000
--- a/Source/Animal_Inheritance/BestialityGeneInheritanceDef.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace RJW_BGS
-{
- public class BestialityGeneInheritanceDef
- {
- public string defName;
- public float chance = 1f;
- }
-}
diff --git a/Source/Animal_Inheritance/Defs/BestialityGeneInheritanceDef.cs b/Source/Animal_Inheritance/Defs/BestialityGeneInheritanceDef.cs
new file mode 100644
index 0000000..ae0c51e
--- /dev/null
+++ b/Source/Animal_Inheritance/Defs/BestialityGeneInheritanceDef.cs
@@ -0,0 +1,8 @@
+namespace RJW_BGS
+{
+ public class BestialityGeneInheritanceDef
+ {
+ public string defName;
+ public float chance = 1f;
+ }
+}
diff --git a/Source/Animal_Inheritance/RaceGeneDef.cs b/Source/Animal_Inheritance/Defs/RaceGeneDef.cs
similarity index 56%
rename from Source/Animal_Inheritance/RaceGeneDef.cs
rename to Source/Animal_Inheritance/Defs/RaceGeneDef.cs
index c4cbcea..10a9149 100644
--- a/Source/Animal_Inheritance/RaceGeneDef.cs
+++ b/Source/Animal_Inheritance/Defs/RaceGeneDef.cs
@@ -10,12 +10,12 @@ namespace RJW_BGS
{
public class RaceGeneDef : Def
{
-
- public String raceGroup;
+ public int priority;
+ public string raceGroup; //keeping this for backwards compatibility
+ public List raceGroups; //racegroup, but in list form so multiple can be entered, preference to use this over racegroup
public List raceNames;
public List pawnKindNames;
public List genes;
- //public List genechances;
- public String hybridName;
+ public string hybridName;
}
}
diff --git a/Source/Animal_Inheritance/Defs/RaceGeneDef_Helper.cs b/Source/Animal_Inheritance/Defs/RaceGeneDef_Helper.cs
new file mode 100644
index 0000000..cd01a47
--- /dev/null
+++ b/Source/Animal_Inheritance/Defs/RaceGeneDef_Helper.cs
@@ -0,0 +1,105 @@
+using rjw;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Verse;
+
+namespace RJW_BGS
+{
+ public class RaceGeneDef_Helper
+ {
+ //code based on racegroupdefinternal which has a similar function
+ public static RaceGeneDef GetRaceGeneDefInternal(Pawn pawn)
+ {
+ List Valids = ValidRaceGeneDefs(pawn);
+ if (Valids.Count > 0)
+ {
+ RaceGeneDef result = Valids.MaxBy(r => r.priority);
+ return result;
+ }
+ return null;
+ }
+
+ public static List ValidRaceGeneDefs(Pawn pawn)
+ {
+ PawnKindDef kindDef = pawn.kindDef;
+ if (kindDef == null)
+ {
+ ModLog.Warning($"Error looking up PawnKindDef for {pawn.Name} - Could not lookup Animal Inheritance Genes");
+ return null;
+ }
+
+ string raceName = kindDef.race.defName;
+ string pawnKindName = kindDef.defName;
+ //Wild animals have no name, so we will use pawnkindname instead
+ string pawnName = pawn.Name != null ? pawn.Name.ToStringFull : pawnKindName;
+ PawnData pawnData = SaveStorage.DataStore.GetPawnData(pawn);
+ RaceGroupDef raceGroupDef = pawnData.RaceSupportDef;
+
+ if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"Looking up Animal-Inheritable Genes for {pawnName} with KindDef {kindDef.defName},RaceName {raceName}, PawnKind {pawnKindName} and RaceGroup {raceGroupDef.defName}");
+
+ IEnumerable allDefs = DefDatabase.AllDefs;
+ List pawnKindDefs = allDefs.Where(delegate (RaceGeneDef group)
+ {
+ List pawnKindNames = group.pawnKindNames;
+ return pawnKindNames != null && pawnKindNames.Contains(pawnKindName);
+ }).ToList();
+ if (pawnKindDefs.Count() > 0)
+ {
+ DebugPrintRaceGeneDefs("PawnKindDefs", pawnName,pawnKindDefs);
+ return pawnKindDefs;
+ }
+ else if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"Did not find PawnKindDefs for {pawnName}");
+
+ List raceKindDefs = allDefs.Where(delegate (RaceGeneDef group)
+ {
+ List raceNames = group.raceNames;
+ return raceNames != null && raceNames.Contains(raceName);
+ }).ToList();
+ if (raceKindDefs.Count() > 0)
+ {
+ DebugPrintRaceGeneDefs("PawnKindDefs", pawnName, raceKindDefs);
+ return raceKindDefs;
+ }
+ else if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"Did not find RaceKindDefs for {pawnName}");
+
+ List raceGroupDefs = new List();
+ if (raceGroupDef != null)
+ {
+ raceGroupDefs = allDefs.Where(delegate (RaceGeneDef group)
+ {
+ string raceGroupDefName = group.raceGroup;
+ List list_raceGroupDefName = group.raceGroups;
+ return (raceGroupDefName != null && raceGroupDefName == raceGroupDef.defName)
+ || (list_raceGroupDefName != null && list_raceGroupDefName.Contains(raceGroupDef.defName));
+ }).ToList();
+ }
+
+ if (raceGroupDefs.Count() > 0)
+ {
+ DebugPrintRaceGeneDefs("RaceKindDefs", pawnName, raceGroupDefs);
+ return raceGroupDefs;
+ }
+ else if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"Did not find RaceGroupDefs for {pawnName}");
+
+ ModLog.Message($"Did not find any Genes inheritable for {pawnName}");
+ return new List();
+ }
+
+ private static void DebugPrintRaceGeneDefs(String header,String identifier,List defs)
+ {
+ if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ {
+ var defString = "[";
+ foreach (RaceGeneDef raceGeneDef in defs)
+ defString += $"({raceGeneDef.priority}:{raceGeneDef.defName} - {raceGeneDef.genes.Count} Genes)";
+ defString += "]";
+ ModLog.Message($"Found the following {header}-Genes for {identifier}: {defString}");
+ }
+ }
+ }
+}
diff --git a/Source/Animal_Inheritance/First.cs b/Source/Animal_Inheritance/First.cs
deleted file mode 100644
index 8194ab3..0000000
--- a/Source/Animal_Inheritance/First.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using rjw;
-using Verse;
-using RimWorld;
-
-namespace RJW_BGS
-{
- [StaticConstructorOnStartup]
- internal static class First
- {
- static First()
- {
- //RJWcopy.Racegroupdictbuilder();
- //Prints all found race dicts (debugging only)
- //logAllFoundRaceGroupGenes
-
- }
-
- private static void logAllFoundRaceGroupGenes()
- {
- foreach (RaceGroupDef def in DefDatabase.AllDefs)
- {
- Log.Message("defName = " + def.defName);
- if (def.raceNames != null)
- {
- foreach (string race in def.raceNames)
- {
- Log.Message(race);
- }
- }
- }
- }
- }
-}
diff --git a/Source/Animal_Inheritance/InheritanceUtility.cs b/Source/Animal_Inheritance/InheritanceUtility.cs
index 2b260dd..de486ae 100644
--- a/Source/Animal_Inheritance/InheritanceUtility.cs
+++ b/Source/Animal_Inheritance/InheritanceUtility.cs
@@ -1,10 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Collections.Generic;
using Verse;
using RimWorld;
+using rjw;
namespace RJW_BGS
{
@@ -19,14 +16,18 @@ namespace RJW_BGS
if (mother.RaceProps.Humanlike && father.RaceProps.Humanlike)
return genelist;
-
+ ModLog.Message($"Trigger an Animal-Gene-Inheritance for {father.Name} and {mother.Name}");
//One parent must be an animal and the other must be human, so only one needs to return
if (father != null && !father.RaceProps.Humanlike)
{
+ if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"Father was found to be animal - looking up genes for {father.Name}");
return SelectGenes(father);
}
if (mother != null && !mother.RaceProps.Humanlike)
{
+ if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"Mother was found to be animal - looking up genes for {mother.Name}");
return SelectGenes(mother);
}
@@ -42,30 +43,53 @@ namespace RJW_BGS
public static List SelectGenes(Pawn pawn)
{
List genelist = new List();
- RaceGeneDef raceGeneDef = RJWcopy.GetRaceGeneDefInternal(pawn);
+ RaceGeneDef raceGeneDef = RaceGeneDef_Helper.GetRaceGeneDefInternal(pawn);
if (raceGeneDef != null)
{
foreach (BestialityGeneInheritanceDef gene in raceGeneDef.genes)
{
- if (gene.chance >= Rand.Range(0.01f,1f))
+ if (gene.chance * RJW_BGSSettings.rjw_bgs_global_gene_chance >= Rand.Range(0.01f,1f))
{
genelist.Add(DefDatabase.GetNamed(gene.defName));
}
}
}
+ if (RJW_BGSSettings.rjw_bgs_detailed_debug)
+ ModLog.Message($"From {raceGeneDef.genes.Count} possible genes in {raceGeneDef.defName}, {genelist.Count} were added by chance ({RJW_BGSSettings.rjw_bgs_global_gene_chance} chance multiplier from Settings).");
return genelist;
}
+
+ ///
+ /// Adds a list of Genes to the pawns existing GeneSet.
+ /// Whether it is added as a Xenogene or Endogene is configured in Mod-Settings.
+ ///
+ /// The pawn for which Genes will be added
+ /// The Genes to add (Endogene by default, Xenogene with Mod Settings)
public static void AddGenes(Pawn pawn, List genes)
{
foreach (GeneDef gene in genes)
{
- pawn.genes.AddGene(gene, false);
+ pawn.genes.AddGene(gene, RJW_BGSSettings.rjw_bgs_animal_genes_as_xenogenes);
}
}
+ ///
+ /// Initiates a bestiality baby with genes if the baby does not exist earlier.
+ /// This is used to make rjw-egg-pregnancies work.
+ /// Related file: PatchRJWHediffInsect_Egg.cs
+ ///
+ /// The mother of the baby.
+ /// The father of the baby.
+ /// The baby created in non-pregnancy-way (has 0 Genes yet)
public static void NewGenes(Pawn mother, Pawn dad, Pawn baby)
{
+ if (!RJW_BGSSettings.rjw_bgs_enabled)
+ {
+ return;
+ }
+
+ ModLog.Message($"Triggering an New-Gene Animal-Gene-Inheritance for {baby.Name} ({dad.Name} + {mother.Name})");
if (baby.RaceProps.Humanlike)
{
if (baby.genes == null)
@@ -115,5 +139,22 @@ namespace RJW_BGS
}
}
+ ///
+ /// Used only for debugging, to see what you loaded and how it looks.
+ ///
+ private static void logAllFoundRaceGroupGenes()
+ {
+ foreach (RaceGroupDef def in DefDatabase.AllDefs)
+ {
+ Log.Message("defName = " + def.defName);
+ if (def.raceNames != null)
+ {
+ foreach (string race in def.raceNames)
+ {
+ Log.Message(race);
+ }
+ }
+ }
+ }
}
}
diff --git a/Source/Animal_Inheritance/PatchRJWBestialityPregnancyUtility.cs b/Source/Animal_Inheritance/Patches/Patch_RJW_BestialityPregnancyUtility.cs
similarity index 70%
rename from Source/Animal_Inheritance/PatchRJWBestialityPregnancyUtility.cs
rename to Source/Animal_Inheritance/Patches/Patch_RJW_BestialityPregnancyUtility.cs
index 5224c4f..c5f6366 100644
--- a/Source/Animal_Inheritance/PatchRJWBestialityPregnancyUtility.cs
+++ b/Source/Animal_Inheritance/Patches/Patch_RJW_BestialityPregnancyUtility.cs
@@ -11,11 +11,15 @@ using rjw;
namespace RJW_BGS
{
[HarmonyPatch(typeof(Hediff_BasePregnancy), "Initialize")]
- public static class PatchRJWBestialityPregnancyUtility
+ public static class Patch_RJW_BestialityPregnancyUtility
{
[HarmonyPostfix]
public static void AddGenes(Pawn mother, Pawn dad, ref Hediff_BasePregnancy __instance)
{
+ if (!RJW_BGSSettings.rjw_bgs_enabled)
+ {
+ return;
+ }
foreach (Pawn baby in __instance.babies)
{
if (baby.RaceProps.Humanlike)
@@ -25,20 +29,21 @@ namespace RJW_BGS
baby.genes = new Pawn_GeneTracker(baby);
}
+
//Remove the hair and skin genes pawns always start with, should get correct ones from human parent anyway.
for (int i = baby.genes.Endogenes.Count - 1; i >= 0; i--)
{
baby.genes.RemoveGene(baby.genes.Endogenes[i]);
}
- List genes = PregnancyUtility.GetInheritedGenes(dad, mother);
+ List humangenes = PregnancyUtility.GetInheritedGenes(dad, mother);
List beastgenes = InheritanceUtility.AnimalInheritedGenes(dad, mother);
InheritanceUtility.AddGenes(baby, beastgenes);
- InheritanceUtility.AddGenes(baby, genes);
- //foreach (GeneDef gene in genes)
- //{
- // baby.genes.AddGene(gene, false);
- //}
+ InheritanceUtility.AddGenes(baby, humangenes);
+
+ // The mix-breed babies should be labelled hybrids
+ baby.genes.hybrid = true;
+ baby.genes.xenotypeName = "Hybrid";
}
}
}
diff --git a/Source/Animal_Inheritance/PatchRJWHediffInsect_Egg.cs b/Source/Animal_Inheritance/Patches/Patch_RJW_HediffInsect_Egg.cs
similarity index 87%
rename from Source/Animal_Inheritance/PatchRJWHediffInsect_Egg.cs
rename to Source/Animal_Inheritance/Patches/Patch_RJW_HediffInsect_Egg.cs
index d52f62d..9861537 100644
--- a/Source/Animal_Inheritance/PatchRJWHediffInsect_Egg.cs
+++ b/Source/Animal_Inheritance/Patches/Patch_RJW_HediffInsect_Egg.cs
@@ -1,19 +1,13 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using HarmonyLib;
using rjw;
-using RimWorld;
-using Verse;
namespace RJW_BGS
{
[HarmonyPatch(typeof(Hediff_InsectEgg), "GiveBirth")]
- public static class PatchRJWHediffInsect_Egg
+ public static class Patch_RJW_HediffInsect_Egg
{
[HarmonyTranspiler]
public static IEnumerable Transpiler(IEnumerable instructions)
diff --git a/Source/Animal_Inheritance/PatchVanillaPregnancyUtility.cs b/Source/Animal_Inheritance/Patches/Patch_Vanilla_PregnancyUtility.cs
similarity index 63%
rename from Source/Animal_Inheritance/PatchVanillaPregnancyUtility.cs
rename to Source/Animal_Inheritance/Patches/Patch_Vanilla_PregnancyUtility.cs
index 0f5cc90..28f872f 100644
--- a/Source/Animal_Inheritance/PatchVanillaPregnancyUtility.cs
+++ b/Source/Animal_Inheritance/Patches/Patch_Vanilla_PregnancyUtility.cs
@@ -1,15 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using Verse;
-using rjw;
namespace RJW_BGS
{
+ ///
+ /// This Patch is applied to change the normal pregnancy to add animal-inheritance.
+ /// If the settings allow animal gene inheritance,
+ /// the genes are determined and "simply added".
+ ///
[HarmonyPatch(typeof(PregnancyUtility), "GetInheritedGeneSet", new Type[]
{
typeof(Pawn),
@@ -17,11 +19,15 @@ namespace RJW_BGS
//typeof(bool)
}
)]
- public static class PatchVanillaPregnancyUtility
+ public static class Patch_Vanilla_PregnancyUtility
{
[HarmonyPostfix]
public static void AnimalInheritedGenes(Pawn father, Pawn mother, ref GeneSet __result)
{
+ if (!RJW_BGSSettings.rjw_bgs_enabled)
+ {
+ return;
+ }
List genes = InheritanceUtility.AnimalInheritedGenes(father, mother);
if (genes.Any())
{
@@ -29,7 +35,7 @@ namespace RJW_BGS
{
__result.AddGene(gene);
}
- }
+ }
}
}
}
diff --git a/Source/Animal_Inheritance/RJW_BGSSettings.cs b/Source/Animal_Inheritance/RJW_BGSSettings.cs
deleted file mode 100644
index 1d5d859..0000000
--- a/Source/Animal_Inheritance/RJW_BGSSettings.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Verse;
-using UnityEngine;
-
-namespace RJW_Genes.Animal_Inheritance
-{
- public class RJW_BGSSettings : ModSettings
- {
- public static void DoWindowContents(Rect inRect)
- {
- //Copied from RJW settings mostly
- Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
- Rect rect = new Rect(0f, 0f, inRect.width - 16f, inRect.height + 300f);
- //Widgets.BeginScrollView(outRect, ref RJWSettings.scrollPosition, rect, true);
- Listing_Standard listing_Standard = new Listing_Standard();
- listing_Standard.maxOneColumn = true;
- listing_Standard.ColumnWidth = rect.width / 2.05f;
- listing_Standard.Begin(rect);
- listing_Standard.Gap(24f);
- listing_Standard.CheckboxLabeled("enabled", ref enabled, "no function yet", 0f, 1f);
- //listing_Standard.CheckboxLabeled("sexfrenzy", ref sexfrenzy, "disable the effects", 0f, 1f);
- listing_Standard.End();
- }
-
- public override void ExposeData()
- {
- base.ExposeData();
- Scribe_Values.Look(ref RJW_BGSSettings.enabled, "enabled", RJW_BGSSettings.enabled, true);
- }
-
- public static bool enabled;
- }
-}
diff --git a/Source/Animal_Inheritance/RaceGeneDef_Helper.cs b/Source/Animal_Inheritance/RaceGeneDef_Helper.cs
deleted file mode 100644
index ed6541a..0000000
--- a/Source/Animal_Inheritance/RaceGeneDef_Helper.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using rjw;
-using Verse;
-using RimWorld;
-
-namespace RJW_BGS
-{
- internal class RJWcopy
- {
- //code based on racegroupdefinternal which has a similar function
- public static RaceGeneDef GetRaceGeneDefInternal(Pawn pawn)
- {
- PawnKindDef kindDef = pawn.kindDef;
- if (kindDef == null)
- {
- return null;
- }
- string raceName = kindDef.race.defName;
- string pawnKindName = kindDef.defName;
- IEnumerable allDefs = DefDatabase.AllDefs;
- PawnData pawnData = SaveStorage.DataStore.GetPawnData(pawn);
- RaceGroupDef raceGroupDef = pawnData.RaceSupportDef;
- List pawnKindDefs = allDefs.Where(delegate (RaceGeneDef group)
- {
- List pawnKindNames = group.pawnKindNames;
- return pawnKindNames != null && pawnKindNames.Contains(pawnKindName);
- }).ToList();
- List raceKindDefs = allDefs.Where(delegate (RaceGeneDef group)
- {
- List raceNames = group.raceNames;
- return raceNames != null && raceNames.Contains(raceName);
- }).ToList();
- List raceGroupDefs = new List();
- if (raceGroupDef != null)
- {
- raceGroupDefs = allDefs.Where(delegate (RaceGeneDef group)
- {
- String raceGroupDefName = group.raceGroup;
- return raceGroupDefName != null && raceGroupDefName == raceGroupDef.defName;
- }).ToList();
- }
- RaceGeneDef result = null;
- //First check if there is a matching pawnkinddef then race, then racegroup
- if (pawnKindDefs.Any())
- {
- result = pawnKindDefs.RandomElement();
- }
- else if (raceKindDefs.Any() && result == null)
- {
- result = raceKindDefs.RandomElement();
- }
- else if (raceGroupDefs.Any() && result == null)
- {
- result = raceGroupDefs.RandomElement();
- }
- else
- {
- result = null;
- }
- return result;
-
-
- }
- }
-}
diff --git a/Source/Animal_Inheritance/Settings/RJW_BGSSettings.cs b/Source/Animal_Inheritance/Settings/RJW_BGSSettings.cs
new file mode 100644
index 0000000..d619354
--- /dev/null
+++ b/Source/Animal_Inheritance/Settings/RJW_BGSSettings.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using UnityEngine;
+
+namespace RJW_BGS
+{
+ public class RJW_BGSSettings : ModSettings
+ {
+ public static void DoWindowContents(Rect inRect)
+ {
+ //Copied from RJW settings mostly
+ Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
+ Rect rect = new Rect(0f, 0f, inRect.width - 16f, inRect.height + 300f);
+ //Widgets.BeginScrollView(outRect, ref RJWSettings.scrollPosition, rect, true);
+ Listing_Standard listing_Standard = new Listing_Standard();
+ listing_Standard.maxOneColumn = true;
+ listing_Standard.ColumnWidth = rect.width / 2.05f;
+ listing_Standard.Begin(rect);
+ listing_Standard.Gap(24f);
+ listing_Standard.CheckboxLabeled("enabled", ref rjw_bgs_enabled, "If toggled, Animal Pregnancies will try inherit genes.", 0f, 1f);
+ //listing_Standard.CheckboxLabeled("sexfrenzy", ref sexfrenzy, "disable the effects", 0f, 1f);
+ listing_Standard.Gap(5f);
+ listing_Standard.Label("gene inheritance chance"+ ": " +
+ Math.Round((double)(RJW_BGSSettings.rjw_bgs_global_gene_chance * 100f), 0).ToString() + "%", -1f, "modify chance for a gene to be inherited.");
+ RJW_BGSSettings.rjw_bgs_global_gene_chance = listing_Standard.Slider(RJW_BGSSettings.rjw_bgs_global_gene_chance, 0f, 5f);
+ listing_Standard.Gap(5f);
+ listing_Standard.CheckboxLabeled("genes as xenogenes", ref rjw_bgs_animal_genes_as_xenogenes, "If toggled, animal genes will be added as xenogenes.", 0f, 1f);
+ listing_Standard.Gap(5f);
+ listing_Standard.CheckboxLabeled("detailed-debug", ref rjw_bgs_detailed_debug, "Adds detailed information to the log about pregnancies and genes.", 0f, 1f);
+ listing_Standard.End();
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref RJW_BGSSettings.rjw_bgs_enabled, "rjw_bgs_enabled", RJW_BGSSettings.rjw_bgs_enabled, true);
+ Scribe_Values.Look(ref RJW_BGSSettings.rjw_bgs_global_gene_chance, "rjw_bgs_global_gene_chance", RJW_BGSSettings.rjw_bgs_global_gene_chance, true);
+ Scribe_Values.Look(ref RJW_BGSSettings.rjw_bgs_animal_genes_as_xenogenes, "rjw_bgs_animal_genes_as_xenogenes", RJW_BGSSettings.rjw_bgs_animal_genes_as_xenogenes, true);
+ Scribe_Values.Look(ref RJW_BGSSettings.rjw_bgs_detailed_debug, "rjw_bgs_detailed_debug", RJW_BGSSettings.rjw_bgs_detailed_debug, true);
+ }
+
+ public static float rjw_bgs_global_gene_chance = 1f;
+ public static bool rjw_bgs_enabled = true;
+ public static bool rjw_bgs_animal_genes_as_xenogenes = false;
+ public static bool rjw_bgs_detailed_debug = false;
+ }
+}
diff --git a/Source/Animal_Inheritance/RJW_BGSSettingsController.cs b/Source/Animal_Inheritance/Settings/RJW_BGSSettingsController.cs
similarity index 94%
rename from Source/Animal_Inheritance/RJW_BGSSettingsController.cs
rename to Source/Animal_Inheritance/Settings/RJW_BGSSettingsController.cs
index 53a7659..12ef107 100644
--- a/Source/Animal_Inheritance/RJW_BGSSettingsController.cs
+++ b/Source/Animal_Inheritance/Settings/RJW_BGSSettingsController.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
using Verse;
using UnityEngine;
-namespace RJW_Genes.Animal_Inheritance
+namespace RJW_BGS
{
public class RJW_BGSSettingsController : Mod
{
diff --git a/Source/Common/ModLog.cs b/Source/Common/ModLog.cs
new file mode 100644
index 0000000..407520a
--- /dev/null
+++ b/Source/Common/ModLog.cs
@@ -0,0 +1,34 @@
+using Verse;
+
+namespace RJW_Genes
+{
+ internal class ModLog
+ {
+ public static string ModId => "RJW-Genes";
+
+ ///
+ /// Logs the given message with [SaveStorage.ModId] appended.
+ ///
+ public static void Error(string message)
+ {
+ Log.Error($"[{ModId}] {message}");
+ }
+
+ ///
+ /// Logs the given message with [SaveStorage.ModId] appended.
+ ///
+ public static void Message(string message)
+ {
+ Log.Message($"[{ModId}] {message}");
+ }
+
+ ///
+ /// Logs the given message with [SaveStorage.ModId] appended.
+ ///
+ public static void Warning(string message)
+ {
+ Log.Warning($"[{ModId}] {message}");
+ }
+
+ }
+}
diff --git a/Source/First.cs b/Source/First.cs
new file mode 100644
index 0000000..101d3cc
--- /dev/null
+++ b/Source/First.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using rjw;
+using Verse;
+using RimWorld;
+using rjw.Modules.Interactions.Rules.PartKindUsageRules;
+using rjw.Modules.Interactions.Internals.Implementation;
+
+namespace RJW_Genes
+{
+ [StaticConstructorOnStartup]
+ internal static class First
+ {
+ static First()
+ {
+ AddtoIPartPreferenceRule();
+ }
+
+ //Modified code from https://gitgud.io/lutepickle/rjw_menstruation/-/tree/main/1.4/source/RJW_Menstruation/RJW_Menstruation
+ //Summary//
+ //Adds our own partpreferences to rjw's list. Our partpreferences are under Interactions.GenesPartKindUsageRule
+ //
+ private static void InjectIntoRjwInteractionServices()
+ {
+ List partPreferenceRules = Unprivater.GetProtectedValue>("_partKindUsageRules", typeof(PartPreferenceDetectorService));
+ partPreferenceRules.Add(new Interactions.GenesPartKindUsageRule());
+ }
+ }
+}
diff --git a/Source/GeneDefOf.cs b/Source/GeneDefOf.cs
index 744eb11..e4af81f 100644
--- a/Source/GeneDefOf.cs
+++ b/Source/GeneDefOf.cs
@@ -1,6 +1,6 @@
using RimWorld;
using Verse;
-
+using Verse.AI;
namespace RJW_Genes
{
[DefOf]
@@ -51,6 +51,7 @@ namespace RJW_Genes
public static readonly GeneDef rjw_genes_mechbreeder;
public static readonly GeneDef rjw_genes_insectincubator;
public static readonly GeneDef rjw_genes_insectbreeder;
+ public static readonly GeneDef rjw_genes_zoophile;
// Cum
public static readonly GeneDef rjw_genes_no_cum;
@@ -63,13 +64,39 @@ namespace RJW_Genes
// Reproduction
public static readonly GeneDef rjw_genes_hypersexual;
public static readonly GeneDef rjw_genes_rapist;
- public static readonly GeneDef rjw_genes_zoophile;
+ public static readonly GeneDef rjw_genes_homosexual;
+ public static readonly GeneDef rjw_genes_bisexual;
// Damage & Side Effects
[MayRequire("LustLicentia.RJWLabs")] public static readonly GeneDef rjw_genes_elasticity;
+ public static readonly GeneDef rjw_genes_unbreakable;
// Special
public static readonly GeneDef rjw_genes_orgasm_rush;
+ public static readonly GeneDef rjw_genes_youth_fountain;
+ public static readonly GeneDef rjw_genes_sex_age_drain;
+ public static readonly GeneDef rjw_genes_aphrodisiac_pheromones;
+
+ // LifeForce
+ public static readonly GeneDef rjw_genes_lifeforce;
+ public static readonly GeneDef rjw_genes_pussyhealing;
+ public static readonly GeneDef rjw_genes_lifeforce_drain;
+ public static readonly GeneDef rjw_genes_cum_eater;
+ public static readonly GeneDef rjw_genes_fertilin_absorber;
+ public static readonly GeneDef rjw_genes_drainer;
+ public static readonly GeneDef rjw_genes_seduce;
+ public static readonly GeneDef rjw_genes_paralysingkiss;
+ public static readonly GeneDef rjw_genes_cockeater;
+
+ // Cosmetic
+ public static readonly GeneDef rjw_genes_succubus_tail;
+ public static readonly GeneDef rjw_genes_succubus_wings;
+
+ //Other Defs
+ public static readonly XenotypeDef rjw_genes_succubus;
+ public static readonly DutyDef rjw_genes_flirt;
+ public static readonly MentalBreakDef rjw_genes_lifeforce_randomrape;
}
+
}
diff --git a/Source/Genes/Breeding/Patch_EggFertilization.cs b/Source/Genes/Breeding/Patch_EggFertilization.cs
index 46ec598..d2f2dcf 100644
--- a/Source/Genes/Breeding/Patch_EggFertilization.cs
+++ b/Source/Genes/Breeding/Patch_EggFertilization.cs
@@ -14,9 +14,8 @@ namespace RJW_Genes
/// Normal Egg-Pregnancy logic is in https://gitgud.io/Ed86/rjw/-/blob/master/1.4/Source/Modules/Pregnancy/Pregnancy_Helper.cs
///
[HarmonyPatch(typeof(SexUtility), "Aftersex")]
- static class PatchEggFertilizationHelper
+ static class Patch_EggFertilization
{
- [HarmonyTranspiler]
public static void Postfix(SexProps props)
{
// Only Fertilize on vaginal / anal sex
@@ -59,7 +58,7 @@ namespace RJW_Genes
}
- private static Boolean canDoEggFertilization(Pawn a, Pawn b)
+ private static bool canDoEggFertilization(Pawn a, Pawn b)
{
// No Partner / Other Errors
diff --git a/Source/Genes/Cum/CumUtility.cs b/Source/Genes/Cum/CumUtility.cs
index ea049cc..b483aed 100644
--- a/Source/Genes/Cum/CumUtility.cs
+++ b/Source/Genes/Cum/CumUtility.cs
@@ -33,5 +33,35 @@ namespace RJW_Genes
}
}
+
+ //Get total fluidamount a person has.
+ public static float GetTotalFluidAmount(Pawn pawn, float multiplier = 1f)
+ {
+ var partBPR = Genital_Helper.get_genitalsBPR(pawn);
+ var parts = Genital_Helper.get_PartsHediffList(pawn, partBPR);
+ float total_cum = 0;
+ if (!parts.NullOrEmpty())
+ {
+ CompHediffBodyPart CompHediff;
+
+ foreach (Hediff part in parts)
+ {
+ if (GenitaliaChanger.IsArtificial(part))
+ continue;
+
+ if (rjw.Genital_Helper.is_penis(part))
+ {
+ CompHediff = part.TryGetComp();
+ if (CompHediff != null)
+ {
+ total_cum += CompHediff.FluidAmmount * CompHediff.FluidModifier * multiplier;
+ }
+ }
+ }
+
+ }
+ return total_cum;
+
+ }
}
}
diff --git a/Source/Genes/Damage/Gene_Elasticity.cs b/Source/Genes/Damage/Gene_Elasticity.cs
index 603a18d..5d92b51 100644
--- a/Source/Genes/Damage/Gene_Elasticity.cs
+++ b/Source/Genes/Damage/Gene_Elasticity.cs
@@ -10,8 +10,6 @@ namespace RJW_Genes
///
public class Gene_Elasticity : Gene
{
-
- private int ticksToReset = RESET_INTERVAL;
private const int RESET_INTERVAL = 60000; // 60k should be 1 day
public override void PostAdd()
@@ -26,11 +24,8 @@ namespace RJW_Genes
public override void Tick()
{
base.Tick();
- --this.ticksToReset;
- if (this.ticksToReset > 0)
- return;
- this.ticksToReset = RESET_INTERVAL;
- ResetSeverity();
+ if (pawn.IsHashIntervalTick(RESET_INTERVAL))
+ ResetSeverity();
}
public override void PostRemove()
diff --git a/Source/Genes/Damage/Gene_Unbreakable.cs b/Source/Genes/Damage/Gene_Unbreakable.cs
new file mode 100644
index 0000000..578ed8a
--- /dev/null
+++ b/Source/Genes/Damage/Gene_Unbreakable.cs
@@ -0,0 +1,40 @@
+using rjw;
+using Verse;
+
+namespace RJW_Genes
+{
+ ///
+ /// This Gene regularly removes the broken hediff of a pawn.
+ /// Blocking / Removing thoughts are done in an XML Patch.
+ ///
+ public class Gene_Unbreakable : Gene
+ {
+ /// DevNote: I first tried to Harmony-Postfix the AfterSexUtility and never add it - but that failed?
+
+ private const int RESET_INTERVAL = 30000; // 30k should be 0.5 day
+ public override void PostAdd()
+ {
+ base.PostAdd();
+ RemoveBrokenHediff();
+ }
+
+ public override void Tick()
+ {
+ base.Tick();
+ if (pawn.IsHashIntervalTick(RESET_INTERVAL))
+ RemoveBrokenHediff();
+ }
+
+
+
+ private void RemoveBrokenHediff()
+ {
+ // Clean-Up of existing feeling brokens
+ var maybeBrokenHediff = pawn.health.hediffSet.GetFirstHediffOfDef(xxx.feelingBroken);
+ if (maybeBrokenHediff != null)
+ {
+ pawn.health.RemoveHediff(maybeBrokenHediff);
+ }
+ }
+ }
+}
diff --git a/Source/Genes/ExtraGenitalia/Gene_ExtraAnus.cs b/Source/Genes/ExtraGenitalia/Gene_ExtraAnus.cs
index cea77f2..65121e9 100644
--- a/Source/Genes/ExtraGenitalia/Gene_ExtraAnus.cs
+++ b/Source/Genes/ExtraGenitalia/Gene_ExtraAnus.cs
@@ -1,6 +1,7 @@
using Verse;
using rjw;
using RimWorld;
+using System.Linq;
namespace RJW_Genes
{
@@ -13,6 +14,13 @@ namespace RJW_Genes
{
base.PostMake();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoAnus())
+ {
+ return;
+ }
+
if (additional_anus == null)
{
CreateAndAddAnus();
@@ -23,6 +31,13 @@ namespace RJW_Genes
{
base.PostAdd();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoAnus())
+ {
+ return;
+ }
+
if (additional_anus == null)
{
CreateAndAddAnus();
@@ -53,5 +68,15 @@ namespace RJW_Genes
pawn.health.AddHediff(additional_anus, partBPR);
}
+ internal bool HasAlreadyTwoAnus()
+ {
+ if (pawn == null)
+ return false;
+
+ var possible_breasts =
+ Genital_Helper.get_AllPartsHediffList(pawn).Where(t => Genital_Helper.is_anus(t));
+
+ return possible_breasts.Count() >= 2;
+ }
}
}
diff --git a/Source/Genes/ExtraGenitalia/Gene_ExtraBreasts.cs b/Source/Genes/ExtraGenitalia/Gene_ExtraBreasts.cs
index 8829854..84fb107 100644
--- a/Source/Genes/ExtraGenitalia/Gene_ExtraBreasts.cs
+++ b/Source/Genes/ExtraGenitalia/Gene_ExtraBreasts.cs
@@ -1,6 +1,7 @@
using Verse;
using rjw;
using RimWorld;
+using System.Linq;
namespace RJW_Genes
{
@@ -13,6 +14,13 @@ namespace RJW_Genes
{
base.PostMake();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoBreasts())
+ {
+ return;
+ }
+
// Tits are only added for female pawns!
if (GenderUtility.IsFemale(pawn) && additional_breasts == null)
{
@@ -24,6 +32,13 @@ namespace RJW_Genes
{
base.PostAdd();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoBreasts())
+ {
+ return;
+ }
+
// Tits are only added for female pawns!
if (GenderUtility.IsFemale(pawn) && additional_breasts == null)
{
@@ -55,5 +70,16 @@ namespace RJW_Genes
pawn.health.AddHediff(additional_breasts, partBPR);
}
+ internal bool HasAlreadyTwoBreasts()
+ {
+ if (pawn == null)
+ return false;
+
+ var possible_breasts =
+ Genital_Helper.get_AllPartsHediffList(pawn).Where(t => t.def.defName.Contains("breast"));
+
+ return possible_breasts.Count() >= 2;
+ }
+
}
}
diff --git a/Source/Genes/ExtraGenitalia/Gene_ExtraPenis.cs b/Source/Genes/ExtraGenitalia/Gene_ExtraPenis.cs
index aee18c7..7b8fcb4 100644
--- a/Source/Genes/ExtraGenitalia/Gene_ExtraPenis.cs
+++ b/Source/Genes/ExtraGenitalia/Gene_ExtraPenis.cs
@@ -1,6 +1,7 @@
using Verse;
using rjw;
using RimWorld;
+using System.Linq;
namespace RJW_Genes
{
@@ -13,6 +14,13 @@ namespace RJW_Genes
{
base.PostMake();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoPenis())
+ {
+ return;
+ }
+
// Penis are only added for male pawns!
if (GenderUtility.IsMale(pawn) && additional_penis == null)
{
@@ -24,6 +32,13 @@ namespace RJW_Genes
{
base.PostAdd();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoPenis())
+ {
+ return;
+ }
+
// Penis are only added for male pawns!
if (GenderUtility.IsMale(pawn) && additional_penis == null)
{
@@ -55,5 +70,17 @@ namespace RJW_Genes
pawn.health.AddHediff(additional_penis, partBPR);
}
+
+ internal bool HasAlreadyTwoPenis()
+ {
+ if (pawn == null)
+ return false;
+
+ var possible_breasts =
+ Genital_Helper.get_AllPartsHediffList(pawn).Where(t => Genital_Helper.is_penis(t));
+
+ return possible_breasts.Count() >= 2;
+ }
+
}
}
diff --git a/Source/Genes/ExtraGenitalia/Gene_ExtraVagina.cs b/Source/Genes/ExtraGenitalia/Gene_ExtraVagina.cs
index 9940de0..fa02b87 100644
--- a/Source/Genes/ExtraGenitalia/Gene_ExtraVagina.cs
+++ b/Source/Genes/ExtraGenitalia/Gene_ExtraVagina.cs
@@ -1,6 +1,7 @@
using Verse;
using rjw;
using RimWorld;
+using System.Linq;
namespace RJW_Genes
{
@@ -18,6 +19,13 @@ namespace RJW_Genes
{
base.PostMake();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoVaginas())
+ {
+ return;
+ }
+
// Vaginas are only added for female pawns!
if (GenderUtility.IsFemale(pawn) && additional_vagina == null)
{
@@ -29,6 +37,13 @@ namespace RJW_Genes
{
base.PostAdd();
+ // Some sources add Genes before they fire, e.g. Character Editor
+ // This should harden the gene, to solve #19
+ if (HasAlreadyTwoVaginas())
+ {
+ return;
+ }
+
// Vaginas are only added for female pawns!
if (GenderUtility.IsFemale(pawn) && additional_vagina == null)
{
@@ -60,5 +75,15 @@ namespace RJW_Genes
pawn.health.AddHediff(additional_vagina, partBPR);
}
+ internal bool HasAlreadyTwoVaginas()
+ {
+ if (pawn == null)
+ return false;
+
+ var possible_breasts =
+ Genital_Helper.get_AllPartsHediffList(pawn).Where(t => Genital_Helper.is_vagina(t));
+
+ return possible_breasts.Count() >= 2;
+ }
}
}
diff --git a/Source/Genes/ExtraGenitalia/Gene_Futa.cs b/Source/Genes/ExtraGenitalia/Gene_Futa.cs
index 2d9f367..812f381 100644
--- a/Source/Genes/ExtraGenitalia/Gene_Futa.cs
+++ b/Source/Genes/ExtraGenitalia/Gene_Futa.cs
@@ -13,6 +13,12 @@ namespace RJW_Genes
{
base.PostMake();
+ // If the Pawn is already a Futa, do not do anything. Can Happen by Base-RJW Spawn Chance or potentially races / other mods.
+ if (IsAlreadyFuta(pawn))
+ {
+ return;
+ }
+
if (GenderUtility.IsFemale(pawn) && additional_genital == null)
{
createAndAddPenis();
@@ -27,6 +33,12 @@ namespace RJW_Genes
{
base.PostAdd();
+ // If the Pawn is already a Futa, do not do anything. Can Happen by Base-RJW Spawn Chance or potentially races / other mods.
+ if (IsAlreadyFuta(pawn))
+ {
+ return;
+ }
+
if (pawn.gender == Gender.Female && additional_genital == null)
{
createAndAddPenis();
@@ -79,5 +91,15 @@ namespace RJW_Genes
pawn.health.AddHediff(additional_genital, partBPR);
}
+ private static bool IsAlreadyFuta(Pawn pawn)
+ {
+ if (pawn == null)
+ return false;
+ if (!Genital_Helper.has_genitals(pawn))
+ return false;
+ return
+ (Genital_Helper.has_penis_fertile(pawn) || Genital_Helper.has_penis_infertile(pawn))
+ && Genital_Helper.has_vagina(pawn) ;
+ }
}
}
diff --git a/Source/Genes/GeneUtility.cs b/Source/Genes/GeneUtility.cs
index ce022ba..66cfd74 100644
--- a/Source/Genes/GeneUtility.cs
+++ b/Source/Genes/GeneUtility.cs
@@ -1,35 +1,68 @@
using System;
+using System.Collections.Generic;
using Verse;
-
+using RimWorld;
namespace RJW_Genes
{
public class GeneUtility
{
- public static bool IsMechbreeder(Pawn pawn)
+
+ //Split function so I can offsetlifeforce from gene without needing to look for the gene agian (for the constant drain tick)
+ public static Gene_LifeForce GetLifeForceGene(Pawn pawn)
{
- if (pawn.genes == null)
- {
- return false;
- }
- return pawn.genes.HasGene(GeneDefOf.rjw_genes_mechbreeder);
+ Pawn_GeneTracker genes = pawn.genes;
+ Gene_LifeForce gene_LifeForce = genes.GetFirstGeneOfType();
+ return gene_LifeForce;
}
- public static bool IsInsectIncubator(Pawn pawn)
- {
- if (pawn.genes == null)
- {
- return false;
- }
- return pawn.genes.HasGene(GeneDefOf.rjw_genes_insectincubator);
+ public static void OffsetLifeForce(IGeneResourceDrain drain, float offset)
+ {
+ float old_value = drain.Resource.Value;
+ drain.Resource.Value += offset;
+ PostOffSetLifeForce(drain, old_value);
}
- public static bool IsInsectBreeder(Pawn pawn)
+ public static void PostOffSetLifeForce(IGeneResourceDrain drain, float old_value)
{
- if (pawn.genes == null)
- {
- return false;
+ if (old_value > 0.2f && drain.Resource.Value <= 0.2f)
+ {
+ //TODO: Mood debuff
}
- return pawn.genes.HasGene(GeneDefOf.rjw_genes_insectbreeder);
+ else if (old_value > 0f && drain.Resource.Value <= 0f)
+ {
+ Pawn pawn = drain.Pawn;
+ if (!drain.Pawn.health.hediffSet.HasHediff(HediffDefOf.rjw_genes_fertilin_craving))
+ {
+ drain.Pawn.health.AddHediff(HediffDefOf.rjw_genes_fertilin_craving);
+ }
+ }
+ }
+
+
+ public static bool HasLowLifeForce(Pawn pawn)
+ {
+ if (HasLifeForce(pawn))
+ {
+ Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType();
+ if (gene.Resource.Value < gene.targetValue)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static bool HasCriticalLifeForce(Pawn pawn)
+ {
+ if (HasLifeForce(pawn))
+ {
+ Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType();
+ if (gene.Resource.Value < gene.MinLevelForAlert)
+ {
+ return true;
+ }
+ }
+ return false;
}
public static float MaxEggSizeMul(Pawn pawn)
@@ -41,31 +74,52 @@ namespace RJW_Genes
}
return MaxEggSize;
}
-
- internal static bool IsElastic(Pawn pawn)
+ public static List GetGenitaliaResizingGenes(Pawn pawn)
{
- if (pawn.genes == null)
- {
- return false;
- }
- return pawn.genes.HasGene(GeneDefOf.rjw_genes_elasticity);
+ var ResizingGenes = new List();
+
+ // Error Handling: Issue with Pawn or Genes return empty.
+ if (pawn == null || pawn.genes == null)
+ return ResizingGenes;
+
+ foreach (Gene gene in pawn.genes.GenesListForReading)
+ if (gene is Gene_GenitaliaResizingGene resizing_gene)
+ ResizingGenes.Add(resizing_gene);
+
+ return ResizingGenes;
}
- public static bool IsCumflationImmune(Pawn pawn)
+ ///
+ /// Unified small check for a pawn if it has a specified Gene.
+ /// Handles some errors and returns false as default.
+ ///
+ /// The pawn for which to look up a gene.
+ /// The gene to look up.
+ ///
+ public static bool HasGeneNullCheck(Pawn pawn, GeneDef genedef)
{
if (pawn.genes == null)
{
return false;
}
- return pawn.genes.HasGene(GeneDefOf.rjw_genes_cumflation_immunity);
- }
- public static bool IsGenerousDonor(Pawn pawn)
- {
- if (pawn.genes == null)
- {
- return false;
- }
- return pawn.genes.HasGene(GeneDefOf.rjw_genes_generous_donor);
+ return pawn.genes.HasGene(genedef);
}
+
+ public static bool HasLifeForce(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_lifeforce); }
+ public static bool IsMechbreeder(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_mechbreeder); }
+ public static bool IsInsectIncubator(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_insectincubator); }
+ public static bool IsYouthFountain(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_youth_fountain); }
+ public static bool IsAgeDrainer(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_sex_age_drain); }
+ public static bool IsInsectBreeder(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_insectbreeder); }
+ public static bool IsElastic(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_elasticity); }
+ public static bool IsCumflationImmune(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_cumflation_immunity); }
+ public static bool IsGenerousDonor(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_generous_donor); }
+ public static bool IsPussyHealer(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_pussyhealing); }
+ public static bool IsUnbreakable(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_unbreakable); }
+ public static bool HasParalysingKiss(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_paralysingkiss); }
+ public static bool HasSeduce(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_seduce); }
+ public static bool IsSexualDrainer(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_drainer); }
+ public static bool IsCumEater(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_cum_eater); }
+
}
}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Gene_BigBreasts.cs b/Source/Genes/GenitaliaSize/Gene_BigBreasts.cs
index b0e61ad..b1c6e4f 100644
--- a/Source/Genes/GenitaliaSize/Gene_BigBreasts.cs
+++ b/Source/Genes/GenitaliaSize/Gene_BigBreasts.cs
@@ -1,24 +1,12 @@
using Verse;
namespace RJW_Genes
{
- public class Gene_BigBreasts : RJW_Gene
+ public class Gene_BigBreasts : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
- if (pawn.gender == Gender.Female)
- SizeAdjuster.AdjustAllBreastSizes(pawn,0.5f,1.0f);
- }
-
- public override void PostAdd()
- {
- base.PostAdd();
if (pawn.gender == Gender.Female)
SizeAdjuster.AdjustAllBreastSizes(pawn, 0.5f, 1.0f);
}
-
-
}
-}
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Gene_BigMaleGenitalia.cs b/Source/Genes/GenitaliaSize/Gene_BigMaleGenitalia.cs
index b04df46..8cee1ef 100644
--- a/Source/Genes/GenitaliaSize/Gene_BigMaleGenitalia.cs
+++ b/Source/Genes/GenitaliaSize/Gene_BigMaleGenitalia.cs
@@ -1,20 +1,10 @@
namespace RJW_Genes
{
- public class Gene_BigMaleGenitalia : RJW_Gene
+ public class Gene_BigMaleGenitalia : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
- SizeAdjuster.AdjustAllPenisSizes(pawn,0.5f,1.0f);
- }
-
- public override void PostAdd()
- {
- base.PostAdd();
SizeAdjuster.AdjustAllPenisSizes(pawn, 0.5f, 1.0f);
}
-
}
-}
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Gene_GenitaliaResizingGene.cs b/Source/Genes/GenitaliaSize/Gene_GenitaliaResizingGene.cs
new file mode 100644
index 0000000..ee24126
--- /dev/null
+++ b/Source/Genes/GenitaliaSize/Gene_GenitaliaResizingGene.cs
@@ -0,0 +1,49 @@
+namespace RJW_Genes
+{
+ ///
+ /// Parent Gene for Genitalia Resizing. All Resizing genes should inherit for this class.
+ ///
+ /// This helps with some functions (e.g. "hasGenitaliaResizingGenes(pawn)") but also to fire genitalia resizing later in life for Pawns.
+ /// (No Children with huge ding dongs, and I don't want kids with tight anuses I am not that degenerate)
+ ///
+ public abstract class Gene_GenitaliaResizingGene : RJW_Gene
+ {
+
+ public const int RESIZING_AGE = 20;
+ public bool WasApplied { get; set; }
+
+ public override void PostMake()
+ {
+ base.PostMake();
+ if (pawn.ageTracker.AgeBiologicalYears >= RESIZING_AGE)
+ {
+ Resize();
+ WasApplied = true;
+ }
+ }
+
+ public override void PostAdd()
+ {
+ base.PostAdd();
+ if (pawn.ageTracker.AgeBiologicalYears >= RESIZING_AGE)
+ {
+ Resize();
+ WasApplied = true;
+ }
+ }
+
+ ///
+ /// Used to resize the pawns genitalia.
+ /// All Logic should be put here:
+ /// 1. Filters for Gender
+ /// 2. Filters for Genitalia Existance
+ /// 3. Selection of right Genitalia
+ /// 4. Adjustment of Size
+ ///
+ /// I kept it intentionally broad, so that e.g. the Penis Resize can resize multiple penises and also for futas,
+ /// while the breast-gene is female only.
+ ///
+ public abstract void Resize();
+
+ }
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Gene_LooseAnus.cs b/Source/Genes/GenitaliaSize/Gene_LooseAnus.cs
index f5a5312..520eb5a 100644
--- a/Source/Genes/GenitaliaSize/Gene_LooseAnus.cs
+++ b/Source/Genes/GenitaliaSize/Gene_LooseAnus.cs
@@ -1,22 +1,12 @@
-namespace RJW_Genes
+using Verse;
+
+namespace RJW_Genes
{
- public class Gene_LooseAnus : RJW_Gene
+ public class Gene_LooseAnus : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
SizeAdjuster.AdjustAllAnusSizes(pawn, 0.5f, 1.0f);
}
-
- public override void PostAdd()
- {
- base.PostAdd();
- SizeAdjuster.AdjustAllAnusSizes(pawn, 0.5f, 1.0f);
- }
-
-
-
}
}
diff --git a/Source/Genes/GenitaliaSize/Gene_LooseFemaleGenitalia.cs b/Source/Genes/GenitaliaSize/Gene_LooseFemaleGenitalia.cs
index 68578b6..2885c07 100644
--- a/Source/Genes/GenitaliaSize/Gene_LooseFemaleGenitalia.cs
+++ b/Source/Genes/GenitaliaSize/Gene_LooseFemaleGenitalia.cs
@@ -1,22 +1,12 @@
-namespace RJW_Genes
+using Verse;
+
+namespace RJW_Genes
{
- public class Gene_LooseFemaleGenitalia : RJW_Gene
+ public class Gene_LooseFemaleGenitalia : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
SizeAdjuster.AdjustAllVaginaSizes(pawn, 0.5f, 1.0f);
}
-
- public override void PostAdd()
- {
- base.PostAdd();
- SizeAdjuster.AdjustAllVaginaSizes(pawn, 0.5f, 1.0f);
- }
-
-
-
}
}
diff --git a/Source/Genes/GenitaliaSize/Gene_SmallBreasts.cs b/Source/Genes/GenitaliaSize/Gene_SmallBreasts.cs
index d5b4a4e..2e8af43 100644
--- a/Source/Genes/GenitaliaSize/Gene_SmallBreasts.cs
+++ b/Source/Genes/GenitaliaSize/Gene_SmallBreasts.cs
@@ -1,18 +1,11 @@
-namespace RJW_Genes
+using Verse;
+
+namespace RJW_Genes
{
- public class Gene_SmallBreasts : RJW_Gene
+ public class Gene_SmallBreasts : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
- SizeAdjuster.AdjustAllBreastSizes(pawn, 0.0f, 0.5f);
- }
-
- public override void PostAdd()
- {
- base.PostAdd();
SizeAdjuster.AdjustAllBreastSizes(pawn, 0.0f, 0.5f);
}
}
diff --git a/Source/Genes/GenitaliaSize/Gene_SmallMaleGenitalia.cs b/Source/Genes/GenitaliaSize/Gene_SmallMaleGenitalia.cs
index 12ba154..ce5d33a 100644
--- a/Source/Genes/GenitaliaSize/Gene_SmallMaleGenitalia.cs
+++ b/Source/Genes/GenitaliaSize/Gene_SmallMaleGenitalia.cs
@@ -1,20 +1,10 @@
namespace RJW_Genes
{
- public class Gene_SmallMaleGenitalia : RJW_Gene
+ public class Gene_SmallMaleGenitalia : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
- SizeAdjuster.AdjustAllPenisSizes(pawn,0.0f,0.5f);
- }
-
- public override void PostAdd()
- {
- base.PostAdd();
SizeAdjuster.AdjustAllPenisSizes(pawn, 0.0f, 0.5f);
}
-
}
-}
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Gene_TightAnus.cs b/Source/Genes/GenitaliaSize/Gene_TightAnus.cs
index 56f52cd..443aba7 100644
--- a/Source/Genes/GenitaliaSize/Gene_TightAnus.cs
+++ b/Source/Genes/GenitaliaSize/Gene_TightAnus.cs
@@ -1,21 +1,10 @@
namespace RJW_Genes
{
- public class Gene_TightAnus : RJW_Gene
+ public class Gene_TightAnus : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
SizeAdjuster.AdjustAllAnusSizes(pawn, 0.0f, 0.5f);
}
-
- public override void PostAdd()
- {
- base.PostAdd();
- SizeAdjuster.AdjustAllAnusSizes(pawn, 0.0f, 0.5f);
- }
-
-
}
-}
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Gene_TightFemaleGenitalia.cs b/Source/Genes/GenitaliaSize/Gene_TightFemaleGenitalia.cs
index 53ec2a7..306635d 100644
--- a/Source/Genes/GenitaliaSize/Gene_TightFemaleGenitalia.cs
+++ b/Source/Genes/GenitaliaSize/Gene_TightFemaleGenitalia.cs
@@ -1,20 +1,10 @@
namespace RJW_Genes
{
- public class Gene_TightFemaleGenitalia : RJW_Gene
+ public class Gene_TightFemaleGenitalia : Gene_GenitaliaResizingGene
{
-
- public override void PostMake()
+ public override void Resize()
{
- base.PostMake();
-
SizeAdjuster.AdjustAllVaginaSizes(pawn, 0.0f, 0.5f);
}
-
- public override void PostAdd()
- {
- base.PostAdd();
- SizeAdjuster.AdjustAllVaginaSizes(pawn, 0.0f, 0.5f);
- }
-
}
-}
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/Patch_ResizingOnAdulthood.cs b/Source/Genes/GenitaliaSize/Patch_ResizingOnAdulthood.cs
new file mode 100644
index 0000000..b8542a0
--- /dev/null
+++ b/Source/Genes/GenitaliaSize/Patch_ResizingOnAdulthood.cs
@@ -0,0 +1,30 @@
+using HarmonyLib;
+using Verse;
+
+namespace RJW_Genes
+{
+ ///
+ /// This Patch adds behavior to all resizing genes:
+ /// At Age RESIZING_MIN_AGE the Pawns Resizing Genes will trigger again, if not already triggered somewhere else.
+ /// This is meant to allow kids to grow up without resized genitals, and resize later (Fixing #11).
+ ///
+ [HarmonyPatch(typeof(Pawn_AgeTracker), "BirthdayBiological")]
+ public class Patch_ResizingOnAdulthood
+ {
+
+ static void Postfix(Pawn ___pawn, int birthdayAge)
+ {
+ if (birthdayAge >= Gene_GenitaliaResizingGene.RESIZING_AGE)
+ {
+ foreach(Gene_GenitaliaResizingGene gene in GeneUtility.GetGenitaliaResizingGenes(___pawn))
+ {
+ if (!gene.WasApplied)
+ {
+ gene.Resize();
+ gene.WasApplied = true;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Genes/GenitaliaSize/SizeAdjuster.cs b/Source/Genes/GenitaliaSize/SizeAdjuster.cs
index e87f490..6a67dcd 100644
--- a/Source/Genes/GenitaliaSize/SizeAdjuster.cs
+++ b/Source/Genes/GenitaliaSize/SizeAdjuster.cs
@@ -58,7 +58,7 @@ namespace RJW_Genes
public static void AdjustAllBreastSizes(Pawn pawn, float lowerLimit = 0.0f, float upperLimit = 1.0f)
{
- List AllBreasts = Genital_Helper.get_AllPartsHediffList(pawn).FindAll(x => x.def.defName.Contains("breasts"));
+ List AllBreasts = Genital_Helper.get_AllPartsHediffList(pawn).FindAll(x => x.def.defName.ToLower().Contains("breasts"));
ResizeAll(AllBreasts,lowerLimit,upperLimit);
}
diff --git a/Source/Genes/Life_Force/Abilities/AbilityUtility.cs b/Source/Genes/Life_Force/Abilities/AbilityUtility.cs
new file mode 100644
index 0000000..77fba03
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/AbilityUtility.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse.Sound;
+using Verse;
+using RimWorld;
+using rjw;
+using rjw.Modules.Interactions.Helpers;
+using rjw.Modules.Interactions.Enums;
+
+namespace RJW_Genes
+{
+ public class AbilityUtility
+ {
+ public static void PussyHeal(SexProps props)
+ {
+ if (InteractionHelper.GetWithExtension(props.dictionaryKey).DominantHasFamily(GenitalFamily.Vagina) || InteractionHelper.GetWithExtension(props.dictionaryKey).SubmissiveHasFamily(GenitalFamily.Vagina))
+ {
+ Pawn pawn = props.pawn;
+ Pawn partner = props.partner;
+ FloatRange tendQualityRange;
+ tendQualityRange.min = 0.4f;
+ tendQualityRange.max = 0.8f;
+ if (GeneUtility.IsPussyHealer(pawn))
+ {
+ Heal(partner, tendQualityRange);
+ }
+ if (GeneUtility.IsPussyHealer(partner))
+ {
+ Heal(pawn, tendQualityRange);
+ }
+ }
+ }
+
+ public static bool Heal(Pawn pawn, FloatRange tendQualityRange)
+ {
+ bool any_wound_tended = false;
+ List hediffs = pawn.health.hediffSet.hediffs;
+ for (int i = hediffs.Count - 1; i >= 0; i--)
+ {
+ if ((hediffs[i] is Hediff_Injury || hediffs[i] is Hediff_MissingPart) && hediffs[i].TendableNow(false))
+ {
+ hediffs[i].Tended(tendQualityRange.RandomInRange, tendQualityRange.TrueMax, 1);
+ any_wound_tended = true;
+ }
+ }
+ return any_wound_tended;
+ }
+
+ public static float LifeForceCost(Ability ability)
+ {
+ if (ability.comps != null)
+ {
+ using (List.Enumerator enumerator = ability.comps.GetEnumerator())
+ {
+ while (enumerator.MoveNext())
+ {
+ CompAbilityEffect_LifeForceCost compAbilityEffect_HemogenCost;
+ if ((compAbilityEffect_HemogenCost = (enumerator.Current as CompAbilityEffect_LifeForceCost)) != null)
+ {
+ return compAbilityEffect_HemogenCost.Props.fertilinCost;
+ }
+ }
+ }
+ }
+ return 0f;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Genes/Life_Force/Abilities/CompAbilityEffect_CasterIsNaked.cs b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_CasterIsNaked.cs
new file mode 100644
index 0000000..aa1d61a
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_CasterIsNaked.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+using Verse.AI;
+using rjw;
+
+namespace RJW_Genes
+{
+ //Summary//
+ //Returns invalid if a pawn is not naked
+ //Summary//
+ public class CompAbilityEffect_CasterIsNaked : CompAbilityEffect_WithDest
+ {
+ private new CompProperties_CasterIsNaked Props
+ {
+ get
+ {
+ return (CompProperties_CasterIsNaked)this.props;
+ }
+ }
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ Pawn pawn = this.CasterPawn;
+ if (pawn != null)
+ {
+ //Copied from ThoughtWorker_NudistNude.CurrentStateInternal
+ List wornApparel = pawn.apparel.WornApparel;
+ for (int i = 0; i < wornApparel.Count; i++)
+ {
+ Apparel apparel = wornApparel[i];
+ if (apparel.def.apparel.countsAsClothingForNudity)
+ {
+ for (int j = 0; j < apparel.def.apparel.bodyPartGroups.Count; j++)
+ {
+ if (apparel.def.apparel.bodyPartGroups[j] == BodyPartGroupDefOf.Torso)
+ {
+ reason = pawn.Name + " is not naked";
+ return true;
+ }
+ if (apparel.def.apparel.bodyPartGroups[j] == BodyPartGroupDefOf.Legs)
+ {
+ reason = pawn.Name + " is not naked";
+ return true;
+
+ }
+ }
+ }
+ }
+ }
+ reason = null;
+ return false;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompAbilityEffect_CockEater.cs b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_CockEater.cs
new file mode 100644
index 0000000..dc0f0fa
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_CockEater.cs
@@ -0,0 +1,121 @@
+using Verse;
+using RimWorld;
+using rjw;
+
+namespace RJW_Genes
+{
+ ///
+ /// The CockEater Ability bites off the first found non-artifical cock of an target pawn.
+ /// It will restore {MINIMUM_LIFEFORCE_GAIN} multiplied by up to 2-times the Cock-Size.
+ /// Consuming a "towering" cock will give 2*{MINIMUM_LIFEFORCE_GAIN}, resulting in default 0.5f LifeForce.
+ /// This number is reduced for consuming animals by Settings.
+ ///
+ /// Balancing note: With the Cock-Eaters a drain of 0.08 is normal per day. This means 1 average cock should hold for 3-4 days of fertilin-fuel and half a day for an animal.
+ ///
+ public class CompAbilityEffect_CockEater : CompAbilityEffect
+ {
+ private new CompProperties_AbilityCockEater Props
+ {
+ get
+ {
+ return (CompProperties_AbilityCockEater)this.props;
+ }
+ }
+
+ public const float MINIMUM_LIFEFORCE_GAIN = 0.25f;
+
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+ Pawn CockBiter = this.parent.pawn;
+ Pawn CockBittenPawn = target.Pawn;
+ if (CockBittenPawn == null)
+ {
+ return;
+ }
+ var partBPR = Genital_Helper.get_genitalsBPR(CockBittenPawn);
+ var parts = Genital_Helper.get_PartsHediffList(CockBittenPawn, partBPR);
+ if (!parts.NullOrEmpty())
+ {
+ foreach (Hediff part in parts)
+ {
+ if (GenitaliaChanger.IsArtificial(part))
+ continue;
+
+ if (Genital_Helper.is_penis(part))
+ {
+ float gained_lifeforce = MINIMUM_LIFEFORCE_GAIN * (1 + part.Severity);
+ if (CockBittenPawn.IsAnimal())
+ {
+ gained_lifeforce *= RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor;
+ }
+ // Increase LifeForce for Biter
+ GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(CockBiter), gained_lifeforce);
+
+ // Handle Damage for Bitten
+ CockBittenPawn.health.RemoveHediff(part);
+ CockBittenPawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.rjw_genes_cock_eaten, CockBittenPawn, null);
+
+ //Only one penis at the time
+ break;
+ }
+ }
+ }
+ }
+
+ ///
+ /// For validity, there are a few checks:
+ /// 1. Target has Penis
+ /// 2. Target is either Colonist / Prisoner
+ /// 3. If the Target is an enemy, it must be downed.
+ ///
+ public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
+ {
+ Pawn CockBiteTarget = target.Pawn;
+ if (CockBiteTarget != null)
+ {
+ bool CockBiteTargetIsColonistOrPrisoner = CockBiteTarget.Faction == this.parent.pawn.Faction || CockBiteTarget.IsPrisonerOfColony;
+ bool CockBiteTargetIsHostile = CockBiteTarget.HostileTo(this.parent.pawn);
+ bool CockBiteTargetIsDowned = CockBiteTarget.Downed;
+
+ if (!CockBiteTargetIsColonistOrPrisoner && !(CockBiteTargetIsHostile && CockBiteTargetIsDowned))
+ {
+ if (throwMessages)
+ {
+ if(CockBiteTargetIsHostile && !CockBiteTargetIsDowned)
+ {
+ Messages.Message(CockBiteTarget.Name + " is hostile, but not downed.", CockBiteTarget, MessageTypeDefOf.RejectInput, false);
+ }
+ else if (!CockBiteTargetIsColonistOrPrisoner)
+ {
+ Messages.Message(CockBiteTarget.Name + " is not a part of the colony or hostile.", CockBiteTarget, MessageTypeDefOf.RejectInput, false);
+ }
+ }
+ return false;
+ }
+ if (!Genital_Helper.has_penis_fertile(CockBiteTarget))
+ {
+ if (throwMessages)
+ {
+ Messages.Message(CockBiteTarget.Name + " has no penis", CockBiteTarget, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+ }
+ return base.Valid(target, throwMessages);
+ }
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ Pawn_GeneTracker genes = this.parent.pawn.genes;
+ Gene_LifeForce gene_LifeForce = (genes != null) ? genes.GetFirstGeneOfType() : null;
+ if (gene_LifeForce == null)
+ {
+ reason = "AbilityDisabledNoFertilinGene".Translate(this.parent.pawn);
+ return true;
+ }
+ reason = null;
+ return false;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompAbilityEffect_LifeForceCost.cs b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_LifeForceCost.cs
new file mode 100644
index 0000000..44aec81
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_LifeForceCost.cs
@@ -0,0 +1,107 @@
+using Verse;
+using Verse.AI;
+using RimWorld;
+namespace RJW_Genes
+{
+ public class CompAbilityEffect_LifeForceCost : CompAbilityEffect
+ {
+
+ public new CompProperties_AbilityLifeForceCost Props
+ {
+ get
+ {
+ return (CompProperties_AbilityLifeForceCost)this.props;
+ }
+ }
+
+ private bool HasEnoughFertilin
+ {
+ get
+ {
+ Pawn_GeneTracker genes = this.parent.pawn.genes;
+ Gene_LifeForce gene_lifeforce = (genes != null) ? genes.GetFirstGeneOfType < Gene_LifeForce>() : null;
+ return gene_lifeforce != null && gene_lifeforce.Value >= this.Props.fertilinCost;
+ }
+ }
+
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+ GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(this.parent.pawn), -this.Props.fertilinCost);
+ }
+
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ Pawn_GeneTracker genes = this.parent.pawn.genes;
+ Gene_LifeForce gene_LifeForce = (genes != null) ? genes.GetFirstGeneOfType() : null;
+ if (gene_LifeForce == null)
+ {
+ reason = "AbilityDisabledNoFertilinGene".Translate(this.parent.pawn);
+ return true;
+ }
+ if (gene_LifeForce.Value < this.Props.fertilinCost)
+ {
+ reason = "AbilityDisabledNoFertilin".Translate(this.parent.pawn);
+ return true;
+ }
+ float num = this.TotalLifeForceCostOfQueuedAbilities();
+ float num2 = this.Props.fertilinCost + num;
+ if (this.Props.fertilinCost > 1E-45f && num2 > gene_LifeForce.Value)
+ {
+ reason = "AbilityDisabledNoFertilin".Translate(this.parent.pawn);
+ return true;
+ }
+ reason = null;
+ return false;
+ }
+
+ public override bool AICanTargetNow(LocalTargetInfo target)
+ {
+ return this.HasEnoughFertilin;
+ }
+
+ private float TotalLifeForceCostOfQueuedAbilities()
+ {
+ Pawn_JobTracker jobs = this.parent.pawn.jobs;
+ object obj;
+ if (jobs == null)
+ {
+ obj = null;
+ }
+ else
+ {
+ Job curJob = jobs.curJob;
+ obj = ((curJob != null) ? curJob.verbToUse : null);
+ }
+ Verb_CastAbility verb_CastAbility = obj as Verb_CastAbility;
+ float num;
+ if (verb_CastAbility == null)
+ {
+ num = 0f;
+ }
+ else
+ {
+ Ability ability = verb_CastAbility.ability;
+ num = ((ability != null) ? AbilityUtility.LifeForceCost(ability) : 0f);
+ }
+ float num2 = num;
+ if (this.parent.pawn.jobs != null)
+ {
+ for (int i = 0; i < this.parent.pawn.jobs.jobQueue.Count; i++)
+ {
+ Verb_CastAbility verb_CastAbility2;
+ if ((verb_CastAbility2 = (this.parent.pawn.jobs.jobQueue[i].job.verbToUse as Verb_CastAbility)) != null)
+ {
+ float num3 = num2;
+ Ability ability2 = verb_CastAbility2.ability;
+ num2 = num3 + ((ability2 != null) ? AbilityUtility.LifeForceCost(ability2) : 0f);
+ }
+ }
+ }
+ return num2;
+ }
+
+
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompAbilityEffect_PussyHeal.cs b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_PussyHeal.cs
new file mode 100644
index 0000000..fdb0c7c
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_PussyHeal.cs
@@ -0,0 +1,95 @@
+using System.Collections.Generic;
+using Verse;
+using RimWorld;
+using rjw;
+
+namespace RJW_Genes
+{
+ public class CompAbilityEffect_PussyHeal : CompAbilityEffect
+ {
+ private new CompProperties_AbilityPussyHeal Props
+ {
+ get
+ {
+ return (CompProperties_AbilityPussyHeal)this.props;
+ }
+ }
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+ Pawn pawn = target.Pawn;
+ if (pawn == null)
+ {
+ return;
+ }
+ bool any_wound_tended = AbilityUtility.Heal(pawn, this.Props.tendQualityRange);
+ if (any_wound_tended)
+ {
+ MoteMaker.ThrowText(pawn.DrawPos, pawn.Map, "Sex tended wounds", 3.65f);
+ }
+ }
+
+ //Not yet implemented, but the heal should also trigger after normal sex
+ public void AfterSex(Pawn pawn, Pawn target)
+ {
+ List hediffs = target.health.hediffSet.hediffs;
+ for (int i = 0; i < hediffs.Count; i++)
+ {
+ if ((hediffs[i] is Hediff_Injury || hediffs[i] is Hediff_MissingPart) && hediffs[i].TendableNow(false))
+ {
+ //target.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.Pussy_Healed, pawn, null);
+ break;
+ }
+ }
+ //InteractionHelper.GetWithExtension(dictionaryKey).DominantHasTag("CanBePenetrated")
+
+
+ }
+
+ public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
+ {
+ Pawn pawn = target.Pawn;
+ if (pawn != null)
+ {
+ //to be replaced with severel checks to make it clear why target is unable to have sex
+ if (!CasualSex_Helper.CanHaveSex(pawn))
+ {
+ if (throwMessages)
+ {
+ Messages.Message(pawn.Name + " is unable to have sex", pawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+ else if (pawn.IsAnimal() && !RJWSettings.bestiality_enabled)
+ {
+ if (throwMessages)
+ {
+ Messages.Message("bestiality is disabled", pawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+ //TODO: Only make pawns targetable that have tendable wounds
+
+ }
+ return base.Valid(target, throwMessages);
+ }
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ reason = null;
+ if (!Genital_Helper.has_vagina(this.parent.pawn))
+ {
+ reason = this.parent.pawn.Name + " has no vagina to use.";
+ return true;
+ }
+ else if (!RJWSettings.rape_enabled)
+ {
+ reason = "Rape is disabled";
+ return true;
+ }
+ return false;
+ }
+
+
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompAbilityEffect_Seduce.cs b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_Seduce.cs
new file mode 100644
index 0000000..b8819a8
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompAbilityEffect_Seduce.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+using Verse.AI;
+using rjw;
+
+namespace RJW_Genes
+{
+ public class CompAbilityEffect_Seduce : CompAbilityEffect_WithDest
+ {
+ private new CompProperties_Seduce Props
+ {
+ get
+ {
+ return (CompProperties_Seduce)this.props;
+ }
+ }
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+ Pawn pawn = target.Thing as Pawn;
+ Pawn pawn2 = this.parent.pawn;
+ if (pawn != null && pawn2 != null && !pawn.Downed)
+ {
+ Job job = JobMaker.MakeJob(JobDefOf.rjw_genes_lifeforce_seduced, pawn2);
+ job.mote = MoteMaker.MakeThoughtBubble(pawn, this.parent.def.iconPath, true);
+ pawn.jobs.StopAll(false, true);
+ pawn.jobs.StartJob(job, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
+ }
+ }
+
+ public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
+ {
+
+ Pawn pawn = target.Pawn;
+ if (pawn != null)
+ {
+ if (!xxx.can_be_fucked(pawn))
+ {
+ if (throwMessages)
+ {
+ Messages.Message(pawn.Name + " is unable to have sex", pawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+ else if (pawn.IsAnimal() && !RJWSettings.bestiality_enabled)
+ {
+ if (throwMessages)
+ {
+ Messages.Message("bestiality is disabled", pawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+ else if (GeneUtility.HasSeduce(pawn))
+ {
+ if (throwMessages)
+ {
+ Messages.Message(pawn.Name + " cannot be seduced, as they also have the Seduce-Ability", pawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+ else if (pawn.Downed)
+ {
+ if (throwMessages)
+ {
+ Messages.Message(pawn.Name + " is unable to move", pawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+
+ }
+ return base.Valid(target, throwMessages);
+ }
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ reason = null;
+ if (!RJWSettings.rape_enabled)
+ {
+ reason = "Rape is disabled";
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompProperties_AbilityCockEater.cs b/Source/Genes/Life_Force/Abilities/CompProperties_AbilityCockEater.cs
new file mode 100644
index 0000000..b64b346
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompProperties_AbilityCockEater.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class CompProperties_AbilityCockEater : CompProperties_AbilityEffect
+ {
+ public CompProperties_AbilityCockEater()
+ {
+ this.compClass = typeof(CompAbilityEffect_CockEater);
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompProperties_AbilityLifeForceCost.cs b/Source/Genes/Life_Force/Abilities/CompProperties_AbilityLifeForceCost.cs
new file mode 100644
index 0000000..5a05d5f
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompProperties_AbilityLifeForceCost.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ // Token: 0x02000F65 RID: 3941
+ public class CompProperties_AbilityLifeForceCost : CompProperties_AbilityEffect
+ {
+ // Token: 0x06005D16 RID: 23830 RVA: 0x001FA73F File Offset: 0x001F893F
+ public CompProperties_AbilityLifeForceCost()
+ {
+ this.compClass = typeof(CompAbilityEffect_LifeForceCost);
+ }
+
+ // Token: 0x06005D17 RID: 23831 RVA: 0x001FA757 File Offset: 0x001F8957
+ public override IEnumerable ExtraStatSummary()
+ {
+ yield return "AbilityFertilinCost" + ": " + Mathf.RoundToInt(this.fertilinCost * 100f);
+ yield break;
+ }
+
+ // Token: 0x040038CD RID: 14541
+ public float fertilinCost;
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompProperties_AbilityPussyHeal.cs b/Source/Genes/Life_Force/Abilities/CompProperties_AbilityPussyHeal.cs
new file mode 100644
index 0000000..16ba74d
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompProperties_AbilityPussyHeal.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class CompProperties_AbilityPussyHeal : CompProperties_AbilityEffect
+ {
+ public CompProperties_AbilityPussyHeal()
+ {
+ this.compClass = typeof(CompAbilityEffect_PussyHeal);
+ }
+
+ public FloatRange tendQualityRange;
+ }
+}
diff --git a/Source/Genes/Life_Force/Abilities/CompProperties_CasterIsNaked.cs b/Source/Genes/Life_Force/Abilities/CompProperties_CasterIsNaked.cs
new file mode 100644
index 0000000..8cb300e
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompProperties_CasterIsNaked.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class CompProperties_CasterIsNaked : CompProperties_EffectWithDest
+ {
+ public CompProperties_CasterIsNaked()
+ {
+ this.compClass = typeof(CompAbilityEffect_CasterIsNaked);
+ }
+ }
+}
+
diff --git a/Source/Genes/Life_Force/Abilities/CompProperties_Seduce.cs b/Source/Genes/Life_Force/Abilities/CompProperties_Seduce.cs
new file mode 100644
index 0000000..21e0cde
--- /dev/null
+++ b/Source/Genes/Life_Force/Abilities/CompProperties_Seduce.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class CompProperties_Seduce : CompProperties_EffectWithDest
+ {
+ public CompProperties_Seduce()
+ {
+ this.compClass = typeof(CompAbilityEffect_Seduce);
+ }
+
+ public StatDef durationMultiplier;
+ }
+}
+
diff --git a/Source/Genes/Life_Force/Events/SuccubusVisit/IncidentWorker_SuccubusDreamVisit.cs b/Source/Genes/Life_Force/Events/SuccubusVisit/IncidentWorker_SuccubusDreamVisit.cs
new file mode 100644
index 0000000..7948e37
--- /dev/null
+++ b/Source/Genes/Life_Force/Events/SuccubusVisit/IncidentWorker_SuccubusDreamVisit.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using Verse.AI;
+using Verse.AI.Group;
+using RimWorld;
+using rjw;
+namespace RJW_Genes
+{
+ public class IncidentWorker_SuccubusDreamVisit : IncidentWorker
+ {
+ //This incidint will only fire if there is a pawn asleep and sexneed is lower than 0.25
+ protected override bool CanFireNowSub(IncidentParms parms)
+ {
+ if (!base.CanFireNowSub(parms))
+ {
+ return false;
+ }
+ Map map = (Map)parms.target;
+ if (!map.mapTemperature.SeasonAcceptableFor(ThingDefOf.Human))
+ {
+ return false;
+ }
+ if (!RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi && !RJW_Genes_Settings.rjw_genes_sexdemon_visit_succubi)
+ {
+ return false;
+ }
+
+ foreach (Pawn pawn in map.mapPawns.FreeColonistsAndPrisonersSpawned)
+ {
+ if (pawn.jobs.curDriver.asleep && xxx.need_some_sex(pawn) > 1f)
+ {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ protected override bool TryExecuteWorker(IncidentParms parms)
+ {
+ Map map = (Map)parms.target;
+ List < Pawn > victims = ValidVictims(map).ToList();
+ if(victims.NullOrEmpty())
+ {
+ return false;
+ }
+ Faction faction;
+ if (!this.TryFindFormerFaction(out faction))
+ {
+ return false;
+ }
+ int pawn_amount = RJW_Genes_Settings.rjw_genes_sexdemon_visit_groups ? Rand.Range(1, victims.Count) : 1;
+ List new_sexdemons = new List();
+ for (int i = 0; i < pawn_amount; i++)
+ {
+ Pawn victim = victims.RandomElement();
+ IntVec3 loc = victim.Position;
+
+ PawnKindDef pawnKindDef;
+ Gender gender;
+ if (victim.gender == Gender.Male || !RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi)
+ {
+
+ }
+ if ((Rand.Bool && RJW_Genes_Settings.rjw_genes_sexdemon_visit_succubi) || !RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi)
+ {
+ pawnKindDef = PawnKindDef.Named("rjw_genes_succubus");
+ gender = Gender.Female;
+ }
+ else
+ {
+ pawnKindDef = PawnKindDef.Named("rjw_genes_incubus");
+ gender = Gender.Male;
+ }
+
+ //Spawn succubus at pawn
+ Pawn sexdemon = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnKindDef, faction, PawnGenerationContext.NonPlayer, -1,
+ false, false, false, true, false, 1f, false, true, false, true, true, false, false, false, false, 0f, 0f, null, 1f, null, null,
+ null, null, null, null, null, gender, null, null, null, null, false, false, false, false, null, null, null, null, null, 0f,
+ DevelopmentalStage.Adult, null, null, null, false));
+ sexdemon.SetFaction(null, null);
+ GenSpawn.Spawn(sexdemon, loc, map, WipeMode.Vanish);
+ List sexdemons = new List { sexdemon };
+ new_sexdemons.Add(sexdemon);
+
+
+ LordMaker.MakeNewLord(Faction.OfPlayer, this.CreateLordJob(parms, sexdemon, victim), map, sexdemons);
+
+ //Make succubus rape victim.
+ if (RJWSettings.rape_enabled)
+ {
+ //follow rjw rules
+ if (SexAppraiser.would_fuck(sexdemon,victim) > 0f)
+ {
+ sexdemon.pather.StopDead();
+ sexdemon.jobs.StopAll();
+ Job newJob = JobMaker.MakeJob(xxx.RapeRandom, victim);
+ sexdemon.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
+ }
+
+ }
+ }
+ Find.LetterStack.ReceiveLetter("rjw_genes_sexdemon_visit_incident_label".Translate(), "rjw_genes_sexdemon_visit_incident_description".Translate(), LetterDefOf.PositiveEvent, new_sexdemons, null, null, null, null);
+ //base.SendStandardLetter(baseLetterLabel, baseLetterText, this.def.letterDef, parms, succubus, Array.Empty());
+
+ return true;
+ }
+
+ private IEnumerable ValidVictims(Map map)
+ {
+ foreach (Pawn pawn in map.mapPawns.FreeColonistsAndPrisonersSpawned)
+ {
+ if (pawn.jobs.curDriver.asleep && xxx.need_some_sex(pawn) > 1f)
+ {
+ yield return pawn;
+ }
+ }
+ yield break;
+ }
+
+ private bool TryFindFormerFaction(out Faction formerFaction)
+ {
+ return Find.FactionManager.TryGetRandomNonColonyHumanlikeFaction(out formerFaction, false, true, TechLevel.Undefined, false);
+ }
+
+ protected virtual LordJob_SuccubusVisit CreateLordJob(IncidentParms parms, Pawn succubus, Pawn target)
+ {
+ return new LordJob_SuccubusVisit(target);
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs b/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs
new file mode 100644
index 0000000..f2e9a99
--- /dev/null
+++ b/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI.Group;
+using RimWorld;
+using rjw;
+namespace RJW_Genes
+{
+ //Based on LordJob_VisitColony
+ public class LordJob_SuccubusVisit : LordJob
+ {
+ public LordJob_SuccubusVisit(){}
+ public LordJob_SuccubusVisit(Pawn target)
+ {
+ this.target = target;
+ }
+
+ //
+ //Stategraph has lordtoils which say what a pawn should be doing
+ //Transitions say when active lordtoil for pawn should change
+ //
+ public override StateGraph CreateGraph()
+ {
+ StateGraph stateGraph = new StateGraph();
+
+ //Flirt
+ LordToil_Flirt lordToil_Flirt = new LordToil_Flirt(this.target, 7f);
+ stateGraph.AddToil(lordToil_Flirt);
+ stateGraph.StartingToil = lordToil_Flirt;
+
+ //Leave
+ LordToil_ExitMapRandom lordToil_ExitMapRandom = new LordToil_ExitMapRandom();
+ stateGraph.AddToil(lordToil_ExitMapRandom);
+ LordToil_ExitMapAndDefendSelf lordToil_ExitMapAndDefendSelf = new LordToil_ExitMapAndDefendSelf();
+ stateGraph.AddToil(lordToil_ExitMapAndDefendSelf);
+
+ //Leave after some time
+ Transition transition1 = new Transition(lordToil_Flirt, lordToil_ExitMapRandom, false, true);
+ int tickLimit;
+ if (this.durationTicks != null)
+ {
+ tickLimit = this.durationTicks.Value;
+ }
+ else
+ {
+ tickLimit = Rand.Range(60000, 180000); //~1-3 days
+ }
+ transition1.AddTrigger(new Trigger_TicksPassed(tickLimit));
+ transition1.AddPreAction(new TransitionAction_Custom(new Action(this.SuccubiLeave))); //Join or leave colony
+ stateGraph.AddTransition(transition1);
+
+ //If they become hostile
+ Transition transition3 = new Transition(lordToil_Flirt, lordToil_ExitMapAndDefendSelf, false, true);
+ transition3.AddSource(lordToil_ExitMapRandom); //Not sure what this does
+ transition3.AddTrigger(new Trigger_BecamePlayerEnemy());
+ transition3.AddTrigger(new Trigger_PawnKilled());
+ transition3.AddPostAction(new TransitionAction_EndAllJobs());
+ stateGraph.AddTransition(transition3, false);
+
+ Transition transition4 = new Transition(lordToil_ExitMapRandom, lordToil_ExitMapAndDefendSelf, false, true);
+ transition4.AddSource(lordToil_Flirt); //Not sure what this does
+ transition4.AddTrigger(new Trigger_PawnHarmed(1f, true, Faction.OfPlayer));
+ stateGraph.AddTransition(transition4, false);
+
+ return stateGraph;
+ }
+
+ //add toggleable gizmo to allow playes to have colonists sex the succubus into joining your colony
+ //comfort pawn? cooldown?
+ public override IEnumerable GetPawnGizmos(Pawn p)
+ {
+ return base.GetPawnGizmos(p);
+ }
+
+ public override void ExposeData()
+ {
+ Scribe_Values.Look(ref this.durationTicks, "durationTicks", null, false);
+ Scribe_References.Look(ref this.target, "target", false);
+ }
+
+ public void SuccubiLeave()
+ {
+ foreach (Pawn pawn in this.lord.ownedPawns)
+ {
+ if(colonyJoiners.Contains(pawn))
+ {
+ RecruitUtility.Recruit(pawn, Faction.OfPlayer);
+ Find.LetterStack.ReceiveLetter("Guest Joins", string.Format("{0} enjoys it here and has decided to stay", xxx.get_pawnname(pawn)), LetterDefOf.PositiveEvent, pawn, null, null, null, null);
+ }
+ else
+ {
+ Messages.Message("SuccubusLeaving".Translate(xxx.get_pawnname(pawn)), pawn, MessageTypeDefOf.NeutralEvent, true);
+ }
+ }
+
+ }
+
+ public Pawn target;
+ private int? durationTicks;
+ public List colonyJoiners = new List();
+ }
+}
diff --git a/Source/Genes/Life_Force/Genes/Gene_LifeForce.cs b/Source/Genes/Life_Force/Genes/Gene_LifeForce.cs
new file mode 100644
index 0000000..8cac6b3
--- /dev/null
+++ b/Source/Genes/Life_Force/Genes/Gene_LifeForce.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+using RimWorld;
+using rjw;
+
+namespace RJW_Genes
+{
+ public class Gene_LifeForce : Gene_Resource, IGeneResourceDrain
+ {
+ //Gene should only be active if sex is allowed for this pawn
+ public override bool Active
+ {
+ get
+ {
+ if (this.Overridden)
+ {
+ return false;
+ }
+ Pawn pawn = this.pawn;
+
+ return ((pawn != null) ? pawn.ageTracker : null) == null ||
+ ((float)this.pawn.ageTracker.AgeBiologicalYears >= this.def.minAgeActive);
+ }
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref this.StoredCumAllowed, "StoredCumAllowed", true, false);
+ }
+
+ public bool ShouldConsumeLifeForceNow()
+ {
+ return this.Value < this.targetValue;
+ }
+
+ //Same as Gene_Hemogen
+ public override IEnumerable GetGizmos()
+ {
+ foreach (Gizmo gizmo in base.GetGizmos())
+ {
+ yield return gizmo;
+ }
+ yield break;
+ }
+
+ //every tick it decreases fertilin value and everyday if fertilin is below alert minimum there a ~50 chance for mental break
+ public override void Tick()
+ {
+ base.Tick();
+ if (this.CanOffset && this.Resource != null)
+ {
+ GeneUtility.OffsetLifeForce(this, -this.ResourceLossPerDay / 60000f);
+
+ }
+
+ }
+
+ public bool StoredCumAllowed = true;
+ public Gene_Resource Resource
+ {
+ get
+ {
+ return this;
+ }
+ }
+ public Pawn Pawn
+ {
+ get
+ {
+ return this.pawn;
+ }
+ }
+ public bool CanOffset
+ {
+ get
+ {
+ return this.pawn.Spawned && this.Active;
+ }
+ }
+
+ public float ResourceLossPerDay
+ {
+ get
+ {
+ return this.def.resourceLossPerDay;
+ }
+ }
+
+ public string DisplayLabel
+ {
+ get
+ {
+ return this.def.resourceLabel;
+ }
+ }
+
+ public override float InitialResourceMax
+ {
+ get
+ {
+ return 1f;
+ }
+ }
+
+ public override float MinLevelForAlert
+ {
+ get
+ {
+ return 0.2f;
+ }
+ }
+ public override float MaxLevelOffset
+ {
+ get
+ {
+ return base.MaxLevelOffset;
+ }
+ }
+ protected override Color BarColor
+ {
+ get
+ {
+ return Color.grey;
+ }
+ }
+ protected override Color BarHighlightColor
+ {
+ get
+ {
+ return Color.white;
+ }
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Genes/Gene_LifeForceDrain.cs b/Source/Genes/Life_Force/Genes/Gene_LifeForceDrain.cs
new file mode 100644
index 0000000..c50dae5
--- /dev/null
+++ b/Source/Genes/Life_Force/Genes/Gene_LifeForceDrain.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class Gene_LifeForceDrain : Gene, IGeneResourceDrain
+ {
+ public Gene_Resource Resource
+ {
+ get
+ {
+ if (this.cachedLifeForceGene == null || !this.cachedLifeForceGene.Active)
+ {
+ this.cachedLifeForceGene = this.pawn.genes.GetFirstGeneOfType();
+ }
+ return this.cachedLifeForceGene;
+ }
+ }
+
+ public bool CanOffset
+ {
+ get
+ {
+ return this.Active && this.Resource != null && this.Resource.Active;
+ }
+ }
+
+ public float ResourceLossPerDay
+ {
+ get
+ {
+ return this.def.resourceLossPerDay;
+ }
+ }
+
+ public Pawn Pawn
+ {
+ get
+ {
+ return this.pawn;
+ }
+ }
+
+ public string DisplayLabel
+ {
+ get
+ {
+ return this.Label + " (" + "Gene".Translate() + ")";
+ }
+ }
+
+ public override void Tick()
+ {
+ base.Tick();
+ if (this.CanOffset && this.Resource != null)
+ {
+ GeneUtility.OffsetLifeForce(this, -this.ResourceLossPerDay / 60000);
+ }
+ }
+
+ [Unsaved(false)]
+ private Gene_LifeForce cachedLifeForceGene;
+
+ private const float MinAgeForDrain = 3f;
+ }
+}
diff --git a/Source/Genes/Life_Force/HediffCompProperties_SeverityFromFertilin.cs b/Source/Genes/Life_Force/HediffCompProperties_SeverityFromFertilin.cs
new file mode 100644
index 0000000..558c3e0
--- /dev/null
+++ b/Source/Genes/Life_Force/HediffCompProperties_SeverityFromFertilin.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+namespace RJW_Genes
+{
+ public class HediffCompProperties_SeverityFromFertilin : HediffCompProperties
+ {
+ public HediffCompProperties_SeverityFromFertilin()
+ {
+ this.compClass = typeof(HediffComp_SeverityFromFertilin);
+ }
+
+ // Token: 0x04001162 RID: 4450
+ public float severityPerHourEmpty;
+
+ // Token: 0x04001163 RID: 4451
+ public float severityPerHourHemogen;
+ }
+}
diff --git a/Source/Genes/Life_Force/HediffComp_SeverityFromFertilin.cs b/Source/Genes/Life_Force/HediffComp_SeverityFromFertilin.cs
new file mode 100644
index 0000000..4b8b3a7
--- /dev/null
+++ b/Source/Genes/Life_Force/HediffComp_SeverityFromFertilin.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+namespace RJW_Genes
+{
+ public class HediffComp_SeverityFromFertilin : HediffComp
+ {
+ public HediffCompProperties_SeverityFromFertilin Props
+ {
+ get
+ {
+ return (HediffCompProperties_SeverityFromFertilin)this.props;
+ }
+ }
+ public override bool CompShouldRemove
+ {
+ get
+ {
+ Pawn_GeneTracker genes = base.Pawn.genes;
+ return ((genes != null) ? genes.GetFirstGeneOfType() : null) == null;
+ }
+ }
+ private Gene_LifeForce LifeForce
+ {
+ get
+ {
+ if (this.cachedLifeForceGene == null)
+ {
+ this.cachedLifeForceGene = base.Pawn.genes.GetFirstGeneOfType();
+ }
+ return this.cachedLifeForceGene;
+ }
+ }
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ base.CompPostTick(ref severityAdjustment);
+ severityAdjustment += ((this.LifeForce.Value > 0f) ? this.Props.severityPerHourHemogen : this.Props.severityPerHourEmpty) / 2500f;
+ this.MentalBreak();
+ }
+
+ public void MentalBreak()
+ {
+ if (cachedLifeForceGene.Resource.Value <= cachedLifeForceGene.Resource.MinLevelForAlert && this.Pawn.IsHashIntervalTick(2500) && Rand.Chance(0.03f)) //~50% chance each day for mental break
+ {
+ if (this.Pawn.genes.HasGene(GeneDefOf.rjw_genes_cum_eater)
+ || this.Pawn.genes.HasGene(GeneDefOf.rjw_genes_fertilin_absorber) || this.Pawn.genes.HasGene(GeneDefOf.rjw_genes_drainer))
+ {
+ //TODO: use mentalstatedef instead of mentalbreakdef
+ MentalBreakDef randomrape = GeneDefOf.rjw_genes_lifeforce_randomrape;
+ if (ModsConfig.BiotechActive &&
+ this.Pawn.Spawned && !this.Pawn.InMentalState && !this.Pawn.Downed &&
+ randomrape.Worker.BreakCanOccur(this.Pawn))
+ {
+ randomrape.Worker.TryStart(this.Pawn, "MentalBreakNoFertilin".Translate(), false);
+ }
+ }
+ }
+ }
+
+ private Gene_LifeForce cachedLifeForceGene;
+ }
+}
diff --git a/Source/Genes/Life_Force/IngestionOutcomeDoer_LifeForceOffset.cs b/Source/Genes/Life_Force/IngestionOutcomeDoer_LifeForceOffset.cs
new file mode 100644
index 0000000..a853abe
--- /dev/null
+++ b/Source/Genes/Life_Force/IngestionOutcomeDoer_LifeForceOffset.cs
@@ -0,0 +1,24 @@
+using RimWorld;
+using Verse;
+
+namespace RJW_Genes
+{
+ ///
+ /// This class checks for pawns with LifeForce and Cumeater Gene to add Fertilin when eating cum (the Item from RJW-Sexperience).
+ ///
+ public class IngestionOutcomeDoer_LifeForceOffset : IngestionOutcomeDoer
+ {
+ public const float DEFAULT_FERTILIN_PER_UNIT = 1f;
+ public float FertilinPerUnit = 1f;
+
+ protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
+ {
+ if (GeneUtility.HasLifeForce(pawn) && GeneUtility.IsCumEater(pawn))
+ {
+ float num = ingested.stackCount * this.FertilinPerUnit / 100;
+ GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(pawn), num);
+ }
+ }
+
+ }
+}
diff --git a/Source/Genes/Life_Force/JobDrivers/JobDriver_CastAbilityAfterSex.cs b/Source/Genes/Life_Force/JobDrivers/JobDriver_CastAbilityAfterSex.cs
new file mode 100644
index 0000000..d604cca
--- /dev/null
+++ b/Source/Genes/Life_Force/JobDrivers/JobDriver_CastAbilityAfterSex.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using rjw;
+
+namespace RJW_Genes
+{
+ public class JobDriver_CastAbilityAfterSex : JobDriver_SexBaseInitiator
+ {
+ //Summary//
+ //Similar to jobdriver rape, but it cast an ability after sex and tries to limit what kind of sexinteractions are allowed.
+ protected override IEnumerable MakeNewToils()
+ {
+ base.setup_ticks();
+ //this.FailOnDespawnedOrNull(TargetIndex.A);
+ //this.FailOnCannotTouch(TargetIndex.B, PathEndMode.OnCell);
+ this.FailOnDespawnedNullOrForbidden(this.iTarget);
+ //this.FailOn(() => !target.health.capacities.CanBeAwake);
+ JobDef PartnerJob = xxx.gettin_raped;
+ yield return Toils_Goto.Goto(TargetIndex.A, PathEndMode.OnCell);
+ yield return new Toil
+ {
+ defaultCompleteMode = ToilCompleteMode.Instant,
+ socialMode = RandomSocialMode.Off,
+ initAction = delegate ()
+ {
+ Job newJob = JobMaker.MakeJob(PartnerJob, this.pawn, this.Partner);
+ this.Partner.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
+ }
+ };
+ Toil toil = new Toil();
+ toil.defaultCompleteMode = ToilCompleteMode.Never;
+ toil.socialMode = RandomSocialMode.Off;
+ toil.defaultDuration = this.duration;
+ toil.handlingFacing = true;
+ toil.FailOn(() => this.Partner.CurJob.def != PartnerJob);
+ toil.initAction = delegate ()
+ {
+ this.Partner.pather.StopDead();
+ this.Partner.jobs.curDriver.asleep = false;
+
+ //Tries to find CompProperties_SexInteractionRequirements and if it finds it it will try and generate sexprops based on the sexpropsrequirements.
+ foreach (AbilityComp comp in this.job.ability.comps)
+ {
+ if (comp.props is CompProperties_SexInteractionRequirements)
+ {
+ CompProperties_SexInteractionRequirements sexpropsreq = comp.props as CompProperties_SexInteractionRequirements;
+ this.Sexprops = CustomSexInteraction_Helper.GenerateSexProps(this.pawn, this.Partner, sexpropsreq);
+ }
+ }
+ this.Start();
+ this.Sexprops.usedCondom = (CondomUtility.TryUseCondom(this.pawn) || CondomUtility.TryUseCondom(this.Partner));
+ };
+ toil.AddPreTickAction(delegate
+ {
+ if (this.pawn.IsHashIntervalTick(this.ticks_between_hearts))
+ {
+ this.ThrowMetaIconF(this.pawn.Position, this.pawn.Map, FleckDefOf.Heart);
+ }
+ this.SexTick(this.pawn, this.Partner, true, true);
+ SexUtility.reduce_rest(this.Partner, 1f);
+ SexUtility.reduce_rest(this.pawn, 1f);
+ if (this.ticks_left <= 0)
+ {
+ this.ReadyForNextToil();
+ }
+ });
+ toil.AddFinishAction(delegate
+ {
+ this.End();
+ });
+ yield return toil;
+ yield return new Toil
+ {
+ initAction = delegate ()
+ {
+ SexUtility.ProcessSex(this.Sexprops);
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
+ };
+ yield return Toils_Combat.CastVerb(TargetIndex.A, TargetIndex.B, false);
+ yield break;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobDrivers/JobDriver_Flirt.cs b/Source/Genes/Life_Force/JobDrivers/JobDriver_Flirt.cs
new file mode 100644
index 0000000..337a9b2
--- /dev/null
+++ b/Source/Genes/Life_Force/JobDrivers/JobDriver_Flirt.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using rjw;
+namespace RJW_Genes
+{
+ public class JobDriver_Flirt : JobDriver
+ {
+ private Pawn Target
+ {
+ get
+ {
+ return (Pawn)((Thing)this.pawn.CurJob.GetTarget(TargetIndex.A));
+ }
+ }
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ return true;
+ }
+
+ //Some wait toils to induce delay
+ protected override IEnumerable MakeNewToils()
+ {
+ this.FailOnDespawnedOrNull(TargetIndex.A);
+ yield return Toils_Interpersonal.GotoInteractablePosition(TargetIndex.A);
+ yield return Toils_General.Wait(300, TargetIndex.A);
+ yield return Toils_Interpersonal.WaitToBeAbleToInteract(this.pawn);
+ Toil toil = Toils_Interpersonal.GotoInteractablePosition(TargetIndex.A);
+ toil.socialMode = RandomSocialMode.Off;
+ yield return toil;
+ yield return this.InteractToil();
+ Toil toil1 = Toils_General.Wait(300, TargetIndex.A);
+ toil1.socialMode = RandomSocialMode.Off;
+ yield return toil1;
+ yield break;
+ }
+ private Toil InteractToil()
+ {
+ return Toils_General.Do(delegate
+ {
+ if (this.pawn.interactions.TryInteractWith(this.Target, ThoughtDefOf.rjw_genes_flirt))
+ {
+ Need_Sex need_Sex = this.Target.needs.TryGetNeed();
+ need_Sex.CurLevel += -0.01f;
+ }
+ });
+ }
+
+ private const TargetIndex TargetInd = TargetIndex.A;
+ }
+}
+
diff --git a/Source/Genes/Life_Force/JobDrivers/JobDriver_Seduced.cs b/Source/Genes/Life_Force/JobDrivers/JobDriver_Seduced.cs
new file mode 100644
index 0000000..2d38d75
--- /dev/null
+++ b/Source/Genes/Life_Force/JobDrivers/JobDriver_Seduced.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using rjw;
+using rjw.Modules.Interactions.Enums;
+using rjw.Modules.Interactions.Helpers;
+using rjw.Modules.Interactions.Objects;
+using rjw.Modules.Interactions.Contexts;
+using rjw.Modules.Interactions.Implementation;
+
+namespace RJW_Genes
+{
+ public class JobDriver_Seduced : JobDriver
+ {
+ //Summary//
+ //Makes a pawn move to seducing pawn and then tries to rape them.
+ protected override IEnumerable MakeNewToils()
+ {
+
+ this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
+ this.FailOn(() => !this.pawn.CanReserve(TargetA, xxx.max_rapists_per_prisoner, 0, null, false));
+ this.FailOn(() => this.pawn.IsFighting());
+ this.FailOn(() => this.pawn.Drafted);
+
+ Pawn partner = this.job.GetTarget(TargetIndex.A).Pawn;
+ yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);
+ yield return new Toil
+ {
+ defaultCompleteMode = ToilCompleteMode.Instant,
+ socialMode = RandomSocialMode.Off,
+ initAction = delegate ()
+ {
+ if(partner != null)
+ {
+ partner.drafter.Drafted = false;
+ this.pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.rjw_genes_seduced, partner, null);
+ Job newJob = JobMaker.MakeJob(JobDefOf.sex_on_spot, pawn);
+ partner.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
+ }
+ }
+ };
+ yield break;
+ }
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ return this.pawn.Reserve(TargetA, this.job, xxx.max_rapists_per_prisoner, 0, null, errorOnFailed);
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpot.cs b/Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpot.cs
new file mode 100644
index 0000000..05c9d5b
--- /dev/null
+++ b/Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpot.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using rjw;
+using rjw.Modules.Interactions.Enums;
+using rjw.Modules.Interactions.Helpers;
+using rjw.Modules.Interactions.Objects;
+using rjw.Modules.Interactions.Contexts;
+using rjw.Modules.Interactions.Implementation;
+
+namespace RJW_Genes
+{
+ public class JobDriver_SexOnSpot : JobDriver_SexBaseInitiator
+ {
+ protected override IEnumerable MakeNewToils()
+ {
+ if (RJWSettings.DebugRape)
+ {
+ ModLog.Message(base.GetType().ToString() + "::MakeNewToils() called");
+ }
+ base.setup_ticks();
+ JobDef PartnerJob = JobDefOf.sex_on_spot_reciever;
+ this.FailOnDespawnedNullOrForbidden(this.iTarget);
+ this.FailOn(() => !this.pawn.CanReserve(this.Partner, xxx.max_rapists_per_prisoner, 0, null, false));
+ this.FailOn(() => this.pawn.IsFighting());
+ this.FailOn(() => this.Partner.IsFighting());
+ this.FailOn(() => this.pawn.Drafted);
+ yield return Toils_Goto.GotoThing(this.iTarget, PathEndMode.Touch);
+ if (this.pawn.HostileTo(this.Partner))
+ {
+ Partner.health.AddHediff(xxx.submitting);
+ }
+ yield return Toils_Goto.GotoThing(this.iTarget, PathEndMode.OnCell);
+ //Give thought malus to partner (I was seduced into having sex against my will)
+ yield return new Toil
+ {
+ defaultCompleteMode = ToilCompleteMode.Instant,
+ socialMode = RandomSocialMode.Off,
+ initAction = delegate ()
+ {
+ if (!(this.Partner.jobs.curDriver is JobDriver_SexOnSpotReciever))
+ {
+ Job newJob = JobMaker.MakeJob(PartnerJob, this.pawn);
+ Building_Bed building_Bed = null;
+ if (this.Partner.GetPosture() == PawnPosture.LayingInBed)
+ {
+ building_Bed = this.Partner.CurrentBed();
+ }
+ this.Partner.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
+ if (building_Bed != null)
+ {
+ JobDriver_SexOnSpotReciever jobDriver_SexOnSpotReciever = this.Partner.jobs.curDriver as JobDriver_SexOnSpotReciever;
+ if (jobDriver_SexOnSpotReciever == null)
+ {
+ return;
+ }
+ jobDriver_SexOnSpotReciever.Set_bed(building_Bed);
+ }
+ }
+ }
+ };
+ Toil toil = new Toil();
+ toil.defaultCompleteMode = ToilCompleteMode.Never;
+ toil.defaultDuration = this.duration;
+ toil.handlingFacing = true;
+ toil.FailOn(() => this.Partner.CurJob.def != PartnerJob);
+ toil.initAction = delegate ()
+ {
+ this.Partner.pather.StopDead();
+ this.Partner.jobs.curDriver.asleep = false;
+ this.Start();
+ };
+ toil.tickAction = delegate ()
+ {
+ if (this.pawn.IsHashIntervalTick(this.ticks_between_hearts))
+ {
+ this.ThrowMetaIconF(this.pawn.Position, this.pawn.Map, FleckDefOf.Heart);
+ }
+ this.SexTick(this.pawn, this.Partner, true, true);
+ SexUtility.reduce_rest(this.Partner, 1f);
+ SexUtility.reduce_rest(this.pawn, 2f);
+ if (this.ticks_left <= 0)
+ {
+ this.ReadyForNextToil();
+ }
+ };
+ toil.AddFinishAction(delegate
+ {
+ this.End();
+ });
+ yield return toil;
+ yield return new Toil
+ {
+ initAction = delegate ()
+ {
+ SexUtility.ProcessSex(this.Sexprops);
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
+ };
+ yield break;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpotReceiver.cs b/Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpotReceiver.cs
new file mode 100644
index 0000000..135b231
--- /dev/null
+++ b/Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpotReceiver.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using rjw;
+using rjw.Modules.Interactions.Enums;
+using rjw.Modules.Interactions.Helpers;
+using rjw.Modules.Interactions.Objects;
+using rjw.Modules.Interactions.Contexts;
+using rjw.Modules.Interactions.Implementation;
+
+namespace RJW_Genes
+{
+ //Modified JobDriver_SexBaseRecieverLoved from rjw
+ public class JobDriver_SexOnSpotReciever : JobDriver_SexBaseReciever
+ {
+ protected override IEnumerable MakeNewToils()
+ {
+ base.setup_ticks();
+ this.parteners.Add(base.Partner);
+ if (this.pawn.relations.OpinionOf(base.Partner) < 0)
+ {
+ this.ticks_between_hearts += 50;
+ }
+ else if (this.pawn.relations.OpinionOf(base.Partner) > 60)
+ {
+ this.ticks_between_hearts -= 25;
+ }
+ this.FailOnDespawnedOrNull(this.iTarget);
+ this.FailOn(() => !base.Partner.health.capacities.CanBeAwake);
+ this.FailOn(() => this.pawn.Drafted);
+ this.FailOn(() => base.Partner.Drafted);
+ yield return Toils_Reserve.Reserve(this.iTarget, 1, 0, null);
+ Toil toil2 = this.MakeSexToil();
+ toil2.handlingFacing = false;
+ yield return toil2;
+ yield break;
+ }
+
+ private Toil MakeSexToil()
+ {
+ Toil toil = new Toil();
+ toil.defaultCompleteMode = ToilCompleteMode.Never;
+ toil.socialMode = RandomSocialMode.Off;
+ toil.handlingFacing = true;
+ toil.tickAction = delegate ()
+ {
+ if (this.pawn.IsHashIntervalTick(this.ticks_between_hearts))
+ {
+ base.ThrowMetaIconF(this.pawn.Position, this.pawn.Map, FleckDefOf.Heart);
+ }
+ };
+ toil.AddEndCondition(delegate
+ {
+ if (this.parteners.Count <= 0)
+ {
+ return JobCondition.Succeeded;
+ }
+ return JobCondition.Ongoing;
+ });
+ toil.AddFinishAction(delegate
+ {
+ if (xxx.is_human(this.pawn))
+ {
+ this.pawn.Drawer.renderer.graphics.ResolveApparelGraphics();
+ }
+ GlobalTextureAtlasManager.TryMarkPawnFrameSetDirty(this.pawn);
+ Hediff submitting = this.pawn.health.hediffSet.GetFirstHediffOfDef(xxx.submitting);
+ if (submitting != null)
+ {
+ this.pawn.health.RemoveHediff(submitting);
+ this.pawn.stances.stunner.StunFor(60, this.pawn, true, true);
+ }
+ });
+ toil.socialMode = RandomSocialMode.Off;
+ return toil;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobGivers/JobGiver_Flirt.cs b/Source/Genes/Life_Force/JobGivers/JobGiver_Flirt.cs
new file mode 100644
index 0000000..a629e0e
--- /dev/null
+++ b/Source/Genes/Life_Force/JobGivers/JobGiver_Flirt.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using Verse.AI;
+using RimWorld;
+namespace RJW_Genes
+{
+ public class JobGiver_Flirt : ThinkNode_JobGiver
+ {
+ // Token: 0x0600405A RID: 16474 RVA: 0x0017271C File Offset: 0x0017091C
+ protected override Job TryGiveJob(Pawn pawn)
+ {
+ Pawn target = pawn.mindState.duty.focus.Pawn;
+ if (pawn.CanReach(target, PathEndMode.InteractionCell, Danger.Deadly) && !target.jobs.curDriver.asleep)
+ {
+ return JobMaker.MakeJob(JobDefOf.rjw_genes_flirt, target);
+ }
+ return null;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobGivers/JobGiver_GetLifeForce.cs b/Source/Genes/Life_Force/JobGivers/JobGiver_GetLifeForce.cs
new file mode 100644
index 0000000..fdd7279
--- /dev/null
+++ b/Source/Genes/Life_Force/JobGivers/JobGiver_GetLifeForce.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using rjw;
+
+namespace RJW_Genes
+{
+ public class JobGiver_GetLifeForce : ThinkNode_JobGiver
+ {
+ protected override Job TryGiveJob(Pawn pawn)
+ {
+ Pawn_GeneTracker genes = pawn.genes;
+ Gene_LifeForce gene_lifeforce = (genes != null) ? genes.GetFirstGeneOfType() : null;
+ if (gene_lifeforce == null)
+ {
+ return null;
+ }
+ if (!gene_lifeforce.ShouldConsumeLifeForceNow())
+ {
+ return null;
+ }
+
+
+ if (ModsConfig.IsActive("rjw.sexperience") && gene_lifeforce.StoredCumAllowed && genes.HasGene(GeneDefOf.rjw_genes_cum_eater))
+ {
+ Thing gatheredCum = this.GetStoredCum(pawn);
+ if (gatheredCum == null)
+ {
+ return null;
+ }
+ IngestionOutcomeDoer_LifeForceOffset ingestionOutcomeDoer = (IngestionOutcomeDoer_LifeForceOffset)gatheredCum.def.ingestible.outcomeDoers.First((IngestionOutcomeDoer x) => x is IngestionOutcomeDoer_LifeForceOffset);
+ if (ingestionOutcomeDoer == null)
+ {
+ return null;
+ }
+ int num = Mathf.RoundToInt(((gene_lifeforce.targetValue - gene_lifeforce.Value) * 100 + 10) / IngestionOutcomeDoer_LifeForceOffset.DEFAULT_FERTILIN_PER_UNIT);
+ if (gatheredCum != null && num > 0)
+ {
+ Job job = JobMaker.MakeJob(RimWorld.JobDefOf.Ingest, gatheredCum);
+ job.count = Mathf.Min(gatheredCum.stackCount, num);
+ job.ingestTotalCount = true;
+ return job;
+ }
+ }
+ return null;
+ }
+
+ //From JobGiver_GetHemogen, dont know exactly what this influences
+ public override float GetPriority(Pawn pawn)
+ {
+ if (!ModsConfig.BiotechActive)
+ {
+ return 0f;
+ }
+ Pawn_GeneTracker genes = pawn.genes;
+ if (((genes != null) ? genes.GetFirstGeneOfType() : null) == null)
+ {
+ return 0f;
+ }
+ return 9.1f;
+ }
+
+ private Thing GetStoredCum(Pawn pawn)
+ {
+ Thing carriedThing = pawn.carryTracker.CarriedThing;
+ ThingDef gatheredCum = ThingDef.Named("GatheredCum");
+ if (carriedThing != null && carriedThing.def == gatheredCum)
+ {
+ return carriedThing;
+ }
+ for (int i = 0; i < pawn.inventory.innerContainer.Count; i++)
+ {
+ if (pawn.inventory.innerContainer[i].def == gatheredCum)
+ {
+ return pawn.inventory.innerContainer[i];
+ }
+ }
+ return GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, pawn.Map.listerThings.ThingsOfDef(gatheredCum), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false, false, false), 9999f, (Thing t) => pawn.CanReserve(t, 1, -1, null, false) && !t.IsForbidden(pawn), null);
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobGivers/JobGiver_LifeForce_RandomRape.cs b/Source/Genes/Life_Force/JobGivers/JobGiver_LifeForce_RandomRape.cs
new file mode 100644
index 0000000..f710c62
--- /dev/null
+++ b/Source/Genes/Life_Force/JobGivers/JobGiver_LifeForce_RandomRape.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using rjw;
+
+namespace RJW_Genes
+{
+ public class JobGiver_LifeForce_RandomRape : JobGiver_RandomRape
+ {
+ protected override Job TryGiveJob(Pawn pawn)
+ {
+ if (!can_rape(pawn, false))
+ {
+ return null;
+ }
+ Pawn pawn2 = this.find_victim(pawn, pawn.Map);
+ if (pawn2 == null)
+ {
+ return null;
+ }
+ return JobMaker.MakeJob(JobDefOf.rjw_genes_lifeforce_randomrape, pawn2);
+ }
+
+ //same as xxx.canrape from rjw, but without last requirements.
+ public static bool can_rape(Pawn pawn, bool forced = false)
+ {
+ return RJWSettings.rape_enabled && (xxx.is_mechanoid(pawn) || ((xxx.can_fuck(pawn) ||
+ (!xxx.is_male(pawn) && xxx.get_vulnerability(pawn) < RJWSettings.nonFutaWomenRaping_MaxVulnerability &&
+ xxx.can_be_fucked(pawn))) && (!xxx.is_human(pawn) || ((pawn.ageTracker.Growth >= 1f || pawn.ageTracker.CurLifeStage.reproductive)))));
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/JobGivers/JobGiver_TryQuickieWith.cs b/Source/Genes/Life_Force/JobGivers/JobGiver_TryQuickieWith.cs
new file mode 100644
index 0000000..22fcb01
--- /dev/null
+++ b/Source/Genes/Life_Force/JobGivers/JobGiver_TryQuickieWith.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using rjw;
+using RJWSexperience;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using Verse.AI.Group;
+using UnityEngine;
+namespace RJW_Genes
+{
+ public class JobGiver_TryQuickieWith : ThinkNode_JobGiver
+ {
+ protected override Job TryGiveJob(Pawn pawn)
+ {
+ Pawn target = pawn.mindState.duty.focus.Pawn;
+ Pawn_JobTracker jobs = target.jobs;
+ string pawn_name = xxx.get_pawnname(pawn);
+ string target_name = xxx.get_pawnname(target);
+ //can reserve eachother
+ if (pawn.CanReserveAndReach(target, PathEndMode.InteractionCell, Danger.Some) && target.CanReserve(pawn, 1, 0, null, false))
+ {
+ //Dont interrupt player
+ if (!(((jobs != null) ? jobs.curJob : null) != null && jobs.curJob.playerForced))
+ {
+ float willingness = TargetWillingness(pawn, target);
+ if (Rand.Chance(willingness))
+ {
+ Job newJob =JobMaker.MakeJob(xxx.quick_sex, target);
+
+ //Pawn joins faction when lordJob ends instead of leaving
+ //in the future determine the chance of this another way
+ if (Rand.Chance(JoinChance(pawn, target)))
+ {
+ Lord lord = pawn.GetLord();
+ LordJob_SuccubusVisit lordJob = lord == null? null : lord.LordJob as LordJob_SuccubusVisit;
+ if (lordJob != null)
+ {
+ if (!lordJob.colonyJoiners.Contains(pawn))
+ {
+ lordJob.colonyJoiners.Add(pawn);
+ }
+ }
+ }
+ return newJob;
+ }
+ else
+ {
+ if (RJWSettings.DebugLogJoinInBed) //change this when we have our own settigns
+ {
+ ModLog.Message(string.Format("{0} was not interested in having sex with {1}: ({2} chance)", pawn_name, target_name, willingness));
+ }
+ }
+ }
+ else
+ {
+ if (RJWSettings.DebugLogJoinInBed) //change this when we have our own settigns
+ {
+ //ModLog.Message(string.Format(" find_pawn_to_fuck({0}): lover has important job ({1}), skipping", pawn_name, target.jobs.curJob.def));
+ }
+ }
+ }
+ else
+ {
+ if (RJWSettings.DebugLogJoinInBed) //change this when we have our own settigns
+ {
+ ModLog.Message(" (" + pawn_name + "): cannot reach or reserve " + target_name);
+ }
+ }
+ return null;
+ }
+ public static float TargetWillingness(Pawn pawn, Pawn target)
+ {
+ string pawn_name = xxx.get_pawnname(pawn);
+ float willingness = SexAppraiser.would_fuck(target,pawn);
+ bool nymph = xxx.is_nympho(target);
+ bool loverelation = LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target);
+ if (nymph || loverelation)
+ {
+ willingness *= 2;
+ }
+ if (xxx.HasNonPolyPartner(pawn, false) && !loverelation)
+ {
+ if (RJWHookupSettings.NymphosCanCheat && nymph && xxx.is_frustrated(pawn))
+ {
+ if (RJWSettings.DebugLogJoinInBed)
+ {
+ ModLog.Message(" find_partner(" + pawn_name + "): I'm a nympho and I'm so frustrated that I'm going to cheat");
+ }
+ }
+ else
+ {
+ if (!pawn.health.hediffSet.HasHediff(HediffDef.Named("AlcoholHigh"), false))
+ {
+ if (RJWSettings.DebugLogJoinInBed)
+ {
+ ModLog.Message(" find_partner(" + pawn_name + "): I interested in banging but that's cheating");
+ }
+ //Succubus has a small chance to seduce even if target is in relationship
+ willingness *= 0.1f;
+ }
+ else
+ {
+ if (RJWSettings.DebugLogJoinInBed)
+ {
+ ModLog.Message(" find_partner(" + pawn_name + "): I want to bang and im too drunk to care if its cheating");
+ }
+ //No change
+ }
+ }
+ }
+ return willingness;
+ }
+
+ public static float JoinChance(Pawn pawn ,Pawn target)
+ {
+
+ float chance = 0.1f;
+
+ //Sex satisfaction, how good the target is at sex
+ chance *= xxx.get_sex_satisfaction(target);
+
+ //Succubus mood
+ if (pawn.needs != null && pawn.needs.mood != null)
+ {
+ chance *= pawn.needs.mood.CurLevelPercentage + 0.5f;
+ }
+
+ //Size of genitals
+ bool size_matters = true; //To be placed in modsettings
+ if (size_matters)
+ {
+ //The larger the penis to greater the chance
+ if (RelationsUtility.AttractedToGender(pawn, Gender.Male))
+ {
+ chance *= GetGenitalSize(target, true) + 0.5f;
+ }
+
+ //The tighter the vagine the greater the chance, a size above 1 is considered as 1
+ if (RelationsUtility.AttractedToGender(pawn, Gender.Female))
+ {
+ chance *= 1f - Mathf.Min(GetGenitalSize(target, false),1f) + 0.5f;
+ }
+ }
+
+ //Sex ability from sexperience
+ if (ModsConfig.IsActive("rjw.sexperience"))
+ {
+ chance *= RJWSexperience.PawnExtensions.GetSexStat(pawn);
+ }
+ return Mathf.Max(chance,0f);
+ }
+
+ //Gets the size of the largest penis or the tightest vagina
+ public static float GetGenitalSize(Pawn pawn, bool penis_else_vagina)
+ {
+ List genitals = rjw.PawnExtensions.GetGenitalsList(pawn);
+ if(!genitals.NullOrEmpty())
+ {
+ if (penis_else_vagina)
+ {
+ List penises = genitals.Where(genital => Genital_Helper.is_penis(genital)).ToList();
+ {
+ if (!penises.NullOrEmpty())
+ {
+ return penises.Max(genital => genital.Severity);
+ }
+ }
+ }
+ else
+ {
+ List vaginas = genitals.Where(genital => Genital_Helper.is_vagina(genital)).ToList();
+ {
+ if (!vaginas.NullOrEmpty())
+ {
+ return vaginas.Min(genital => genital.Severity);
+ }
+ }
+ }
+ }
+ return 0f;
+
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/LordToil_Flirt.cs b/Source/Genes/Life_Force/LordToil_Flirt.cs
new file mode 100644
index 0000000..0bd1e38
--- /dev/null
+++ b/Source/Genes/Life_Force/LordToil_Flirt.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using Verse.AI;
+using Verse.AI.Group;
+using RimWorld;
+namespace RJW_Genes
+{
+ //Based on LordToil_EscortPawn
+ public class LordToil_Flirt : LordToil
+ {
+ public LordToil_Flirt(Pawn victim, float followRadius)
+ {
+ this.victim = victim;
+ this.followRadius = followRadius;
+ }
+
+
+ public override void UpdateAllDuties()
+ {
+ for (int i = 0; i < this.lord.ownedPawns.Count; i++)
+ {
+ PawnDuty duty = new PawnDuty(GeneDefOf.rjw_genes_flirt, this.victim, this.followRadius);
+ this.lord.ownedPawns[i].mindState.duty = duty;
+ }
+ }
+
+ public Pawn victim;
+ public float followRadius;
+ }
+}
diff --git a/Source/Genes/Life_Force/MentalStates/LifeForceMentalBreakWorker.cs b/Source/Genes/Life_Force/MentalStates/LifeForceMentalBreakWorker.cs
new file mode 100644
index 0000000..36b47b0
--- /dev/null
+++ b/Source/Genes/Life_Force/MentalStates/LifeForceMentalBreakWorker.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+using RimWorld;
+using Verse.AI;
+
+namespace RJW_Genes
+{
+ public class LifeForceMentalBreakWorker : MentalBreakWorker
+ {
+ public override bool BreakCanOccur(Pawn pawn)
+ {
+ if (pawn.Spawned && base.BreakCanOccur(pawn))
+ {
+ if (!GeneUtility.HasLifeForce(pawn))
+ {
+ return false;
+ }
+ Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType();
+ if( gene.Resource.Value <= 0)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/MentalStates/LifeForceMentalState.cs b/Source/Genes/Life_Force/MentalStates/LifeForceMentalState.cs
new file mode 100644
index 0000000..9c22f4e
--- /dev/null
+++ b/Source/Genes/Life_Force/MentalStates/LifeForceMentalState.cs
@@ -0,0 +1,23 @@
+using System;
+using Verse;
+using Verse.AI;
+using rjw;
+namespace RJW_Genes
+{
+ public class LifeForceMentalState : MentalState
+ {
+ public override void MentalStateTick()
+ {
+ if (this.pawn.IsHashIntervalTick(150) && !GeneUtility.HasCriticalLifeForce(this.pawn))
+ {
+ Pawn_JobTracker jobs = this.pawn.jobs;
+ if (!(((jobs != null) ? jobs.curDriver : null) is JobDriver_Sex))
+ {
+ base.RecoverFromState();
+ return;
+ }
+ }
+ base.MentalStateTick();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Genes/Life_Force/MentalStates/LifeForceMentalStateWorker.cs b/Source/Genes/Life_Force/MentalStates/LifeForceMentalStateWorker.cs
new file mode 100644
index 0000000..eaeaf89
--- /dev/null
+++ b/Source/Genes/Life_Force/MentalStates/LifeForceMentalStateWorker.cs
@@ -0,0 +1,14 @@
+using System;
+using Verse;
+using Verse.AI;
+using rjw;
+namespace RJW_Genes
+{
+ public class LifeForceMentalStateWorker : MentalStateWorker
+ {
+ public override bool StateCanOccur(Pawn pawn)
+ {
+ return base.StateCanOccur(pawn) && (xxx.is_human(pawn) && JobGiver_LifeForce_RandomRape.can_rape(pawn));
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Patches/Patch_SatisfyPersonal_LifeForceGain.cs b/Source/Genes/Life_Force/Patches/Patch_SatisfyPersonal_LifeForceGain.cs
new file mode 100644
index 0000000..6ea0a62
--- /dev/null
+++ b/Source/Genes/Life_Force/Patches/Patch_SatisfyPersonal_LifeForceGain.cs
@@ -0,0 +1,203 @@
+using HarmonyLib;
+using rjw;
+using RimWorld;
+using Verse;
+
+namespace RJW_Genes
+{
+ ///
+ /// This Patch hooks after "SatisfyPersonal"(i.E. when the pawn finished fucking) and covers LifeForceGain.
+ /// If the pawn has LifeForce, all relevant Genes are checked and applied.
+ ///
+ [HarmonyPatch(typeof(SexUtility), nameof(SexUtility.SatisfyPersonal))]
+ public static class Patch_SatisfyPersonal_LifeForceGain
+ {
+ public const float LIFEFORCE_GAINED_FROM_DRAINER_GENE = 0.25f;
+
+ public static void Postfix(SexProps props)
+ {
+ // ShortCuts: Exit Early if Pawn or Partner are null (can happen with Animals or Masturbation)
+ if (props.pawn == null || !props.hasPartner())
+ return;
+
+ // Exit if pawn has fertilin themself, it won't give any if it has lifeforce themself.
+ if (GeneUtility.HasLifeForce(props.pawn))
+ {
+ return;
+ }
+
+ //Summary//
+ //We use the positions of the pawn (dom or sub) and based on that which interactions will transfer fertilin
+ //By checking isreceiver we know if the succubus is the dom or the sub and if the situation is reverse we also swap the function we use
+ float absorb_factor = 0f;
+ if (GeneUtility.HasLifeForce(props.partner))
+ {
+ Pawn PawnWithLifeForce = props.partner;
+
+ if (!props.isRevese)
+ {
+ if (props.isReceiver)
+ {
+ // Scenario Dom Succubus, normal
+ absorb_factor = BaseDom(props, PawnWithLifeForce);
+ }
+ else
+ {
+ // Scenario Sub Succubus, normal
+ absorb_factor = BaseSub(props, PawnWithLifeForce);
+ }
+ }
+ else
+ {
+ if (props.isReceiver)
+ {
+ // Scenario Dom Succubus, Reverse
+ absorb_factor = BaseSub(props, PawnWithLifeForce);
+ }
+ else
+ {
+ // Scenario Sub Succubus, Reverse
+ absorb_factor = BaseDom(props, PawnWithLifeForce);
+ }
+ }
+
+ // If we remove this check fertilin is always lost, but the succubus doesn't always gain any
+ if (absorb_factor != 0f)
+ {
+ TransferFertilin(props, absorb_factor);
+ }
+
+ // Handle Gene: Sexual_Drainer
+ // to be drained, a pawn must not-be-drained-already and drainers cannot be drained either.
+ if (GeneUtility.IsSexualDrainer(PawnWithLifeForce)
+ && !props.pawn.health.hediffSet.HasHediff(HediffDefOf.rjw_genes_succubus_drained)
+ && !GeneUtility.IsSexualDrainer(props.pawn))
+ {
+ if (GeneUtility.IsGenerousDonor(props.pawn) && RJW_Genes_Settings.rjw_genes_generous_donor_cheatmode)
+ {
+ // Cheatmode is on, do not drain but give life
+ GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(PawnWithLifeForce), LIFEFORCE_GAINED_FROM_DRAINER_GENE);
+ if (RJW_Genes_Settings.rjw_genes_detailed_debug)
+ ModLog.Message($"{props.pawn.Name} was not (sexually) drained by {PawnWithLifeForce.Name}, because Cheatmode for Generous Donors is on");
+ } else
+ {
+ if (RJW_Genes_Settings.rjw_genes_detailed_debug)
+ ModLog.Message($"{props.pawn.Name} has been (sexually) drained by {PawnWithLifeForce.Name}");
+ props.pawn.health.AddHediff(HediffDefOf.rjw_genes_succubus_drained);
+ GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(PawnWithLifeForce), LIFEFORCE_GAINED_FROM_DRAINER_GENE);
+ }
+ }
+ }
+ }
+
+ public static void TransferFertilin(SexProps props, float absorb_percentage = 1f)
+ {
+ Pawn_GeneTracker genes = props.partner.genes;
+ Gene_LifeForce gene = genes.GetFirstGeneOfType();
+
+ Hediff fertilin_lost = props.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.rjw_genes_fertilin_lost);
+ //Around quarter get ejected everytime pawn cums
+ float multiplier = Rand.Range(0.10f, 0.40f);
+
+ if (GeneUtility.IsGenerousDonor(props.pawn) && RJW_Genes_Settings.rjw_genes_generous_donor_cheatmode)
+ {
+ // Do nothing, Cheatmode is on
+ multiplier = 1;
+ }
+ else
+ {
+ //Create a new ferilin_lost hediff or increase it
+ if (fertilin_lost == null)
+ {
+ Hediff new_fertilin_lost = HediffMaker.MakeHediff(HediffDefOf.rjw_genes_fertilin_lost, props.pawn);
+ props.pawn.health.AddHediff(new_fertilin_lost);
+ new_fertilin_lost.Severity = multiplier;
+ } else
+ {
+ multiplier *= 1 - fertilin_lost.Severity;
+ fertilin_lost.Severity += multiplier;
+ }
+ }
+
+ multiplier *= absorb_percentage;
+ //Currently taking the sum of all penises, maybe I should just consider one at random
+ float valuechange = TotalFertilinAmount(props, multiplier);
+
+ if (props.partner.IsAnimal())
+ {
+ if (RJW_Genes_Settings.rjw_genes_detailed_debug)
+ ModLog.Message($"Fertilin-Source of {props.pawn.Name} was an Animal, Fertilin-Gain is being adjusted by {RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor}%");
+ valuechange *= RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor;
+ }
+
+ GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(props.partner), valuechange);
+ }
+
+ public static float TotalFertilinAmount(SexProps props, float multiplier)
+ {
+ float total_fluid = CumUtility.GetTotalFluidAmount(props.pawn) / 100;
+
+ //More in the tank means more to give
+ if (props.pawn.Has(Quirk.Messy))
+ {
+ total_fluid *= 2;
+ }
+ if (props.pawn.RaceProps.Animal)
+ {
+ total_fluid *= 0.1f; //Should make this settable in settings
+ }
+
+ return total_fluid;
+ }
+
+ ///
+ /// Handles the Case that the Life-Force wielder initiated the Sex (They are "Dom").
+ ///
+ /// The summary of the sex act, used for checking conditions.
+ /// The pawn that might gain LifeForce through this method.
+ /// A factor between 0 and 1 how much of output-fertilin will be used for input-lifeforce
+ public static float BaseDom(SexProps props, Pawn PawnWithLifeForce)
+ {
+ float absorb_factor = 0f;
+ if (props.sexType == xxx.rjwSextype.Sixtynine && GeneUtility.IsCumEater(PawnWithLifeForce))
+ {
+ absorb_factor += 1f;
+ }
+ return absorb_factor;
+ }
+
+ ///
+ /// Handles the Case that the Life-Force wielder got initiated into sex (They are "Sub").
+ ///
+ /// The summary of the sex act, used for checking conditions.
+ /// The pawn that might gain LifeForce through this method.
+ /// A factor between 0 and 1 how much of output-fertilin will be used for input-lifeforce
+ public static float BaseSub(SexProps props, Pawn PawnWithLifeForce)
+ {
+ float absorb_factor = 0f;
+ if ((props.sexType == xxx.rjwSextype.Oral || props.sexType == xxx.rjwSextype.Fellatio || props.sexType == xxx.rjwSextype.Sixtynine)
+ && GeneUtility.IsCumEater(PawnWithLifeForce))
+ {
+ absorb_factor += 1f;
+ }
+ else if (props.sexType == xxx.rjwSextype.Vaginal && GeneUtility.HasGeneNullCheck(PawnWithLifeForce, GeneDefOf.rjw_genes_fertilin_absorber))
+ {
+ absorb_factor += 1f;
+ }
+ else if (props.sexType == xxx.rjwSextype.Anal && GeneUtility.HasGeneNullCheck(PawnWithLifeForce, GeneDefOf.rjw_genes_fertilin_absorber))
+ {
+ absorb_factor += 1f;
+ }
+ else if (props.sexType == xxx.rjwSextype.DoublePenetration && GeneUtility.HasGeneNullCheck(PawnWithLifeForce, GeneDefOf.rjw_genes_fertilin_absorber))
+ {
+ absorb_factor += 1f;
+ }
+ else if (props.sexType == xxx.rjwSextype.Scissoring || props.sexType == xxx.rjwSextype.Cunnilingus)
+ {
+ //with vaginal cum absorbtion
+ //absorb_factor += 1f;
+ }
+ return absorb_factor;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Patches/Patch_SexTicks_ChangePsyfocus.cs b/Source/Genes/Life_Force/Patches/Patch_SexTicks_ChangePsyfocus.cs
new file mode 100644
index 0000000..dfc359b
--- /dev/null
+++ b/Source/Genes/Life_Force/Patches/Patch_SexTicks_ChangePsyfocus.cs
@@ -0,0 +1,62 @@
+using HarmonyLib;
+using rjw;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+
+namespace RJW_Genes
+{
+
+ ///
+ /// This patch enables cum-eater pawns to drain cumflations for more fertilin drain by passively having sex.
+ /// It is hooked after RJWs Change-Psyfocus so that pawns that are having prolonged sex (e.g. by overdrive) can fully drain the cumflation over time.
+ ///
+ /// It is conditionally loaded only when LicentiaLabs is enabled, as this is the necessary source for cumflation-hediffs.
+ /// The patched function is: [HarmonyPatch(typeof(JobDriver_Sex), nameof(JobDriver_Sex.ChangePsyfocus))]
+ ///
+ public static class Patch_SexTicks_ChangePsyfocus
+ {
+ public const float LIFEFORCE_GAIN_PER_TICK = 0.05f;
+ public const float CUMFLATION_SEVERITY_LOSS_PER_TICK = 0.1f;
+
+ //Using ChangePsyfocus as it is something that fires every 60 ticks
+ public static void Postfix(ref JobDriver_Sex __instance, ref Pawn pawn, ref Thing target)
+ {
+ SexProps props = __instance.Sexprops;
+ if (props != null && props.sexType == xxx.rjwSextype.Cunnilingus && props.partner != null && target != null)
+ {
+ Pawn pawn2 = target as Pawn;
+ // Case 1: Pawn is "drinking" and has CumEater Gene
+ if (props.isRevese && GeneUtility.IsCumEater(pawn))
+ {
+ if (RJW_Genes_Settings.rjw_genes_detailed_debug)
+ ModLog.Message($"{pawn.Name} is draining {pawn2.Name}'s cumflation for additional fertilin (CumEater-Gene ChangePsyFocus-Trigger).");
+ DrinkCumflation(pawn2, pawn);
+ }
+ // Case 2: Pawn2 is "drinking" and has CumEater Gene
+ else if (GeneUtility.IsCumEater(pawn2))
+ {
+ if (RJW_Genes_Settings.rjw_genes_detailed_debug)
+ ModLog.Message($"{pawn.Name} is draining {pawn2.Name}'s cumflation for additional fertilin (CumEater-Gene ChangePsyFocus-Trigger).");
+ DrinkCumflation(pawn, pawn2);
+ }
+ }
+ }
+
+ public static void DrinkCumflation(Pawn source, Pawn consumer)
+ {
+ if (GeneUtility.HasLifeForce(consumer) && GeneUtility.IsCumEater(consumer)
+ && source.health.hediffSet.HasHediff(HediffDef.Named("Cumflation")))
+ {
+ Hediff cumflation = source.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Cumflation"));
+ Gene_LifeForce gene_LifeForce = consumer.genes.GetFirstGeneOfType();
+ cumflation.Severity = Math.Max(0f,cumflation.Severity - CUMFLATION_SEVERITY_LOSS_PER_TICK);
+ gene_LifeForce.Resource.Value += LIFEFORCE_GAIN_PER_TICK;
+ }
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/Patches/Patch_Vanilla_Inheritance_Fertilin.cs b/Source/Genes/Life_Force/Patches/Patch_Vanilla_Inheritance_Fertilin.cs
new file mode 100644
index 0000000..b4b327c
--- /dev/null
+++ b/Source/Genes/Life_Force/Patches/Patch_Vanilla_Inheritance_Fertilin.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HarmonyLib;
+using RimWorld;
+using Verse;
+
+namespace RJW_Genes
+{
+ ///
+ /// This Patch is applied to add a absorption gene for fertilin if it has none, but it does have the fertilin gene
+ /// First tries to get one from the parents else chooses one of them at random
+ /// the genes are determined and "simply added".
+ ///
+ /// This fixes the potential problem that Pawns could inherit Fertilin, but no gene to gain Fertilin.
+ ///
+ [HarmonyPatch(typeof(PregnancyUtility), "GetInheritedGeneSet", new Type[]
+ {
+ typeof(Pawn),
+ typeof(Pawn)
+ }
+ )]
+ public static class Patch_Vanilla_Inheritance_Fertilin
+ {
+ [HarmonyPostfix]
+ public static void InheritedGenes(Pawn father, Pawn mother, ref GeneSet __result)
+ {
+ //Also make a setting for this
+ if (__result.GenesListForReading.Contains(GeneDefOf.rjw_genes_lifeforce))
+ {
+ List babies_genes = __result.GenesListForReading;
+
+ //If there is no absorption gene get one from the parents, else a random one
+ if(!Has_Fertilin_Source_Gene(babies_genes))
+ {
+ if (RJW_Genes_Settings.rjw_genes_detailed_debug)
+ ModLog.Message($"Child of ({father.Name};{mother.Name}) has Genes with LifeForce-Resource but no Source-Gene, adding one of parents random if possible or any random otherwise.");
+ // Gather Parents Source-Genes
+ List absorption_genes_parents = new List();
+ foreach (GeneDef geneDef in FertilinSourceGenes)
+ {
+ if(mother.genes != null && mother.genes.HasGene(geneDef))
+ absorption_genes_parents.Add(geneDef);
+
+ if (father.genes != null && father.genes.HasGene(geneDef))
+ absorption_genes_parents.Add(geneDef);
+ }
+ // Parents had Genes - Pick a random one of them
+ if (!absorption_genes_parents.NullOrEmpty())
+ __result.AddGene(absorption_genes_parents.RandomElement());
+ // Create a fully random one for your little Cumfueled missbreed
+ else
+ __result.AddGene(FertilinSourceGenes.RandomElement());
+ }
+ }
+ }
+
+ private static List FertilinSourceGenes = new List() {
+ GeneDefOf.rjw_genes_drainer,
+ GeneDefOf.rjw_genes_cum_eater,
+ GeneDefOf.rjw_genes_fertilin_absorber,
+ GeneDefOf.rjw_genes_cockeater
+ };
+
+ private static bool Has_Fertilin_Source_Gene(List genes)
+ {
+ foreach (GeneDef gene in genes)
+ {
+ if (FertilinSourceGenes.Contains(gene))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ }
+}
diff --git a/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalCannotInteract.cs b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalCannotInteract.cs
new file mode 100644
index 0000000..06e05b4
--- /dev/null
+++ b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalCannotInteract.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using Verse.AI;
+namespace RJW_Genes
+{
+ public class ThinkNode_ConditionalCannotInteract : ThinkNode_Conditional
+ {
+ protected override bool Satisfied(Pawn pawn)
+ {
+ Pawn target = pawn.mindState.duty.focus.Pawn;
+ if (target == null)
+ {
+ return true;
+ }
+ return (target.jobs != null && target.jobs.curDriver.asleep) || !pawn.CanReach(target, PathEndMode.InteractionCell, Danger.Deadly);
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalCritcalLifeForce.cs b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalCritcalLifeForce.cs
new file mode 100644
index 0000000..dbb3f6b
--- /dev/null
+++ b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalCritcalLifeForce.cs
@@ -0,0 +1,14 @@
+using System;
+using Verse;
+using Verse.AI;
+
+namespace RJW_Genes
+{
+ public class ThinkNode_ConditionalCritcalLifeForce : ThinkNode_Conditional
+ {
+ protected override bool Satisfied(Pawn p)
+ {
+ return GeneUtility.HasCriticalLifeForce(p);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalLowLifeForce.cs b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalLowLifeForce.cs
new file mode 100644
index 0000000..0e71ce7
--- /dev/null
+++ b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_ConditionalLowLifeForce.cs
@@ -0,0 +1,14 @@
+using System;
+using Verse;
+using Verse.AI;
+
+namespace RJW_Genes
+{
+ public class ThinkNode_ConditionalLowLifeForce : ThinkNode_Conditional
+ {
+ protected override bool Satisfied(Pawn p)
+ {
+ return GeneUtility.HasLowLifeForce(p);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Genes/Life_Force/ThinkNodes/ThinkNode_NewFlirtTarget.cs b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_NewFlirtTarget.cs
new file mode 100644
index 0000000..9dee5ad
--- /dev/null
+++ b/Source/Genes/Life_Force/ThinkNodes/ThinkNode_NewFlirtTarget.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using Verse.AI;
+using rjw;
+namespace RJW_Genes
+{
+ public class ThinkNode_NewFlirtTarget : ThinkNode
+ {
+ public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
+ {
+ List validTargets = ValidTargets(pawn, pawn.Map).ToList();
+ Pawn new_target = validTargets.NullOrEmpty() ? null : validTargets.RandomElement();
+ if (new_target != null)
+ {
+ pawn.mindState.duty.focus = new_target;
+ }
+ return ThinkResult.NoJob;
+ }
+
+ private IEnumerable ValidTargets(Pawn pawn, Map map)
+ {
+ foreach (Pawn pawn2 in map.mapPawns.FreeAdultColonistsSpawned)
+ {
+ if (pawn != null && pawn2 != null && pawn != pawn2 && !pawn2.jobs.curDriver.asleep && SexAppraiser.would_fuck(pawn, pawn2) > 0.1f)
+ {
+ yield return pawn2;
+ }
+ }
+ //IEnumerator enumerator = null;
+ yield break;
+ }
+ }
+}
diff --git a/Source/Genes/Life_Force/UI/Alert_LowFertilin.cs b/Source/Genes/Life_Force/UI/Alert_LowFertilin.cs
new file mode 100644
index 0000000..d76d4ce
--- /dev/null
+++ b/Source/Genes/Life_Force/UI/Alert_LowFertilin.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld.Planet;
+using Verse;
+using RimWorld;
+namespace RJW_Genes
+{
+ public class Alert_CriticalFertilin : Alert
+ {
+ private List Targets
+ {
+ get
+ {
+ this.CalculateTargets();
+ return this.targets;
+ }
+ }
+
+ public override string GetLabel()
+ {
+ if (this.Targets.Count == 1)
+ {
+ return "AlertLowFertilin".Translate() + ": " + this.targetLabels[0];
+ }
+ return "AlertLowFertilin".Translate();
+ }
+
+ private void CalculateTargets()
+ {
+ this.targets.Clear();
+ this.targetLabels.Clear();
+ if (!ModsConfig.BiotechActive)
+ {
+ return;
+ }
+ foreach (Pawn pawn in PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive)
+ {
+ if (pawn.RaceProps.Humanlike && pawn.Faction == Faction.OfPlayer)
+ {
+ Pawn_GeneTracker genes = pawn.genes;
+ Gene_LifeForce gene_Lifeforce = (genes != null) ? genes.GetFirstGeneOfType() : null;
+ if (gene_Lifeforce != null && gene_Lifeforce.Value < gene_Lifeforce.MinLevelForAlert)
+ {
+ this.targets.Add(pawn);
+ this.targetLabels.Add(pawn.NameShortColored.Resolve());
+ }
+ }
+ }
+ }
+
+ public override TaggedString GetExplanation()
+ {
+ return "AlertLowFertilinDesc".Translate() + ":\n" + this.targetLabels.ToLineList(" - ");
+ }
+
+ public override AlertReport GetReport()
+ {
+ return AlertReport.CulpritsAre(this.Targets);
+ }
+
+ private List targets = new List();
+
+ private List targetLabels = new List();
+ }
+}
diff --git a/Source/Genes/Life_Force/UI/GeneGizmo_ResourceLifeForce.cs b/Source/Genes/Life_Force/UI/GeneGizmo_ResourceLifeForce.cs
new file mode 100644
index 0000000..f2b0055
--- /dev/null
+++ b/Source/Genes/Life_Force/UI/GeneGizmo_ResourceLifeForce.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+using UnityEngine;
+namespace RJW_Genes
+{
+ //Copied from GeneGizmo_ResourceHemogen, with small modifications
+ public class GeneGizmo_ResourceLifeForce : GeneGizmo_Resource
+ {
+ public GeneGizmo_ResourceLifeForce(Gene_Resource gene, List drainGenes, Color barColor, Color barhighlightColor) : base(gene, drainGenes, barColor, barhighlightColor)
+ {
+ this.draggableBar = true;
+ }
+
+ public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
+ {
+ return base.GizmoOnGUI(topLeft, maxWidth, parms);
+ }
+
+ protected override string GetTooltip()
+ {
+
+ this.tmpDrainGenes.Clear();
+ string text = string.Format("{0}: {1} / {2}\n", this.gene.ResourceLabel.CapitalizeFirst().Colorize(ColoredText.TipSectionTitleColor), this.gene.ValueForDisplay, this.gene.MaxForDisplay);
+ if (this.gene.pawn.IsColonistPlayerControlled || this.gene.pawn.IsPrisonerOfColony)
+ {
+ if (this.gene.targetValue <= 0f)
+ {
+ text += "NeverSeekFertilin";
+ }
+ else
+ {
+ text = text + ("SeekFertilinBelow" + ": ") + this.gene.PostProcessValue(this.gene.targetValue);
+ }
+ }
+ if (!this.drainGenes.NullOrEmpty())
+ {
+ float num = 0f;
+ foreach (IGeneResourceDrain geneResourceDrain in this.drainGenes)
+ {
+ if (geneResourceDrain.CanOffset)
+ {
+ this.tmpDrainGenes.Add(new Pair(geneResourceDrain, geneResourceDrain.ResourceLossPerDay));
+ num += geneResourceDrain.ResourceLossPerDay;
+ }
+ }
+ if (num != 0f)
+ {
+ string text2 = (num < 0f) ? "RegenerationRate".Translate() : "DrainRate".Translate();
+ text = string.Concat(new string[]
+ {
+ text,
+ "\n\n",
+ text2,
+ ": ",
+ "PerDay".Translate(Mathf.Abs(this.gene.PostProcessValue(num))).Resolve()
+ });
+ foreach (Pair pair in this.tmpDrainGenes)
+ {
+ text = string.Concat(new string[]
+ {
+ text,
+ "\n - ",
+ pair.First.DisplayLabel.CapitalizeFirst(),
+ ": ",
+ "PerDay".Translate(this.gene.PostProcessValue(-pair.Second).ToStringWithSign()).Resolve()
+ });
+ }
+ }
+ }
+ if (!this.gene.def.resourceDescription.NullOrEmpty())
+ {
+ text = text + "\n\n" + this.gene.def.resourceDescription.Formatted(this.gene.pawn.Named("PAWN")).Resolve();
+ }
+ return text;
+ }
+ private List> tmpDrainGenes = new List>();
+ }
+}
diff --git a/Source/Genes/Special/Gene_Aphrodisiac_Pheromones.cs b/Source/Genes/Special/Gene_Aphrodisiac_Pheromones.cs
new file mode 100644
index 0000000..e3628dc
--- /dev/null
+++ b/Source/Genes/Special/Gene_Aphrodisiac_Pheromones.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class Gene_Aphrodisiac_Pheromones : Gene
+ {
+
+ // Default XML Setting is that it looses 4 Severity per day - so a "fully libido" gives 6h boost.
+ // This means that adding +.25 equals 1.5h of Libido.
+ // Tick Speed is hence set to 0.5h
+
+ const int APHRODISIAC_DISTANCE = 25;
+ const int TICK_INTERVAL = 60000 / 48 ; // 60k = 1 day, we want 0.5h which is 1/48th of 1 day.
+
+ const float SEXFREQ_THRESHOLD = 0.5f;
+
+ // Summary: once every one hour check for all pawns nearby and in line of sight (same room) and add/renew a hediff which lasts for 1 hour.
+ public override void Tick()
+ {
+ base.Tick();
+ if (this.pawn.IsHashIntervalTick(TICK_INTERVAL) && this.pawn.Map != null)
+ {
+ // Only spread pheromones if sexdrive above 1
+ float sexfrequency = this.pawn.GetStatValue(StatDef.Named("SexFrequency"));
+ if(sexfrequency > SEXFREQ_THRESHOLD)
+ {
+ foreach (Pawn pawn in this.AffectedPawns(this.pawn.Position, this.pawn.Map))
+ {
+ this.InduceAphrodisiac(pawn);
+ }
+ }
+ }
+ }
+
+ // Creates an IEnumerable of all pawns which are closeby and in lineofsight, self and other pawns with aphrodisiac pheromones gene are skipped (to prevent loops).
+ private IEnumerable AffectedPawns(IntVec3 pos, Map map)
+ {
+ foreach (Pawn pawn in map.mapPawns.AllPawns)
+ {
+ if (pawn != null && this.pawn != null && pawn != this.pawn
+ && pos.DistanceTo(pawn.Position) < APHRODISIAC_DISTANCE && GenSight.LineOfSight(pos, pawn.Position, pawn.Map)
+ && !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_aphrodisiac_pheromones))
+ {
+ yield return pawn;
+ }
+ }
+
+ yield break;
+ }
+
+ private void InduceAphrodisiac(Pawn pawn)
+ {
+ Hediff aphrodisiac = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.rjw_genes_aphrodisiac_pheromone);
+
+ if (aphrodisiac != null)
+ {
+ aphrodisiac.Severity += 0.25f;
+ }
+ else
+ {
+ aphrodisiac = HediffMaker.MakeHediff(HediffDefOf.rjw_genes_aphrodisiac_pheromone, pawn);
+ aphrodisiac.Severity = 0.5f;
+ pawn.health.AddHediff(aphrodisiac);
+ }
+ }
+
+ }
+}
diff --git a/Source/Genes/Special/Patch_AgeDrain.cs b/Source/Genes/Special/Patch_AgeDrain.cs
new file mode 100644
index 0000000..2c7e55d
--- /dev/null
+++ b/Source/Genes/Special/Patch_AgeDrain.cs
@@ -0,0 +1,40 @@
+using HarmonyLib;
+using rjw;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RJW_Genes.Genes.Special
+{
+ [HarmonyPatch(typeof(SexUtility), "Aftersex")]
+ public static class Patch_AgeDrain
+ {
+
+ const long AGE_TRANSFERED = 120000; // 120k == 2 days
+ // 20 Years * 60 Days / Year * 60k Ticks/Day + 1 for safety
+ const long MINIMUM_AGE = 20 * 60 * 60000 + 1;
+
+ // Comment Below in for debugging, changes years
+ // const long AGE_TRANSFERED = 12000000;
+ public static void Postfix(SexProps props)
+ {
+ if (props == null || props.pawn == null || props.partner == null || props.partner.IsAnimal() )
+ {
+ return;
+ }
+ if (GeneUtility.IsAgeDrainer(props.pawn))
+ {
+ var pawnAge = props.pawn.ageTracker.AgeBiologicalTicks;
+ //ModLog.Error($"Firing Age Drain \nMinimum Age is \t{MINIMUM_AGE} \nPawn Age is \t{pawnAge} \nTransferred \t{AGE_TRANSFERED}\nResulting in \t{pawnAge - AGE_TRANSFERED}");
+
+ // Make Partner older
+ props.partner.ageTracker.AgeBiologicalTicks += AGE_TRANSFERED;
+ // Make Pawn younger
+ props.pawn.ageTracker.AgeBiologicalTicks = Math.Max(MINIMUM_AGE, (pawnAge - AGE_TRANSFERED));
+ }
+
+ }
+ }
+}
diff --git a/Source/Genes/Special/Patch_OrgasmRush.cs b/Source/Genes/Special/Patch_OrgasmRush.cs
index 0b881f2..eaf6216 100644
--- a/Source/Genes/Special/Patch_OrgasmRush.cs
+++ b/Source/Genes/Special/Patch_OrgasmRush.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Verse;
namespace RJW_Genes
{
@@ -14,18 +15,51 @@ namespace RJW_Genes
{
private const float REST_INCREASE = 0.05f;
+ private const float ORGASMS_NEEDED_FOR_SUPERCHARGE = 3.0f;
public static void Postfix(SexProps props)
{
- // ShortCuts: Exit Early if Pawn or Partner are null (can happen with Animals or Masturbation)
- if (props.pawn == null || !props.hasPartner())
+ // ShortCuts: Exit Early if Pawn or Partner are null (can happen with Masturbation or other nieche-cases)
+ if (props == null || props.pawn == null || !props.hasPartner())
+ return;
+
+ // Exit for Animals - Animals can't get or trigger Orgasm Rushes. Fixes #15
+ if (props.pawn.IsAnimal() || props.partner.IsAnimal())
return;
if (props.pawn.genes != null && props.pawn.genes.HasGene(GeneDefOf.rjw_genes_orgasm_rush))
{
- props.pawn.needs.rest.CurLevel += REST_INCREASE;
- }
+
+ // Pump up Wake-Ness
+ if (props.pawn.needs.rest != null)
+ props.pawn.needs.rest.CurLevel += REST_INCREASE;
+
+ // Add or Update Hediff for Orgasm Rush
+ Hediff rush = GetOrgasmRushHediff(props.pawn);
+ float added_severity = props.orgasms / ORGASMS_NEEDED_FOR_SUPERCHARGE;
+ rush.Severity += added_severity;
+ // Severity should be capped to 1 by the XML logic
+ }
+
+ }
+
+ ///
+ /// Helps to get the Orgasm Rush Hediff of a Pawn. If it does not exist, one is added.
+ ///
+ /// The pawn that had the orgasm, for which a hediff is looked up or created.
+ ///
+ public static Hediff GetOrgasmRushHediff(Pawn orgasmed)
+ {
+ Hediff orgasmRushHediff = orgasmed.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.rjw_genes_orgasm_rush_hediff);
+ if (orgasmRushHediff == null)
+ {
+ orgasmRushHediff = HediffMaker.MakeHediff(HediffDefOf.rjw_genes_orgasm_rush_hediff, orgasmed);
+ orgasmRushHediff.Severity = 0;
+ orgasmed.health.AddHediff(orgasmRushHediff);
+ }
+ return orgasmRushHediff;
}
}
+
}
diff --git a/Source/Genes/Special/Patch_Youth_Fountain.cs b/Source/Genes/Special/Patch_Youth_Fountain.cs
new file mode 100644
index 0000000..a1a1840
--- /dev/null
+++ b/Source/Genes/Special/Patch_Youth_Fountain.cs
@@ -0,0 +1,44 @@
+using HarmonyLib;
+using rjw;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RJW_Genes.Genes.Special
+{
+ [HarmonyPatch(typeof(SexUtility), "Aftersex")]
+ public static class Patch_Youth_Fountain
+ {
+
+ const long AGE_REDUCTION = 60000; // 60k == 1 day
+ // 20 Years * 60 Days / Year * 60k Ticks/Day + 1 for safety
+ const long MINIMUM_AGE = 20 * 60 * 60000 + 1;
+
+ // Comment Below in for debugging
+ // const long AGE_REDUCTION = 6000000; // 6000k == 100 days
+ public static void Postfix(SexProps props)
+ {
+ if (props == null || props.pawn == null || props.partner == null || props.partner.IsAnimal())
+ {
+ return;
+ }
+ if (GeneUtility.IsYouthFountain(props.pawn))
+ {
+ var partnerAge = props.partner.ageTracker.AgeBiologicalTicks;
+
+ //ModLog.Error($"Firing Youth Fountain \nMinimum Age is \t{MINIMUM_AGE}\t{ticksToYears(MINIMUM_AGE)}y\nPawn Age is \t{partnerAge}\t{ticksToYears(partnerAge)}y \nTransferred \t {AGE_REDUCTION}\t{ticksToYears(AGE_REDUCTION)}y\nResulting in \t{partnerAge - AGE_REDUCTION}\t{ticksToYears(partnerAge - AGE_REDUCTION)}y");
+
+ props.partner.ageTracker.AgeBiologicalTicks = Math.Max(MINIMUM_AGE, partnerAge - AGE_REDUCTION);
+ }
+
+ }
+
+ private static float ticksToYears(long ticks)
+ {
+ return (ticks / 60000f) / 60f;
+ }
+ }
+
+}
diff --git a/Source/HarmonyInit.cs b/Source/HarmonyInit.cs
index 35ffb2e..b0f8295 100644
--- a/Source/HarmonyInit.cs
+++ b/Source/HarmonyInit.cs
@@ -27,6 +27,9 @@ namespace RJW_Genes
// Gene: Generous Donor [Postfix Patch]
harmony.Patch(AccessTools.Method(typeof(LicentiaLabs.CumflationHelper), nameof(LicentiaLabs.CumflationHelper.TransferNutrition)),
postfix: new HarmonyMethod(typeof(Patch_TransferNutrition), nameof(Patch_TransferNutrition.Postfix)));
+ // Gene: CumEater [Postfix Patch]
+ harmony.Patch(AccessTools.Method(typeof(rjw.JobDriver_Sex), nameof(rjw.JobDriver_Sex.ChangePsyfocus)),
+ postfix: new HarmonyMethod(typeof(Patch_SexTicks_ChangePsyfocus), nameof(Patch_SexTicks_ChangePsyfocus.Postfix)));
}
}))();
}
diff --git a/Source/HediffDefOf.cs b/Source/HediffDefOf.cs
new file mode 100644
index 0000000..4d59a41
--- /dev/null
+++ b/Source/HediffDefOf.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ [DefOf]
+ public static class HediffDefOf
+ {
+ public static readonly HediffDef rjw_genes_aphrodisiac_pheromone;
+ public static readonly HediffDef rjw_genes_fertilin_lost;
+ public static readonly HediffDef rjw_genes_succubus_drained;
+ public static readonly HediffDef rjw_genes_orgasm_rush_hediff;
+ public static readonly HediffDef rjw_genes_fertilin_craving;
+ }
+}
diff --git a/Source/Interactions/SuccubusTailjob/CompAbility_SexInteractionRequirements.cs b/Source/Interactions/SuccubusTailjob/CompAbility_SexInteractionRequirements.cs
new file mode 100644
index 0000000..f3b9c26
--- /dev/null
+++ b/Source/Interactions/SuccubusTailjob/CompAbility_SexInteractionRequirements.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+
+namespace RJW_Genes
+{
+ public class CompAbility_SexInteractionRequirements : AbilityComp
+ {
+ public CompProperties_SexInteractionRequirements Props
+ {
+ get
+ {
+ return (CompProperties_SexInteractionRequirements)this.props;
+ }
+ }
+
+
+ }
+}
diff --git a/Source/Interactions/SuccubusTailjob/CompProperties_SexInteractionRequirements.cs b/Source/Interactions/SuccubusTailjob/CompProperties_SexInteractionRequirements.cs
new file mode 100644
index 0000000..3756d7b
--- /dev/null
+++ b/Source/Interactions/SuccubusTailjob/CompProperties_SexInteractionRequirements.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+using rjw;
+using rjw.Modules.Interactions.Defs.DefFragment;
+using rjw.Modules.Interactions.Enums;
+
+namespace RJW_Genes
+{
+ public class CompProperties_SexInteractionRequirements : AbilityCompProperties
+ {
+ public CompProperties_SexInteractionRequirements()
+ {
+ this.compClass = typeof(CompAbility_SexInteractionRequirements);
+ }
+
+ public List tags = new List();
+ public InteractionRequirement dominantRequirement;
+ public InteractionRequirement submissiveRequirement;
+ }
+}
diff --git a/Source/Interactions/SuccubusTailjob/CustomSexInteraction_Helper.cs b/Source/Interactions/SuccubusTailjob/CustomSexInteraction_Helper.cs
new file mode 100644
index 0000000..4e69462
--- /dev/null
+++ b/Source/Interactions/SuccubusTailjob/CustomSexInteraction_Helper.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+using rjw;
+using rjw.Modules.Interactions.Objects;
+using rjw.Modules.Interactions.Helpers;
+using rjw.Modules.Interactions.Enums;
+using rjw.Modules.Interactions.Implementation;
+using rjw.Modules.Interactions.Defs.DefFragment;
+namespace RJW_Genes
+{
+ public class CustomSexInteraction_Helper
+ {
+ public static List GenerateInteractionDefList(Pawn pawn, Pawn pawn2, CompProperties_SexInteractionRequirements sexpropsreq)
+ {
+ List tags = new List();
+ if (pawn2.IsAnimal())
+ {
+ tags.Add(InteractionTag.Animal);
+
+ }
+ else
+ {
+ tags = sexpropsreq.tags;
+ }
+
+ InteractionRequirement dominantRequirement = sexpropsreq.dominantRequirement;
+ InteractionRequirement submissiveRequirement = sexpropsreq.submissiveRequirement;
+ List list = new List();
+ //List a = from interaction in sexinteractions
+ //where InteractionHelper.GetWithExtension(interaction).DominantHasFamily(dominantRequirement.families.)
+ // select interaction;
+
+ //should use where select but dont fully understand that, so I am using this.
+ foreach (InteractionDef interactionDef in SexUtility.SexInterractions)
+ {
+ //Use rjw function to check if the interaction would be valid
+ if (!LewdInteractionValidatorService.Instance.IsValid(interactionDef, pawn, pawn2))
+ {
+ continue;
+ }
+ InteractionWithExtension withExtension = InteractionHelper.GetWithExtension(interactionDef);
+ bool add_interaction = false;
+ //only add interactions which have a correct tag
+ foreach (InteractionTag tag in tags)
+ {
+ if (withExtension.HasInteractionTag(tag))
+ {
+ add_interaction = true;
+ break;
+ }
+ }
+ //In case of failure go to next interaction
+ if (!add_interaction)
+ {
+ continue;
+ }
+ //goes to next interaction if it doesn't have the required genitals
+ if (dominantRequirement != null)
+ {
+ foreach (GenitalFamily genitalFamily in dominantRequirement.families)
+ {
+ if (!withExtension.DominantHasFamily(genitalFamily))
+ {
+ add_interaction = false;
+ break;
+
+ }
+ }
+ if (!add_interaction)
+ {
+ continue;
+ }
+ foreach (GenitalTag tag in dominantRequirement.tags)
+ {
+ if (!withExtension.DominantHasTag(tag))
+ {
+ add_interaction = false;
+ break;
+
+ }
+ }
+ }
+ //goes to next interaction if it doesn't have the required genitals
+ if (submissiveRequirement != null)
+ {
+ foreach (GenitalFamily genitalFamily in submissiveRequirement.families)
+ {
+ if (!withExtension.SubmissiveHasFamily(genitalFamily))
+ {
+ add_interaction = false;
+ break;
+
+ }
+ }
+ if (!add_interaction)
+ {
+ continue;
+ }
+ foreach (GenitalTag tag in submissiveRequirement.tags)
+ {
+ if (!withExtension.SubmissiveHasTag(tag))
+ {
+ add_interaction = false;
+ break;
+
+ }
+
+ }
+ }
+ if (add_interaction)
+ {
+ list.Add(interactionDef);
+ }
+
+ }
+ return list;
+ }
+
+ //Generates a valid interaction for the requirements and assigns sexprops based on that
+ public static SexProps GenerateSexProps(Pawn pawn, Pawn pawn2, CompProperties_SexInteractionRequirements sexpropsreq)
+ {
+ List interactionlist = GenerateInteractionDefList(pawn, pawn2, sexpropsreq);
+ if (!interactionlist.Any())
+ {
+ return null;
+ }
+ InteractionDef dictionaryKey = interactionlist.RandomElement();
+ bool rape = InteractionHelper.GetWithExtension(dictionaryKey).HasInteractionTag(InteractionTag.Rape);
+ SexProps sexProps = new SexProps();
+ sexProps.pawn = pawn;
+ sexProps.partner = pawn2;
+ sexProps.sexType = SexUtility.rjwSextypeGet(dictionaryKey);
+ sexProps.isRape = rape;
+ sexProps.isRapist = rape;
+ sexProps.canBeGuilty = false;
+ sexProps.dictionaryKey = dictionaryKey;
+ sexProps.rulePack = SexUtility.SexRulePackGet(dictionaryKey);
+ return sexProps;
+ }
+ }
+}
diff --git a/Source/Interactions/SuccubusTailjob/DomSuccubusTailCustomRequirementHandler.cs b/Source/Interactions/SuccubusTailjob/DomSuccubusTailCustomRequirementHandler.cs
new file mode 100644
index 0000000..cfa3ebf
--- /dev/null
+++ b/Source/Interactions/SuccubusTailjob/DomSuccubusTailCustomRequirementHandler.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+using rjw.Modules.Interactions;
+using rjw.Modules.Interactions.Internals.Implementation;
+using rjw.Modules.Interactions.Objects;
+using rjw;
+using rjw.Modules.Interactions.Enums;
+
+//Modefied code based of RJW-AI code at https://gitgud.io/Ed86/rjw-ia/-/tree/master/
+namespace RJW_Genes
+{
+ [StaticConstructorOnStartup]
+ public class DomSuccubusTailCustomRequirementHandler : ICustomRequirementHandler
+ {
+ public string HandlerKey
+ {
+ get
+ {
+ return "DomSuccubusTailCustomRequirementHandler";
+ }
+ }
+
+
+ static DomSuccubusTailCustomRequirementHandler()
+ {
+ Register();
+ }
+ public static void Register()
+ {
+ InteractionRequirementService.CustomRequirementHandlers.Add(new DomSuccubusTailCustomRequirementHandler());
+ if (Prefs.DevMode)
+ {
+ Log.Message("DomSuccubusTailCustomRequirementHandler registered: ");
+ }
+ }
+
+ public bool FufillRequirements(InteractionWithExtension interaction, InteractionPawn dominant, InteractionPawn submissive)
+ {
+ if (GeneUtility.HasGeneNullCheck(dominant.Pawn, GeneDefOf.rjw_genes_succubus_tail))
+ {
+ return true;
+ }
+ return false;
+ }
+ //public static readonly StringListDef filter = DefDatabase.GetNamed("DomSuccubusTailFilter");
+ }
+}
diff --git a/Source/Interactions/SuccubusTailjob/GenesPartKindUsageRule.cs b/Source/Interactions/SuccubusTailjob/GenesPartKindUsageRule.cs
new file mode 100644
index 0000000..8e993aa
--- /dev/null
+++ b/Source/Interactions/SuccubusTailjob/GenesPartKindUsageRule.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using rjw;
+using rjw.Modules.Interactions.Contexts;
+using rjw.Modules.Interactions.Enums;
+using rjw.Modules.Interactions.Rules.PartKindUsageRules;
+using rjw.Modules.Shared;
+using Verse;
+
+namespace RJW_Genes.Interactions
+{
+ //Summary//
+ //Set custom preferences for pawn. Gets integrated into rjw by AddtoIPartPreferenceRule in First
+ //Depending on the level of lifeforce increase the chance for using the mouth.
+ public class GenesPartKindUsageRule : IPartPreferenceRule
+ {
+ public IEnumerable> ModifiersForDominant(InteractionContext context)
+ {
+ Pawn pawn = context.Internals.Dominant.Pawn;
+ Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType();
+ if (gene != null)
+ {
+ float weight = 2f;
+ if (gene.Value < gene.MinLevelForAlert)
+ {
+ weight *= 10;
+ }
+ else if (gene.Value < gene.targetValue)
+ {
+ weight *= 2.5f;
+ }
+ if (pawn.genes.HasGene(GeneDefOf.rjw_genes_cum_eater))
+ {
+ yield return new Weighted(weight, LewdablePartKind.Mouth);
+ yield return new Weighted(weight, LewdablePartKind.Beak);
+ }
+
+ if (pawn.genes.HasGene(GeneDefOf.rjw_genes_fertilin_absorber))
+ {
+ yield return new Weighted(weight, LewdablePartKind.Vagina);
+ yield return new Weighted(weight, LewdablePartKind.Anus);
+ }
+ }
+ yield break;
+ }
+
+ public IEnumerable> ModifiersForSubmissive(InteractionContext context)
+ {
+ Pawn pawn = context.Internals.Dominant.Pawn;
+ Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType();
+ if (gene != null)
+ {
+ float weight = 2f;
+ if (gene.Value < gene.MinLevelForAlert)
+ {
+ weight *= 10;
+ }
+ else if (gene.Value < gene.targetValue)
+ {
+ weight *= 2.5f;
+ }
+ yield return new Weighted(weight, LewdablePartKind.Mouth);
+ yield return new Weighted(weight, LewdablePartKind.Beak);
+
+ if (pawn.genes.HasGene(GeneDefOf.rjw_genes_fertilin_absorber))
+ {
+ yield return new Weighted(weight, LewdablePartKind.Vagina);
+ yield return new Weighted(weight, LewdablePartKind.Anus);
+ }
+ }
+ yield break;
+ }
+ }
+}
diff --git a/Source/Interactions/SuccubusTailjob/SubSuccubusTailCustomRequirementHandler.cs b/Source/Interactions/SuccubusTailjob/SubSuccubusTailCustomRequirementHandler.cs
new file mode 100644
index 0000000..9bd8289
--- /dev/null
+++ b/Source/Interactions/SuccubusTailjob/SubSuccubusTailCustomRequirementHandler.cs
@@ -0,0 +1,44 @@
+using Verse;
+using rjw.Modules.Interactions;
+using rjw.Modules.Interactions.Internals.Implementation;
+using rjw.Modules.Interactions.Objects;
+
+//Modified code based of RJW-AI code at https://gitgud.io/Ed86/rjw-ia/-/tree/master/
+namespace RJW_Genes
+{
+ [StaticConstructorOnStartup]
+ public class SubSuccubusTailCustomRequirementHandler : ICustomRequirementHandler
+ {
+ public string HandlerKey
+ {
+ get
+ {
+ return "SubSuccubusTailCustomRequirementHandler";
+ }
+ }
+
+ static SubSuccubusTailCustomRequirementHandler()
+ {
+ Register();
+ }
+ public static void Register()
+ {
+ InteractionRequirementService.CustomRequirementHandlers.Add(new SubSuccubusTailCustomRequirementHandler());
+ if (Prefs.DevMode)
+ {
+ Log.Message("SubSuccubusTailCustomRequirementHandler registered: ");
+ }
+ }
+
+ public bool FufillRequirements(InteractionWithExtension interaction, InteractionPawn dominant, InteractionPawn submissive)
+ {
+ if (GeneUtility.HasGeneNullCheck(submissive.Pawn, GeneDefOf.rjw_genes_succubus_tail))
+ {
+ return true;
+ }
+ return false;
+ }
+ //public static readonly StringListDef filter = DefDatabase.GetNamed("SubSuccubusTailFilter");
+ }
+}
+
diff --git a/Source/JobDefOf.cs b/Source/JobDefOf.cs
new file mode 100644
index 0000000..b077aa3
--- /dev/null
+++ b/Source/JobDefOf.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using RimWorld;
+namespace RJW_Genes
+{
+ [DefOf]
+ public static class JobDefOf
+ {
+ public static readonly JobDef rjw_genes_lifeforce_randomrape;
+ public static readonly JobDef rjw_genes_lifeforce_seduced;
+ public static readonly JobDef sex_on_spot;
+ public static readonly JobDef sex_on_spot_reciever;
+ public static readonly JobDef rjw_genes_flirt;
+ }
+}
diff --git a/Source/RJW_GenesSettings.cs b/Source/RJW_GenesSettings.cs
new file mode 100644
index 0000000..57e7249
--- /dev/null
+++ b/Source/RJW_GenesSettings.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using UnityEngine;
+namespace RJW_Genes
+{
+ public class RJW_GenesSettings : ModSettings
+ {
+ public static void DoWindowContents(Rect inRect)
+ {
+ Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
+ Rect rect = new Rect(0f, 0f, inRect.width - 16f, inRect.height + 300f);
+ //Widgets.BeginScrollView(outRect, ref RJWSettings.scrollPosition, rect, true);
+ Listing_Standard listing_Standard = new Listing_Standard();
+ listing_Standard.maxOneColumn = true;
+ listing_Standard.ColumnWidth = rect.width / 2.05f;
+ listing_Standard.Begin(rect);
+ listing_Standard.Gap(30);
+ listing_Standard.CheckboxLabeled("Sexdemon Visits", ref rjw_genes_sexdemon_visit, "If enabled, incubi and succubi can spawn in through an event.", 0f, 1f);
+ if (rjw_genes_sexdemon_visit)
+ {
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Size matters", ref rjw_genes_sexdemon_join_size_matters, "Incubi and succubi will consider size/tightness of partners genital for deciding if they want to join", 0f, 1f);
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Sexdemon groups", ref rjw_genes_sexdemon_visit_groups, "Multiple sexdemons can spawn during a event", 0f, 1f);
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Succubi", ref rjw_genes_sexdemon_visit_succubi, "Allow incubi to spawn through this even", 0f, 1f);
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Incubi", ref rjw_genes_sexdemon_visit_incubi, "Allow incubi to spawn through this even", 0f, 1f);
+
+ }
+ //listing_Standard.CheckboxLabeled("sexfrenzy", ref sexfrenzy, "disable the effects", 0f, 1f);
+ listing_Standard.Gap(10f);
+ listing_Standard.End();
+ }
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref RJW_GenesSettings.rjw_genes_sexdemon_visit, "rjw_genes_sexdemon_visit", RJW_GenesSettings.rjw_genes_sexdemon_visit, true);
+ Scribe_Values.Look(ref RJW_GenesSettings.rjw_genes_sexdemon_join_size_matters, "rjw_genes_sexdemon_join_size_matters", RJW_GenesSettings.rjw_genes_sexdemon_join_size_matters, true);
+ Scribe_Values.Look(ref RJW_GenesSettings.rjw_genes_sexdemon_visit_groups, "rjw_genes_sexdemon_groups", RJW_GenesSettings.rjw_genes_sexdemon_visit_groups, true);
+ Scribe_Values.Look(ref RJW_GenesSettings.rjw_genes_sexdemon_visit_succubi, "rjw_genes_sexdemon_succubi", RJW_GenesSettings.rjw_genes_sexdemon_visit_succubi, true);
+ Scribe_Values.Look(ref RJW_GenesSettings.rjw_genes_sexdemon_visit_incubi, "rjw_genes_sexdemon_incubi", RJW_GenesSettings.rjw_genes_sexdemon_visit_incubi, true);
+ }
+
+ public static bool rjw_genes_sexdemon_visit = true;
+ public static bool rjw_genes_sexdemon_join_size_matters = true;
+ public static bool rjw_genes_sexdemon_visit_groups = true;
+ public static bool rjw_genes_sexdemon_visit_succubi = true;
+ public static bool rjw_genes_sexdemon_visit_incubi = true;
+
+ }
+}
diff --git a/Source/RJW_GenesSettingsControllercs.cs b/Source/RJW_GenesSettingsControllercs.cs
new file mode 100644
index 0000000..a1f0fef
--- /dev/null
+++ b/Source/RJW_GenesSettingsControllercs.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+using UnityEngine;
+namespace RJW_Genes
+{
+ public class RJW_GenesSettingsControllercs : Mod
+ {
+ public RJW_GenesSettingsControllercs(ModContentPack content) : base(content)
+ {
+ base.GetSettings();
+ }
+
+ public override string SettingsCategory()
+ {
+ return "RJW Genes";
+ }
+ public override void DoSettingsWindowContents(Rect inRect)
+ {
+ RJW_GenesSettings.DoWindowContents(inRect);
+ }
+ }
+}
diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj
index c7b5a48..96bc6f5 100644
--- a/Source/Rjw-Genes.csproj
+++ b/Source/Rjw-Genes.csproj
@@ -22,55 +22,25 @@
false
-
- ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\workshop\content\294100\2009463077\Current\Assemblies\0Harmony.dll
- False
-
-
- ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\Assembly-CSharp.dll
- False
-
-
- ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\RimWorld\Mods\licentia-labs-master\Assemblies\LicentiaLabs.dll
- False
-
-
- ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\RimWorld\Mods\rjw-master\1.4\Assemblies\RJW.dll
- False
-
-
-
-
-
-
-
-
- ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.dll
- False
-
-
- ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll
- False
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -82,6 +52,7 @@
+
@@ -98,6 +69,7 @@
+
@@ -105,6 +77,7 @@
+
@@ -114,15 +87,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ ..\..\..\..\..\workshop\content\294100\2009463077\Current\Assemblies\0Harmony.dll
+ False
+
+
+ False
+ ..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll
+ False
+
+
+ False
+ ..\..\licentia-labs\Assemblies\LicentiaLabs.dll
+ False
+
+
+ False
+ ..\..\rjw\1.4\Assemblies\RJW.dll
+ False
+
+
+ ..\..\RJW-Sexperience\1.4\Assemblies\RJWSexperience.dll
+ False
+
+
+
+ ..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll
+ False
+
+
+ False
+ ..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll
+ False
+
+
+ False
+ ..\..\..\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll
+ False
+
+
\ No newline at end of file
diff --git a/Source/Settings/RJW_Genes_Settings.cs b/Source/Settings/RJW_Genes_Settings.cs
new file mode 100644
index 0000000..71cf028
--- /dev/null
+++ b/Source/Settings/RJW_Genes_Settings.cs
@@ -0,0 +1,74 @@
+using System;
+using Verse;
+using UnityEngine;
+
+namespace RJW_Genes
+{
+ public class RJW_Genes_Settings : ModSettings
+ {
+ public static void DoWindowContents(Rect inRect)
+ {
+ //Copied from RJW settings mostly
+ Rect outRect = new Rect(0f, 30f, inRect.width, inRect.height - 30f);
+ Rect rect = new Rect(0f, 0f, inRect.width - 16f, inRect.height + 300f);
+ //Widgets.BeginScrollView(outRect, ref RJWSettings.scrollPosition, rect, true);
+ Listing_Standard listing_Standard = new Listing_Standard();
+ listing_Standard.maxOneColumn = true;
+ listing_Standard.ColumnWidth = rect.width / 2.05f;
+ listing_Standard.Begin(rect);
+ listing_Standard.Gap(24f);
+ listing_Standard.Label("Fertlin-Gain from Animals" + ": " +
+ Math.Round((double)(RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor * 100f), 0).ToString() + "%", -1f, "of fertilin gained (compared to human-baseline).");
+ RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor = listing_Standard.Slider(RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor, 0f, 3f);
+
+ listing_Standard.Gap(5f);
+ listing_Standard.CheckboxLabeled("Sexdemon Visits", ref rjw_genes_sexdemon_visit, "If enabled, incubi and succubi can spawn in through an event.", 0f, 1f);
+ if (rjw_genes_sexdemon_visit)
+ {
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Size matters", ref rjw_genes_sexdemon_join_size_matters, "Incubi and succubi will consider size/tightness of partners genital for deciding if they want to join", 0f, 1f);
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Sexdemon groups", ref rjw_genes_sexdemon_visit_groups, "Multiple sexdemons can spawn during a event", 0f, 1f);
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Succubi", ref rjw_genes_sexdemon_visit_succubi, "Allow incubi to spawn through this even", 0f, 1f);
+ listing_Standard.Gap(3f);
+ listing_Standard.CheckboxLabeled(" Incubi", ref rjw_genes_sexdemon_visit_incubi, "Allow incubi to spawn through this even", 0f, 1f);
+
+ }
+
+ listing_Standard.Gap(5f);
+ listing_Standard.CheckboxLabeled("generous-donor cheatmode", ref rjw_genes_generous_donor_cheatmode, "When enabled, pawns with the 'generous donor' are not drained and not fertilin exhausted. Hence they can fuel succubi and incubi non-stop. This makes them drastically easier to keep, and you should not do it.", 0f, 1f);
+
+ listing_Standard.Gap(5f);
+ listing_Standard.CheckboxLabeled("detailed-debug", ref rjw_genes_detailed_debug, "Adds detailed information to the log about interactions and genes.", 0f, 1f);
+ listing_Standard.End();
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor, "rjw_genes_fertilin_from_animals_factor", RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor, true);
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_detailed_debug, "rjw_genes_detailed_debug", RJW_Genes_Settings.rjw_genes_detailed_debug, true);
+
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_sexdemon_visit, "rjw_genes_sexdemon_visit", RJW_Genes_Settings.rjw_genes_sexdemon_visit, true);
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_sexdemon_join_size_matters, "rjw_genes_sexdemon_join_size_matters", RJW_Genes_Settings.rjw_genes_sexdemon_join_size_matters, true);
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_sexdemon_visit_groups, "rjw_genes_sexdemon_groups", RJW_Genes_Settings.rjw_genes_sexdemon_visit_groups, true);
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_sexdemon_visit_succubi, "rjw_genes_sexdemon_succubi", RJW_Genes_Settings.rjw_genes_sexdemon_visit_succubi, true);
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi, "rjw_genes_sexdemon_incubi", RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi, true);
+
+ Scribe_Values.Look(ref RJW_Genes_Settings.rjw_genes_generous_donor_cheatmode, "rjw_genes_generous_donor_cheatmode", RJW_Genes_Settings.rjw_genes_generous_donor_cheatmode, true);
+ }
+
+ public static bool rjw_genes_detailed_debug = false;
+ public static float rjw_genes_fertilin_from_animals_factor = 0.1f;
+
+
+ public static bool rjw_genes_sexdemon_visit = true;
+ public static bool rjw_genes_sexdemon_join_size_matters = true;
+ public static bool rjw_genes_sexdemon_visit_groups = true;
+ public static bool rjw_genes_sexdemon_visit_succubi = true;
+ public static bool rjw_genes_sexdemon_visit_incubi = true;
+
+ public static bool rjw_genes_generous_donor_cheatmode = false;
+ }
+}
diff --git a/Source/Settings/RJW_Genes_SettingsController.cs b/Source/Settings/RJW_Genes_SettingsController.cs
new file mode 100644
index 0000000..7236b14
--- /dev/null
+++ b/Source/Settings/RJW_Genes_SettingsController.cs
@@ -0,0 +1,22 @@
+using Verse;
+using UnityEngine;
+
+namespace RJW_Genes
+{
+ public class RJW_Genes_SettingsController : Mod
+ {
+ public RJW_Genes_SettingsController(ModContentPack content) : base(content)
+ {
+ base.GetSettings();
+ }
+
+ public override string SettingsCategory()
+ {
+ return "RJW Genes - General";
+ }
+ public override void DoSettingsWindowContents(Rect inRect)
+ {
+ RJW_Genes_Settings.DoWindowContents(inRect);
+ }
+ }
+}
diff --git a/Source/ThoughtDefOf.cs b/Source/ThoughtDefOf.cs
new file mode 100644
index 0000000..aefcfa8
--- /dev/null
+++ b/Source/ThoughtDefOf.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+namespace RJW_Genes
+{
+ [DefOf]
+ public static class ThoughtDefOf
+ {
+ public static readonly ThoughtDef rjw_genes_cock_eaten;
+ public static readonly ThoughtDef rjw_genes_seduced;
+
+ //Others with same names but other defs than in genedefof
+ public static readonly InteractionDef rjw_genes_flirt;
+ }
+}
diff --git a/TODOS.md b/TODOS.md
index 0dc2a0a..1977952 100644
--- a/TODOS.md
+++ b/TODOS.md
@@ -3,33 +3,30 @@
I have many ideas but not too much time / knowledge of Rimworld or Modding.
So any help is very appreciated, even if it is just pointing me to existing similar projects.
-## Planned Genes
+## Additions to existing things
-**Sanguophage like Cumwhores** adding Hemogen and refilling it by getting semen.
-Showstopper here is the amount of code required, and that I need to understand a bit better of harmony to run the AfterSexUtility and modulate SexChances. My first attempt exploded on adding UI Elements.
+**Cumeater** - Look for edible cum-items when low on Fertilin
+
+**Incubi** - Add a forced striptease Ability
+
+## Planned Genes
**Adjustable Cock-Size** like e.g. artificial genitalia have
**Infectious Hypersexuality Gene** (Maybe?) add Hypersexuality Gene through sex with a certain chance.
-**Cum Addiction** add Cum-Addiction from Sexpererience, slowly loose conciousness while addiction is not attended.
+**Cum Addiction** add Cum-Addiction from Sexperience, slowly loose conciousness while addiction is not attended.
**Cum-Drugs** eating cum has an effect similar to Go-Juice (including (separate?) addiction)
-**More Orgasm Boost** currently only does sleep, other things could be cool here too. Maybe a separate hediff boosting movement or fight.
-
**Self-Fertilizing Eggs** Pawns fertilize eggs that are put inside them (with themselves as a parent)
-## Animal Gene Inheritance
+**Death-Rest** until the pawn is cumflated.
-It should be doable to have a per-category list of genes that a child can inherit on bestiality.
-Just roll for the available genes and add them to the kid.
+## Planned Xenotypes
-Issues:
-
-- I do not know how to access babies genes from pregnancy
-- I did not (yet) find categories in the game such as *canine* or *equine*.
-- To have genes, the baby needs to be non-baseliner to the best of my knowledge (maybe make bestiality babies hybrid)
+- "Beastmaster": Zoophile with various genes to command animals to rape, mate etc. and increased animal "handling".
+- "Hive-Mother": for breeding Insect Armies, maybe it is also possible to "store" small insects in her etc.
## Genes with Abilities and more Effects
@@ -38,11 +35,4 @@ There were some suggestions on the Discord I saved them somewhere else. I am far
- Genitalia deal damage as per size (on normal sex-use)
- Genitalia can cause Terror (as ability)
- Cumshot Sniper Abilities
-- Healing Pussy
-
-## Things to add/change for base-rjw
-
-(Bit dependable on RJW-Core people)
-
-1. Make Racegroup-Defs accessible and non-private [This file here](https://gitgud.io/Ed86/rjw/-/blob/master/1.4/Source/Common/Helpers/RaceGroupDef_Helper.cs)
-2. Make [this](https://gitgud.io/Ed86/rjw/-/blob/master/1.4/Source/Common/Helpers/Gender_Helper.cs#L316) not warn, to reduce errors towards users
\ No newline at end of file
+- Healing Pussy
\ No newline at end of file