diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ce1000..48efc2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +# 1.3.0 + +**Changes:** + +- New Gene for Evergrowing Cocks. Be careful. +- New Gene for Genderfluid Pawns - daily chance to change sex. Futas just change "display" and keep genitalia, other pawns switch genitalia. XML configurable times & chances. +- New Drawings for the Succubi Wings & Tail, thanks to @Monti (donated via Discord) +- Simple Gene that removes Sex need (called asexual, `rjw_genes_no_sex_need`) +- New Gene that grows Penisses on Oral sex. Configurable in XML. +- New Gene Lifeforce Empath: Gain Lifeforce for sexually satisfied pawns, loose for frustrated pawns. +- More genes are configurable with XML, e.g. tick speed, distances or multipliers. I am getting the hang of it. +- Halfed Succubus Fertilin-Need, increased cost of abilities. +- Translation Keys for some letters + +**Fixes:** + +- New attempt at fixing condom consumption for Fertilin, adressing #41 & #48 provided by Infi +- Copy of Infis patch for eating cum from sexperience, #41 and #48 +- Updated some Icons to have better backgrounds (thanks @WasmachenDennSachenSo #53) +- Custom Queen- and Drone-Xenotypes should work now. +- Some more checks if Queen is on Map or not (fixing #60) + +*Notes*: +The pawns that are gender fluid can get pregnant. +However, with RJW 5.3.7 these pregnancies disappear. +This is a change needed upstream, but I will have a look. + # 1.2.1 **Fixes**: diff --git a/Common/Assemblies/Rjw-Genes.dll b/Common/Assemblies/Rjw-Genes.dll index a45e15c..4950b80 100644 Binary files a/Common/Assemblies/Rjw-Genes.dll and b/Common/Assemblies/Rjw-Genes.dll differ diff --git a/Common/Defs/AbilityDefs/Ability_NakedProwess.xml b/Common/Defs/AbilityDefs/Ability_NakedProwess.xml index 778f4d9..292af25 100644 --- a/Common/Defs/AbilityDefs/Ability_NakedProwess.xml +++ b/Common/Defs/AbilityDefs/Ability_NakedProwess.xml @@ -38,7 +38,7 @@
  • - 0.1 + 0.15
  • diff --git a/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml b/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml index 0d8959d..29e1588 100644 --- a/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml +++ b/Common/Defs/AbilityDefs/Ability_ParalysingKiss.xml @@ -37,7 +37,7 @@ rjw_genes_lips
  • - 0.05 + 0.1
  • diff --git a/Common/Defs/AbilityDefs/Ability_PussyHeal.xml b/Common/Defs/AbilityDefs/Ability_PussyHeal.xml index 4445bf2..c31cb75 100644 --- a/Common/Defs/AbilityDefs/Ability_PussyHeal.xml +++ b/Common/Defs/AbilityDefs/Ability_PussyHeal.xml @@ -28,7 +28,7 @@
  • - 0.2 + 0.3
  • 0.4~0.8 diff --git a/Common/Defs/AbilityDefs/Ability_Seduce.xml b/Common/Defs/AbilityDefs/Ability_Seduce.xml index 595c348..d4467e6 100644 --- a/Common/Defs/AbilityDefs/Ability_Seduce.xml +++ b/Common/Defs/AbilityDefs/Ability_Seduce.xml @@ -36,7 +36,7 @@ Heart
  • - 0.1 + 0.20
  • diff --git a/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml b/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml index 8723630..6767e77 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Cosmetic.xml @@ -27,9 +27,9 @@ 1 -1 - Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings + Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings Skin - 2 + 2 (0.0, 0.01, -0.1) (0.0, 0.0, -0.1) (0.1, 0.0, 0.0) @@ -59,14 +59,9 @@ 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
  • -
    + Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail Skin - 2 + 2 (0, 0.2, -0.1) (0, -0.1, 0.1) (0.2, 0.2, 0.1) diff --git a/Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml b/Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml index 5c43285..492aedc 100644 --- a/Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml +++ b/Common/Defs/GeneDefs/GeneDefs_GenitaliaSizes.xml @@ -111,4 +111,26 @@
  • AnusSize
  • + + + + + rjw_genes_evergrowth + + One of the most regretted gene-modifications in the Glitterworlds: The (primary) genitalia will continue growing forever. This affects size and fluid output. Excessive growth can also effect mental stability! (Resizing takes place at 20th Birthday) + Genes/Icons/Big_Male_Genitalia + RJW_Genes.Gene_EvergrowingGenitalia + 767 + +
  • PenisSize
  • +
  • VaginaSize
  • +
    + +
  • + + 60000 +
  • +
    +
    + \ No newline at end of file diff --git a/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml b/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml index 67f0994..8c793e2 100644 --- a/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml +++ b/Common/Defs/GeneDefs/GeneDefs_LifeForce.xml @@ -1,6 +1,18 @@ - + + + rjw_genes_fertilin + + +
  • + Genes/Icons/RJW_Genes_Endogene_Background + Genes/Icons/RJW_Genes_Xenogene_Background +
  • +
    +
    + + rjw_genes_lifeforce 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. @@ -17,7 +29,6 @@ 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 18 @@ -28,43 +39,28 @@
  • fert
  • - 0.05 + 0.025 1 1 - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_lifeforce_drain draining - Carriers lose an additional 15 fertilin per day from biological entropy. + Carriers lose an additional 7.5 fertilin per day from biological entropy. fertilin RJW_Genes.Gene_LifeForceDrain Genes/Icons/FertilinDrainAlt rjw_genes_lifeforce - 0.15 - rjw_genes_fertilin + 0.075 18 -1 1 6 - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_pussyhealing pussyhealer @@ -72,7 +68,6 @@ Genes/Icons/Healpussy rjw_genes_lifeforce 9 - rjw_genes_fertilin
  • rjw_genes_ability_pussyheal
  • @@ -88,16 +83,9 @@
  • heal
  • - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_cockeater cockeater @@ -105,7 +93,6 @@ Genes/Icons/cockeater rjw_genes_lifeforce 11 - rjw_genes_fertilin
  • rjw_genes_ability_cockeater
  • @@ -121,16 +108,9 @@
  • eat
  • - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_paralysingkiss paralysing kiss @@ -138,7 +118,6 @@ Genes/Icons/Paralysing_Kiss rjw_genes_lifeforce 12 - rjw_genes_fertilin
  • rjw_genes_ability_paralysingkiss
  • @@ -153,16 +132,9 @@
  • kiss
  • - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_seduce seduction @@ -170,7 +142,6 @@ Genes/Icons/seduce rjw_genes_lifeforce 13 - rjw_genes_fertilin
  • rjw_genes_ability_seduce
  • @@ -186,23 +157,15 @@
  • kiss
  • - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_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 + 14
  • rjw_genes_ability_naked_prowess
  • @@ -211,67 +174,64 @@ 1 -1 - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_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 - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    - + rjw_genes_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_lifeforce_empath + + RJW_Genes.Gene_LifeForce_Empath + Carriers of this gene generate lifeforce if nearby pawns are sexually satisfied. Be careful: Sexually frustrated pawns will make your empath loose lifeforce! + Genes/Icons/Hypersexual + rjw_genes_lifeforce + 3 + 3 + -2 -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background +
  • + 0.02 + 0.01 + -0.01 +
  • +
  • + + 2500 +
  • +
  • + + 25
  • - - + + rjw_genes_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. Genes/Icons/Vitality_Drainer rjw_genes_lifeforce 4 - rjw_genes_fertilin 1 -1 - - -
  • - Genes/Icons/RJW_Genes_Endogene_Background - Genes/Icons/RJW_Genes_Xenogene_Background -
  • -
    \ No newline at end of file diff --git a/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml b/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml index 7c888cd..12eafe5 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Reproduction.xml @@ -94,4 +94,29 @@ + + + rjw_genes_no_sex_need + + Carriers of this gene do not have a sex-need. They can still participate in sex, + Genes/Icons/Empty + 5 + +
  • Sex
  • +
    + -1 + 2 + + +
  • rjw_genes_sexual_orientation
  • +
    + + +
  • + Genes/Icons/RJW_Genes_Endogene_Background + Genes/Icons/RJW_Genes_Xenogene_Background +
  • +
    +
    + \ No newline at end of file diff --git a/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml b/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml index af6c34f..c3c042f 100644 --- a/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml +++ b/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml @@ -65,6 +65,17 @@ 4 1 1 + + +
  • + + 1250 +
  • +
  • + + 25 +
  • +
    @@ -78,4 +89,24 @@ -5 + + rjw_genes_hormonal_saliva + + The saliva of this xenotype stimulates growth in penises. Regular contact will lead to noticable growth. + 2 + -1 + Genes/Icons/Big_Male_Genitalia + 6 + + +
  • + + 0.02 + 2.5 + + 1.05 +
  • +
    +
    + \ No newline at end of file diff --git a/Common/Defs/GeneDefs/GeneDefs_SpecifiedGender.xml b/Common/Defs/GeneDefs/GeneDefs_SpecifiedGender.xml index fae1f90..d7541e7 100644 --- a/Common/Defs/GeneDefs/GeneDefs_SpecifiedGender.xml +++ b/Common/Defs/GeneDefs/GeneDefs_SpecifiedGender.xml @@ -46,4 +46,36 @@ + + + rjw_genes_gender_fluid + rjw_genes_gender + + Everyday carriers of this gene might change their biological sex. + 0 + Genes/Icons/Futa + RJW_Genes.Gene_GenderFluid + 2 + + + 0.9 + + +
  • AG_Gender
  • +
  • Gender
  • +
    + + +
  • + Genes/Icons/RJW_Genes_Endogene_Background + Genes/Icons/RJW_Genes_Xenogene_Background +
  • +
  • + + 120000 + 0.25 +
  • +
    +
    + \ No newline at end of file diff --git a/Common/Defs/HediffDefs/Hediffs_Evergrowth.xml b/Common/Defs/HediffDefs/Hediffs_Evergrowth.xml new file mode 100644 index 0000000..c2fc098 --- /dev/null +++ b/Common/Defs/HediffDefs/Hediffs_Evergrowth.xml @@ -0,0 +1,52 @@ + + + + + rjw_genes_evergrowth_sideeffect + HediffWithComps + + science has gone too far - a tool like this needs constant attention. + (1,0,0.5) + 1.0 + +
  • + -0.025 +
  • +
    + +
  • + + + 3 + +
  • +
  • + 0.5 + + + 5 + + +
  • + Consciousness + -0.05 +
  • + + +
  • + 0.9 + + + 7 + + +
  • + Consciousness + -0.1 +
  • + + +
    +
    + +
    \ No newline at end of file diff --git a/Common/Languages/English/Keyed/Hive.xml b/Common/Languages/English/Keyed/Hive.xml new file mode 100644 index 0000000..60cff64 --- /dev/null +++ b/Common/Languages/English/Keyed/Hive.xml @@ -0,0 +1,7 @@ + + + + New Queen + A new Queen was born! Make sure to adress inheritance before the new queen reaches adolesence. + + \ No newline at end of file diff --git a/Common/Languages/English/Keyed/Lifeforce.xml b/Common/Languages/English/Keyed/Lifeforce.xml index 5b0520d..9ac9873 100644 --- a/Common/Languages/English/Keyed/Lifeforce.xml +++ b/Common/Languages/English/Keyed/Lifeforce.xml @@ -14,4 +14,7 @@ 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. + + Guest Joins + {0} enjoys it here and has decided to stay. \ No newline at end of file diff --git a/Common/Patches/ThingDefs/RJW_Used_Condoms.xml b/Common/Patches/ThingDefs/RJW_Used_Condoms.xml index d04bcb1..56ae1d2 100644 --- a/Common/Patches/ThingDefs/RJW_Used_Condoms.xml +++ b/Common/Patches/ThingDefs/RJW_Used_Condoms.xml @@ -1,11 +1,19 @@ - - - -
  • RimJobWorld
  • -
    - + + + + Defs/ThingDef[defName="UsedCondom"]/ingestible/outcomeDoers + /Defs/ThingDef[defName="UsedCondom"]/ingestible @@ -14,6 +22,15 @@ + + + Defs/ThingDef[defName="UsedCondom"]/ingestible/outcomeDoers + +
  • + 1 +
  • +
    +
    \ No newline at end of file diff --git a/Common/Patches/ThingDefs/Sexperience_Cum.xml b/Common/Patches/ThingDefs/Sexperience_Cum.xml index b905d4b..5ba06c4 100644 --- a/Common/Patches/ThingDefs/Sexperience_Cum.xml +++ b/Common/Patches/ThingDefs/Sexperience_Cum.xml @@ -1,17 +1,37 @@ - - - -
  • RJW Sexperience
  • -
    + + + + + Defs/ThingDef[defName="GatheredCum"]/ingestible/outcomeDoers + + /Defs/ThingDef[defName="GatheredCum"]/ingestible + + +
  • + 1 +
  • +
    +
    +
    - /Defs/ThingDef[defName="GatheredCum"]/ingestible/outcomeDoers + Defs/ThingDef[defName="GatheredCum"]/ingestible/outcomeDoers
  • - 1 -
  • + 1 +
    +
    \ 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 5061ee5..a9d1786 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 fe6d86e..68396ba 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/Extra_Anus.png b/Common/Textures/Genes/Icons/Extra_Anus.png index 9dfbbb6..6097374 100644 Binary files a/Common/Textures/Genes/Icons/Extra_Anus.png and b/Common/Textures/Genes/Icons/Extra_Anus.png differ diff --git a/Common/Textures/Genes/Icons/Extra_Breasts.png b/Common/Textures/Genes/Icons/Extra_Breasts.png index 5e7cbc3..3247920 100644 Binary files a/Common/Textures/Genes/Icons/Extra_Breasts.png and b/Common/Textures/Genes/Icons/Extra_Breasts.png differ diff --git a/Common/Textures/Genes/Icons/Genitalia_Canine.png b/Common/Textures/Genes/Icons/Genitalia_Canine.png index 7631681..24283b6 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_Demon.png b/Common/Textures/Genes/Icons/Genitalia_Demon.png index d8ace83..e3400e8 100644 Binary files a/Common/Textures/Genes/Icons/Genitalia_Demon.png and b/Common/Textures/Genes/Icons/Genitalia_Demon.png differ diff --git a/Common/Textures/Genes/Icons/Genitalia_Equine.png b/Common/Textures/Genes/Icons/Genitalia_Equine.png index efb9bab..9577293 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/Loose_Anus.png b/Common/Textures/Genes/Icons/Loose_Anus.png index 86036d8..ada02ee 100644 Binary files a/Common/Textures/Genes/Icons/Loose_Anus.png and b/Common/Textures/Genes/Icons/Loose_Anus.png differ diff --git a/Common/Textures/Genes/Icons/No_Anus.png b/Common/Textures/Genes/Icons/No_Anus.png index 69f7d6b..7cfb774 100644 Binary files a/Common/Textures/Genes/Icons/No_Anus.png and b/Common/Textures/Genes/Icons/No_Anus.png differ diff --git a/Common/Textures/Genes/Icons/No_Breasts.png b/Common/Textures/Genes/Icons/No_Breasts.png index 5566734..fd17996 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/No_Male_Genitalia.png b/Common/Textures/Genes/Icons/No_Male_Genitalia.png index 9104ea6..bad56cf 100644 Binary files a/Common/Textures/Genes/Icons/No_Male_Genitalia.png and b/Common/Textures/Genes/Icons/No_Male_Genitalia.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 index 507684a..a15e618 100644 Binary files a/Common/Textures/Genes/Icons/RJW-Genes_Rodent_Genitalia (Not in use now).png 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_Endogene_Background.png b/Common/Textures/Genes/Icons/RJW_Genes_Endogene_Background.png index 9973e24..5d8b0e0 100644 Binary files a/Common/Textures/Genes/Icons/RJW_Genes_Endogene_Background.png and b/Common/Textures/Genes/Icons/RJW_Genes_Endogene_Background.png differ diff --git a/Common/Textures/Genes/Icons/RJW_Genes_Xenogene_Background.png b/Common/Textures/Genes/Icons/RJW_Genes_Xenogene_Background.png index f902c39..b3b359e 100644 Binary files a/Common/Textures/Genes/Icons/RJW_Genes_Xenogene_Background.png and b/Common/Textures/Genes/Icons/RJW_Genes_Xenogene_Background.png differ diff --git a/Common/Textures/Genes/Icons/Small_Breasts.png b/Common/Textures/Genes/Icons/Small_Breasts.png index b32f1d3..e2005b7 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 b4d7194..19924d2 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 index cc86056..afe26f7 100644 Binary files a/Common/Textures/Genes/Icons/Succubus_Tail.png 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 index 0665f1a..62453b0 100644 Binary files a/Common/Textures/Genes/Icons/Succubus_Wings.png and b/Common/Textures/Genes/Icons/Succubus_Wings.png differ diff --git a/Common/Textures/Genes/Icons/Tight_Anus.png b/Common/Textures/Genes/Icons/Tight_Anus.png index 0e797de..dd57b1d 100644 Binary files a/Common/Textures/Genes/Icons/Tight_Anus.png and b/Common/Textures/Genes/Icons/Tight_Anus.png differ diff --git a/Common/Textures/Genes/Icons/Zoophile.png b/Common/Textures/Genes/Icons/Zoophile.png index 75afdf4..a31c470 100644 Binary files a/Common/Textures/Genes/Icons/Zoophile.png and b/Common/Textures/Genes/Icons/Zoophile.png differ diff --git a/Common/Textures/Genes/Icons/cockeater.png b/Common/Textures/Genes/Icons/cockeater.png index fa9577b..0b60a46 100644 Binary files a/Common/Textures/Genes/Icons/cockeater.png and b/Common/Textures/Genes/Icons/cockeater.png differ diff --git a/Common/Textures/Genes/Icons/extra_male.png b/Common/Textures/Genes/Icons/extra_male.png index c39e163..743ae44 100644 Binary files a/Common/Textures/Genes/Icons/extra_male.png and b/Common/Textures/Genes/Icons/extra_male.png differ diff --git a/Common/Textures/Genes/Icons/rjw_naked_prowess.png b/Common/Textures/Genes/Icons/rjw_naked_prowess.png index 468fc60..d54231c 100644 Binary files a/Common/Textures/Genes/Icons/rjw_naked_prowess.png and b/Common/Textures/Genes/Icons/rjw_naked_prowess.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_east.png new file mode 100644 index 0000000..dc01479 Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_east.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_north.png new file mode 100644 index 0000000..eb5780a Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_north.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_south.png new file mode 100644 index 0000000..8e5e4de Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Tail/RJW_Genes_Succubus_Tail_south.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_east.png new file mode 100644 index 0000000..0e193da Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_east.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_north.png new file mode 100644 index 0000000..37ba8fb Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_north.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_south.png new file mode 100644 index 0000000..62453b0 Binary files /dev/null and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/RJW_Genes_Succubus_Wings/RJW_Genes_Succubus_Wings_south.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/deprecated_rjw_genes_succubus/Succubus_Tail_L1_east.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_east.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_L1_east.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_L1_north.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_north.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_L1_north.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_L1_south.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L1_south.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_L1_south.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_L2_east.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_east.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_L2_east.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_L2_north.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_north.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_L2_north.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_L2_south.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_L2_south.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_L2_south.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_R1_east.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_east.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_R1_east.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_R1_north.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_north.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_R1_north.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_R1_south.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R1_south.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_R1_south.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_R2_east.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_east.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_R2_east.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_R2_north.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_north.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_R2_north.png 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/deprecated_rjw_genes_succubus/Succubus_Tail_R2_south.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Tail/Succubus_Tail_R2_south.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Tail_R2_south.png diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Wings_east.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Wings_east.png diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Wings_north.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Wings_north.png diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Wings_south.png similarity index 100% rename from Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png rename to Common/Textures/Things/Pawn/Humanlike/BodyAttachments/deprecated_rjw_genes_succubus/Succubus_Wings_south.png diff --git a/Source/Common/Defs/DistanceExtension.cs b/Source/Common/Defs/DistanceExtension.cs new file mode 100644 index 0000000..8bdd083 --- /dev/null +++ b/Source/Common/Defs/DistanceExtension.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + + /// + /// Small Extension that covers distances for Genes. + /// This allows to set distance in the XMLs. + /// The distance is measured in tiles, so a distance of ~25 means 25 tiles away from the pawn in any direction. + /// + public class DistanceExtension : DefModExtension + { + public int distance; + } +} \ No newline at end of file diff --git a/Source/Common/Defs/ModExtensionHelper.cs b/Source/Common/Defs/ModExtensionHelper.cs new file mode 100644 index 0000000..d75fc12 --- /dev/null +++ b/Source/Common/Defs/ModExtensionHelper.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + internal class ModExtensionHelper + { + + public static int GetDistanceFromModExtension(GeneDef defOf, int fallback) + { + DistanceExtension distanceExt = defOf.GetModExtension(); + + int potentialDistance = distanceExt?.distance ?? fallback; + + if (potentialDistance > 0) + { + return potentialDistance; + } else { + ModLog.Warning($"Retrieved a bad distance ({potentialDistance}) reading the RJW_Genes.DistanceExtension for {defOf.defName}"); + return 1; + } + } + + + public static int GetTickIntervalFromModExtension(GeneDef defOf, int fallback) + { + TickIntervalExtension tickExt = defOf.GetModExtension(); + + int potentialTickInterval = tickExt?.tickInterval ?? fallback; + + if (potentialTickInterval > 0) + { + return potentialTickInterval; + } + else + { + ModLog.Warning($"Retrieved a bad distance ({potentialTickInterval}) reading the RJW_Genes.DistanceExtension for {defOf.defName}"); + return 1; + } + } + + + } +} diff --git a/Source/Common/Defs/TickIntervalExtension.cs b/Source/Common/Defs/TickIntervalExtension.cs new file mode 100644 index 0000000..3e8184c --- /dev/null +++ b/Source/Common/Defs/TickIntervalExtension.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + /// + /// General DefModExtension to cover various genes that need to tick regularly. + /// Defining it like this allows to adjust things in XML. + /// + public class TickIntervalExtension : DefModExtension + { + public int tickInterval; + } +} diff --git a/Source/Common/Either.cs b/Source/Common/Either.cs new file mode 100644 index 0000000..dcd6dd8 --- /dev/null +++ b/Source/Common/Either.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RJW_Genes +{ + public class Either + { + public readonly TL left; + public readonly TR right; + public readonly bool isLeft; + + public Either(TL left) + { + this.left = left; + this.isLeft = true; + } + + public Either(TR right) + { + this.right = right; + this.isLeft = false; + } + } + +} diff --git a/Source/GeneDefOf.cs b/Source/GeneDefOf.cs index 1bc9770..f016e97 100644 --- a/Source/GeneDefOf.cs +++ b/Source/GeneDefOf.cs @@ -32,9 +32,10 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_extra_anus; public static readonly GeneDef rjw_genes_no_anus; public static readonly GeneDef rjw_genes_futa; + public static readonly GeneDef rjw_genes_featureless_chest; - // Genitalia Sizes - public static readonly GeneDef rjw_genes_big_male_genitalia; + // Genitalia Sizes + public static readonly GeneDef rjw_genes_big_male_genitalia; public static readonly GeneDef rjw_genes_small_male_genitalia; public static readonly GeneDef rjw_genes_loose_female_genitalia; public static readonly GeneDef rjw_genes_tight_female_genitalia; @@ -42,10 +43,12 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_small_breasts; public static readonly GeneDef rjw_genes_loose_anus; public static readonly GeneDef rjw_genes_tight_anus; + public static readonly GeneDef rjw_genes_evergrowth; // Gender public static readonly GeneDef rjw_genes_female_only; public static readonly GeneDef rjw_genes_male_only; + public static readonly GeneDef rjw_genes_gender_fluid; // Breeding public static readonly GeneDef rjw_genes_mechbreeder; @@ -66,6 +69,7 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_rapist; public static readonly GeneDef rjw_genes_homosexual; public static readonly GeneDef rjw_genes_bisexual; + public static readonly GeneDef rjw_genes_no_sex_need; // Damage & Side Effects [MayRequire("LustLicentia.RJWLabs")] public static readonly GeneDef rjw_genes_elasticity; @@ -77,6 +81,7 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_sex_age_drain; public static readonly GeneDef rjw_genes_aphrodisiac_pheromones; public static readonly GeneDef rjw_genes_sexual_mytosis; + public static readonly GeneDef rjw_genes_hormonal_saliva; // LifeForce public static readonly GeneDef rjw_genes_lifeforce; @@ -88,9 +93,10 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_seduce; public static readonly GeneDef rjw_genes_paralysingkiss; public static readonly GeneDef rjw_genes_cockeater; + public static readonly GeneDef rjw_genes_lifeforce_empath; - // Cosmetic - public static readonly GeneDef rjw_genes_succubus_tail; + // Cosmetic + public static readonly GeneDef rjw_genes_succubus_tail; public static readonly GeneDef rjw_genes_succubus_wings; // Hive diff --git a/Source/Genes/Gender/Defs/GenderFluidExtension.cs b/Source/Genes/Gender/Defs/GenderFluidExtension.cs new file mode 100644 index 0000000..332015f --- /dev/null +++ b/Source/Genes/Gender/Defs/GenderFluidExtension.cs @@ -0,0 +1,20 @@ +using Verse; + +namespace RJW_Genes +{ + public class GenderFluidExtension : DefModExtension + { + /// + /// Number of ticks until the change can be triggered. + /// Just being "triggered" does not mean changing, see the changeChance below. + /// + public int changeInterval; + + /// + /// How high is the chance to change gender? + /// Set to 1 for "always", set to 0 for "never". + /// Everything else is a bit statistics, but e.g. when set to .5 the chances grow per day from [50%, 75%, 82.25%, ...] + /// + public float changeChance; + } +} \ No newline at end of file diff --git a/Source/Genes/Gender/GenderUtility.cs b/Source/Genes/Gender/GenderUtility.cs index 10b811d..700f3c9 100644 --- a/Source/Genes/Gender/GenderUtility.cs +++ b/Source/Genes/Gender/GenderUtility.cs @@ -31,7 +31,8 @@ namespace RJW_Genes } /// - /// Adjusts the Body Type to match the given target gender + /// Adjusts the Body Type to match the given target gender. + /// This is only for "drawing" attributes of the pawn, the genitalia are untouched at this point. /// (for male and female only, baby,child and hulks don't change) /// /// diff --git a/Source/Genes/Gender/Gene_GenderFluid.cs b/Source/Genes/Gender/Gene_GenderFluid.cs new file mode 100644 index 0000000..1ffdf20 --- /dev/null +++ b/Source/Genes/Gender/Gene_GenderFluid.cs @@ -0,0 +1,276 @@ +using HarmonyLib; +using RimWorld; +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using Verse.AI; + +namespace RJW_Genes +{ + + /* + * Once per day (or slightly different per configuration) checks if the pawn changes gender. + * At the triggered tick, there is a random chance to change gender. + * This will swap genitalia, appearance and breasts. + * + * For some situations, the pawn better not change genitalia, e.g. while having vaginal sex. This would throw errors. + * For these cases a check is implemented, and if there was a block the change happens a bit later when "unblocked". + * + * TODO: Keep pregnancies. + * The pregnancies remove their things on Tick at the end, which kills it for male pawns. + * This seems to be an upstream RJW thing, but needs a bit of investigation. + */ + public class Gene_GenderFluid : RJW_Gene + { + + //public const int CHANGE_INTERVAL_FALLBACK = 1000; // Test value for Quick Trials + const int CHANGE_INTERVAL_FALLBACK = 60000; // 60k == 1 day + const float SWITCH_CHANCE_FALLBACK = 0.25f; + + int change_interval; + float switch_chance; + + List storedBreasts = new List(); + + private bool sexChangeWasBlocked = false; + + public Gene_GenderFluid() : base() { + GenderFluidExtension genderFluidExt = GeneDefOf.rjw_genes_gender_fluid.GetModExtension(); + change_interval = genderFluidExt?.changeInterval ?? CHANGE_INTERVAL_FALLBACK; + switch_chance = genderFluidExt?.changeChance ?? SWITCH_CHANCE_FALLBACK; + } + + public override void Tick() + { + base.Tick(); + + // Case 1: We had a blocked SexChange, now Pawn is free, apply sexchange a bit delayed. + if (pawn.IsHashIntervalTick(1500) && sexChangeWasBlocked && !SexChangeBlocked(pawn)){ + ChangeSex(); + sexChangeWasBlocked = false; + } + // Case 2: Check every interval if the Chance triggers + else if (pawn.IsHashIntervalTick(change_interval) && (new Random()).NextDouble() < switch_chance) + { + + // Case 2.A) SexChange was blocked, postpone it + if (SexChangeBlocked(pawn)) + { + sexChangeWasBlocked |= true; + return; + } + // Case 2.B) Nothing blocking, change the sex. + else { ChangeSex();} + } + + } + + private void ChangeSex() + { + if (rjw.Genital_Helper.is_futa(pawn)) + { + // Handle Futa Pawns - Keep Genitalia as is, just change RW Gender + pawn.gender = pawn.gender == Gender.Male? Gender.Female: Gender.Male; + } + // Handle Non-Futas - Change Genitalia and Store breasts. + else + { + if (pawn.gender == Gender.Female) + { + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"genderfluid pawn {pawn} is changing from female to male"); + SwitchToMale(); + } + else if (pawn.gender == Gender.Male) + { + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"genderfluid pawn {pawn} is changing from male to female"); + SwitchToFemale(); + } + } + GenderUtility.RemoveAllSexChangeThoughts(pawn); + } + + private void SwitchToFemale() + { + // Change Drawing + GenderUtility.AdjustBodyToTargetGender(pawn, Verse.Gender.Female); + // Change Gender + pawn.gender = Verse.Gender.Female; + + // Switch Penisses to Vaginas + var genitalsToRemove = pawn.GetGenitalsList().FindAll(g => Genital_Helper.is_penis(g) || Genital_Helper.is_vagina(g)); + foreach (var genital in genitalsToRemove) + { + var genitaliaHediffDef = GenitaliaUtility.GetVaginaForGene(GenitaliaUtility.GetGenitaliaTypeGeneForPawn(pawn)); + float size = genital.Severity; + pawn.health.RemoveHediff(genital); + + var newVagina = HediffMaker.MakeHediff(genitaliaHediffDef, pawn, Genital_Helper.get_genitalsBPR(pawn)); + pawn.health.AddHediff(newVagina); + newVagina.Severity = size; + } + + SwitchBreasts(); + } + + private void SwitchToMale() + { + // Change Drawing + GenderUtility.AdjustBodyToTargetGender(pawn, Verse.Gender.Male); + // Change Gender + pawn.gender = Verse.Gender.Male; + + // Switch Vaginas to Penisses + var genitalsToRemove = pawn.GetGenitalsList().FindAll(g => Genital_Helper.is_penis(g) || Genital_Helper.is_vagina(g)); + foreach (var genital in genitalsToRemove) + { + var genitaliaHediffDef = GenitaliaUtility.GetPenisForGene(GenitaliaUtility.GetGenitaliaTypeGeneForPawn(pawn)); + float size = genital.Severity; + pawn.health.RemoveHediff(genital); + + var newPenis = HediffMaker.MakeHediff(genitaliaHediffDef, pawn, Genital_Helper.get_genitalsBPR(pawn)); + pawn.health.AddHediff(newPenis); + newPenis.Severity = size; + } + + SwitchBreasts(); + + RemoveLicentiaVaginaHediffs(); + } + + + private void SwitchBreasts() + { + List current_breasts = pawn.GetBreastList(); + + // Stored_Breasts can be empty when the pawn first ever switches gender! + if (storedBreasts.NullOrEmpty()) + { + foreach (var breasts in current_breasts) + { + // Is Male, and does not have the "no breast gene" + if (pawn.gender == Gender.Male && !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_no_breasts)) + { + storedBreasts.Add(CreateNewBreasts()); + } + else if (pawn.gender == Gender.Female && !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_featureless_chest) ) + { + storedBreasts.Add(CreateNewBreasts()); + } + } + } + + + foreach (var breast in current_breasts) + { + pawn.health.RemoveHediff(breast); + } + foreach (var breast in storedBreasts) + { + pawn.health.AddHediff(breast); + } + + storedBreasts.Clear(); + storedBreasts.AddRange(current_breasts); + } + + + internal Hediff CreateNewBreasts() + { + var correctGene = GenitaliaUtility.GetGenitaliaTypeGeneForPawn(pawn); + var breastDef = GenitaliaUtility.GetBreastsForGene(correctGene); + var partBPR = Genital_Helper.get_breastsBPR(pawn); + var additional_breasts = HediffMaker.MakeHediff(breastDef, pawn,partBPR); + + var CompHediff = additional_breasts.TryGetComp(); + if (CompHediff != null) + { + CompHediff.initComp(pawn); + CompHediff.updatesize(); + } + + return additional_breasts; + } + + /// + /// Checks the pawn if it has any of the vagina-related hediffs (e.g. stretched) and removes them. + /// Anal Soreness, Stretching etc. remains. + /// + private void RemoveLicentiaVaginaHediffs() + { + try + { + if (ModsConfig.IsActive("LustLicentia.RJWLabs")){ + Hediff cumflation = pawn.health.hediffSet.GetFirstHediffOfDef(LicentiaLabs.Licentia.HediffDefs.Cumflation); + if (cumflation != null) + pawn.health.RemoveHediff(cumflation); + + Hediff stretched = pawn.health.hediffSet.GetFirstHediffOfDef(LicentiaLabs.Licentia.HediffDefs.Stretched); + if (stretched != null && stretched.Part != Genital_Helper.get_anusBPR(pawn)) + pawn.health.RemoveHediff(stretched); + + Hediff torn = pawn.health.hediffSet.GetFirstHediffOfDef(LicentiaLabs.Licentia.HediffDefs.StretchTear); + if (torn != null && torn.Part != Genital_Helper.get_anusBPR(pawn)) + pawn.health.RemoveHediff(torn); + + Hediff prolapsed = pawn.health.hediffSet.GetFirstHediffOfDef(LicentiaLabs.Licentia.HediffDefs.Prolapse); + if (prolapsed != null && prolapsed.Part != Genital_Helper.get_anusBPR(pawn)) + pawn.health.RemoveHediff(prolapsed); + + Hediff extremeProlapsed = pawn.health.hediffSet.GetFirstHediffOfDef(LicentiaLabs.Licentia.HediffDefs.ExtremeProlapse); + if (extremeProlapsed != null && extremeProlapsed.Part != Genital_Helper.get_anusBPR(pawn)) + pawn.health.RemoveHediff(extremeProlapsed); + }; + } + //TODO: Don't make this an "catch all" Exception! + catch (Exception ex) + { + // To be expected for people without Licentia Labs, do nothing. + } + } + + + /// + /// There are some actions that block sex change, + /// being drafted or having sex. + /// + /// The pawn that want to sexchange. + /// False if the SexChange is applicable, True if there needs to be a wait timer. + internal bool SexChangeBlocked(Pawn pawn) + { + // DEVNOTE: This list might extend on new cases, thus the explicit method. + return pawn == null + || pawn.health.Dead + || (pawn.jobs.curDriver is JobDriver_Masturbate) + || (pawn.jobs.curDriver is JobDriver_Sex) + || (pawn.jobs.curDriver is JobDriver_SexBaseReciever) + || (pawn.jobs.curDriver is JobDriver_SexBaseInitiator) + || (pawn.jobs.curDriver is JobDriver_JoinInBed) + + || (pawn.jobs.curDriver is JobDriver_SexQuick) + || (pawn.jobs.curDriver is JobDriver_SexBaseRecieverQuickie) + || (pawn.jobs.curDriver is JobDriver_SexOnSpot) + || (pawn.jobs.curDriver is JobDriver_SexOnSpotReciever) + + || (pawn.jobs.curDriver is JobDriver_Knotted) + || (pawn.jobs.curDriver is JobDriver_Mate) + || (pawn.jobs.curDriver is JobDriver_Mating) + || (pawn.jobs.curDriver is JobDriver_Breeding) + + || (pawn.jobs.curDriver is JobDriver_Rape) + || (pawn.jobs.curDriver is JobDriver_SexBaseRecieverRaped) + || (pawn.jobs.curDriver is JobDriver_RandomRape) + || (pawn.jobs.curDriver is JobDriver_RapeComfortPawn) + || (pawn.jobs.curDriver is JobDriver_RapeEnemy) + || pawn.jobs.curDriver is JobDriver_Lovin + + // This is a heavy check, but this is necessary because sometimes the pawns go somewhere to have sex and then they start despite missing genitalia! + || (pawn.jobs.curDriver is JobDriver_Goto) + + || pawn.Drafted; + } + } +} diff --git a/Source/Genes/GenitaliaSize/Gene_EvergrowingGenitalia.cs b/Source/Genes/GenitaliaSize/Gene_EvergrowingGenitalia.cs new file mode 100644 index 0000000..cbb37a9 --- /dev/null +++ b/Source/Genes/GenitaliaSize/Gene_EvergrowingGenitalia.cs @@ -0,0 +1,113 @@ +using Verse; +using Verse; +using RimWorld; +using rjw; +using System.Collections.Generic; +using System; + +namespace RJW_Genes +{ + public class Gene_EvergrowingGenitalia : RJW_Gene + { + + /// + /// The age (in years) at which the Pawns Genes will take effect, resizing their genitalia. + /// + public const int RESIZING_AGE = 20; + + //public const int GROWTH_INTERVAL = 1000; // Test value for Quick Trials + public const int GROWTH_INTERVAL_FALLBACK = 60000; // 60k == 1 day + + public override void Tick() + { + base.Tick(); + + int interval = ModExtensionHelper.GetTickIntervalFromModExtension(GeneDefOf.rjw_genes_evergrowth, GROWTH_INTERVAL_FALLBACK); + if (pawn.IsHashIntervalTick(interval) + && this.pawn.Map != null + && pawn.ageTracker.AgeBiologicalYears >= RESIZING_AGE) + { + GrowPenisses(); + GrowVaginas(); + } + } + + private void GrowPenisses() + { + List AllPenisses = Genital_Helper.get_AllPartsHediffList(pawn).FindAll(x => Genital_Helper.is_penis(x)); + foreach(Hediff penis in AllPenisses) + { + CompHediffBodyPart CompHediff = penis.TryGetComp(); + if (penis.Severity < 1.00) + { + penis.Severity = Math.Min(1.01f, penis.Severity + 0.05f); + } else { + if (CompHediff != null) + { + CompHediff.SizeOwner += 0.015f; + if (CompHediff.SizeOwner > 3.0f) + { + // Add Mental Hediff + HandleGenitaliaSizeThoughts(pawn); + } + } + } + + // Increase Fluid + if (CompHediff != null) + CompHediff.FluidAmmount *= 1.05f; + } + } + + private void GrowVaginas() + { + List AllVaginas = Genital_Helper.get_AllPartsHediffList(pawn).FindAll(x => Genital_Helper.is_vagina(x)); + foreach (Hediff vagina in AllVaginas) + { + CompHediffBodyPart CompHediff = vagina.TryGetComp(); + if (vagina.Severity < 1.00) + { + vagina.Severity = Math.Min(1.01f, vagina.Severity + 0.05f); + } + else + { + if (CompHediff != null) + { + CompHediff.SizeOwner += 0.015f; + if (CompHediff.SizeOwner > 3.0f) + { + // Add Mental Hediff + HandleGenitaliaSizeThoughts(pawn); + } + } + } + + // Increase Fluid + if (CompHediff != null) + CompHediff.FluidAmmount *= 1.025f; + } + } + + private void HandleGenitaliaSizeThoughts(Pawn pawn) + { + Hediff hybridsThoughts = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.rjw_genes_evergrowth_sideeffect); + + if (hybridsThoughts != null) + { + hybridsThoughts.Severity += 0.025f; + } + else + { + hybridsThoughts = HediffMaker.MakeHediff(HediffDefOf.rjw_genes_evergrowth_sideeffect, pawn); + hybridsThoughts.Severity = 0.1f; + pawn.health.AddHediff(hybridsThoughts); + + if (!xxx.is_nympho(pawn)) + { + pawn.story.traits.GainTrait(new Trait(xxx.nymphomaniac)); + } + } + } + + } +} \ No newline at end of file diff --git a/Source/Genes/Hive/Helpers/HiveBirthLogic.cs b/Source/Genes/Hive/Helpers/HiveBirthLogic.cs index 8bb1600..a706ea7 100644 --- a/Source/Genes/Hive/Helpers/HiveBirthLogic.cs +++ b/Source/Genes/Hive/Helpers/HiveBirthLogic.cs @@ -1,4 +1,5 @@ using RimWorld; +using rjw; using System; using System.Collections; using System.Collections.Generic; @@ -30,9 +31,9 @@ namespace RJW_Genes /// /// The pawn born, that maybe becomes a hive-xenotype. /// whether there was a drone parent involved - public static void ManageHiveBirth(Pawn pawn, bool hasDroneParent = false, XenotypeDef fallbackQueenDef = null, XenotypeDef fallbackDroneDef = null) + public static void ManageHiveBirth(Pawn pawn, bool hasDroneParent = false, Either fallbackQueenDef = null, Either fallbackDroneDef = null) { - XenotypeDef queenDef = TryFindParentQueenXenotype(pawn); + Either queenDef = TryFindParentQueenXenotype(pawn); if (queenDef == null) queenDef = fallbackQueenDef; HiveOffspringChanceDef hiveOffspringChanceDef = HiveUtility.LookupHiveInheritanceChances(queenDef); @@ -49,17 +50,15 @@ namespace RJW_Genes // Case 2.a: New Queen born if (roll < hiveOffspringChanceDef.queenChance) { - pawn.genes.SetXenotype(queenDef); - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new queen with xenotype {queenDef.defName} ({hiveOffspringChanceDef.queenChance * 100}% chance,rolled {roll})"); - MakeQueenBornLetter(pawn); + MakeQueen(pawn, queenDef); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Queen Chance: {hiveOffspringChanceDef.queenChance * 100}% chance,rolled { roll}"); } // Case 2.b: New Drone born else if (roll < hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) { - XenotypeDef droneDef = TryFindParentDroneXenotype(pawn); - if (droneDef == null) droneDef = fallbackDroneDef; - pawn.genes.SetXenotype(droneDef); - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new drone with xenotype {droneDef.defName} ({(hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) * 100}% chance,rolled {roll}))"); + var droneDef = TryFindParentDroneXenotype(pawn); + MakeDrone(pawn,droneDef); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Drone Chance ({(hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) * 100}% chance,rolled {roll}))"); } // Case 2.c: Worker else @@ -70,6 +69,52 @@ namespace RJW_Genes } } + private static void MakeQueen(Pawn pawnToBeQueen, Either queenDef) { + if (queenDef == null && pawnToBeQueen == null) + return; + if (queenDef.isLeft) { + var xenotype = queenDef.left; + pawnToBeQueen.genes.SetXenotype(xenotype); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawnToBeQueen} born as a new queen with Xenotype {xenotype.defName}"); + } else { + var customXenotype = queenDef.right; + + foreach (var gene in customXenotype.genes) + pawnToBeQueen.genes.AddGene(gene, true); + + pawnToBeQueen.genes.xenotypeName = customXenotype.name; + pawnToBeQueen.genes.iconDef = customXenotype.iconDef; + + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawnToBeQueen} born as a new queen with custom Xenotype {customXenotype.name}"); + } + + MakeQueenBornLetter(pawnToBeQueen); + } + + + private static void MakeDrone(Pawn pawnToBeDrone, Either droneDef) + { + if (droneDef == null && pawnToBeDrone == null) + return; + if (droneDef.isLeft) + { + var xenotype = droneDef.left; + pawnToBeDrone.genes.SetXenotype(xenotype); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawnToBeDrone} born as a new drone with Xenotype {xenotype.defName}"); + } + else + { + var customXenotype = droneDef.right; + + foreach (var gene in customXenotype.genes) + pawnToBeDrone.genes.AddGene(gene, true); + + pawnToBeDrone.genes.xenotypeName = customXenotype.name; + pawnToBeDrone.genes.iconDef = customXenotype.iconDef; + + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawnToBeDrone} born as a new drone with custom Xenotype {customXenotype.name}"); + } + } /// /// Turns a given pawn into a worker, by looking up the relevant genes as per queen. @@ -79,14 +124,19 @@ namespace RJW_Genes /// /// The pawn for which the genes are added. /// The xenotype of the queen, used for lookup. - private static void MakeWorker(Pawn pawnTobeWorker, XenotypeDef queenDef) + private static void MakeWorker(Pawn pawnTobeWorker, Either queenDef) { if (pawnTobeWorker == null) return; var mappings = HiveUtility.GetQueenWorkerMappings(); + String queenDefName = HiveUtility.GetXenotypeDefName(queenDef); + if (queenDef == null || mappings.NullOrEmpty()) + return; - var genes = mappings.TryGetValue(queenDef, HiveUtility.LookupDefaultWorkerGenes()); + var genes = mappings.TryGetValue(queenDefName, HiveUtility.LookupDefaultWorkerGenes()); + if (genes == null) + return; foreach (var gene in genes) pawnTobeWorker.genes.AddGene(gene, false); @@ -101,7 +151,7 @@ namespace RJW_Genes /// /// The pawn for whichs parent the xenotypes is looked up. /// The Drone-Xenotype of a parent or null. If both are drones, mothers are preferred. - public static XenotypeDef TryFindParentDroneXenotype(Pawn pawn) + public static Either TryFindParentDroneXenotype(Pawn pawn) { if (pawn == null) return null; @@ -109,7 +159,7 @@ namespace RJW_Genes List parentRelations = pawn.relations.DirectRelations.FindAll(rel => rel.def.Equals(PawnRelationDefOf.Parent)); foreach (DirectPawnRelation parent in parentRelations) { - XenotypeDef xenotype = HiveUtility.TryGetDroneXenotype(parent.otherPawn); + var xenotype = HiveUtility.TryGetDroneXenotype(parent.otherPawn); if (xenotype != null) return xenotype; } @@ -120,10 +170,10 @@ namespace RJW_Genes { if (bornQueen == null) return; - var letter= LetterMaker.MakeLetter( - "New Queen", "A new Queen was born! Make sure to adress inheritance before the new queen reaches adolesence.", LetterDefOf.NeutralEvent, bornQueen - ); - //letter.Start(); + var letter = LetterMaker.MakeLetter( + "rjw_genes_queenbirth_letter_label".Translate(), + string.Format("rjw_genes_queenbirth_letter_description".Translate(), xxx.get_pawnname(bornQueen)), + LetterDefOf.NeutralEvent, bornQueen); Find.LetterStack.ReceiveLetter(letter); } @@ -134,7 +184,7 @@ namespace RJW_Genes /// /// The pawn for whichs parent the xenotypes is looked up. /// The Queen-Xenotype of a parent or null. If both are queens, mothers are preferred. - public static XenotypeDef TryFindParentQueenXenotype(Pawn pawn) + public static Either TryFindParentQueenXenotype(Pawn pawn) { if (pawn == null) return null; @@ -142,7 +192,7 @@ namespace RJW_Genes List parentRelations = pawn.relations.DirectRelations.FindAll(rel => rel.def.Equals(PawnRelationDefOf.Parent)); foreach (var parent in parentRelations) { - XenotypeDef xenotype = HiveUtility.TryGetQueenXenotype(parent.otherPawn); + var xenotype = HiveUtility.TryGetQueenXenotype(parent.otherPawn); if (xenotype != null) return xenotype; } diff --git a/Source/Genes/Hive/Helpers/HiveUtility.cs b/Source/Genes/Hive/Helpers/HiveUtility.cs index c7d262d..089be9c 100644 --- a/Source/Genes/Hive/Helpers/HiveUtility.cs +++ b/Source/Genes/Hive/Helpers/HiveUtility.cs @@ -61,6 +61,9 @@ namespace RJW_Genes /// True if the pawn is on the home-map, False otherwise. public static bool PawnIsOnHomeMap(Pawn pawn) { + if (Find.Maps.NullOrEmpty() || !Find.Maps.Where(mapCandidate => mapCandidate.IsPlayerHome).Any()) { + return false; + } Map homeMap = Find.Maps.Where(mapCandidate => mapCandidate.IsPlayerHome).First(); return homeMap != null && pawn != null @@ -74,7 +77,7 @@ namespace RJW_Genes /// /// /// A xenotype with a queen gene, or null. - public static XenotypeDef TryGetQueenXenotype(Pawn pawn) + public static Either TryGetQueenXenotype(Pawn pawn) { if (pawn == null) return null; @@ -84,8 +87,15 @@ namespace RJW_Genes var potentialXenotype = pawn.genes.Xenotype; if (potentialXenotype != null && potentialXenotype.genes.Contains(GeneDefOf.rjw_genes_queen)) { - return potentialXenotype; + return new Either(potentialXenotype); } + + var potentialCustomXenotype = pawn.genes.CustomXenotype; + if (potentialCustomXenotype != null && potentialCustomXenotype.genes.Contains(GeneDefOf.rjw_genes_queen)) + { + return new Either(potentialCustomXenotype); + } + } return null; @@ -98,7 +108,7 @@ namespace RJW_Genes /// /// /// A xenotype with a drone gene, or null. - public static XenotypeDef TryGetDroneXenotype(Pawn pawn) + public static Either TryGetDroneXenotype(Pawn pawn) { if (pawn == null) return null; @@ -108,7 +118,13 @@ namespace RJW_Genes var potentialXenotype = pawn.genes.Xenotype; if (potentialXenotype != null && potentialXenotype.genes.Contains(GeneDefOf.rjw_genes_drone)) { - return potentialXenotype; + return new Either(potentialXenotype); + } + + var potentialCustomXenotype = pawn.genes.CustomXenotype; + if (potentialCustomXenotype != null && potentialCustomXenotype.genes.Contains(GeneDefOf.rjw_genes_drone)) + { + return new Either(potentialCustomXenotype); } } @@ -122,23 +138,35 @@ namespace RJW_Genes /// Prints a bigger piece of information when debug printing is enabled. /// /// A mapping which Queen-Xenotypes should produce which worker genes. - - public static Dictionary> GetQueenWorkerMappings() + public static Dictionary> GetQueenWorkerMappings() { - Dictionary> dict = new Dictionary>(); IEnumerable mappingDefs = DefDatabase.AllDefs; + Dictionary> results = new Dictionary>(); + // Dev-Note: I first a nice lambda here, but I used nesting in favour of logging. foreach (QueenWorkerMappingDef mappingDef in mappingDefs) { - + // Option A) This is the default worker genes, expected, just ignore. if (mappingDef.defName == "rjw_genes_default_worker_genes") { // Do nothing, there is no lookup but this entry is fine and should not log a warning. continue; } + // Option B) The Xenotype is a "static" Xenotype, from a mod or something. XenotypeDef queenDef = DefDatabase.GetNamed(mappingDef.queenXenotype); + string defName = null; if (queenDef != null) + { + defName = queenDef.defName; + } + else if (Current.Game != null && Current.Game.customXenotypeDatabase != null) + { + // Option C) The Xenotype is a Custom Xenotype, created by the player + CustomXenotype customQueenDef = Current.Game.customXenotypeDatabase.customXenotypes.Find(f => f.name == mappingDef.defName); + defName = customQueenDef?.name; + } + if (defName != null) { List workerGenes = new List(); foreach (string geneName in mappingDef.workerGenes) @@ -149,15 +177,17 @@ namespace RJW_Genes else if(RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Warning($"Could not look up Gene {geneName} for {mappingDef.queenXenotype}."); } - dict.Add(queenDef, workerGenes); - } - else { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) - ModLog.Warning($"Did not find a matching xenotype for {mappingDef.queenXenotype}! Defaulting to rjw_genes_default_worker_genes."); + results.Add(defName, workerGenes); + continue; } + + // Option D) Fallback, unknown + if (RJW_Genes_Settings.rjw_genes_detailed_debug) + ModLog.Warning($"Did not find a matching xenotype for {mappingDef.queenXenotype}! Defaulting to rjw_genes_default_worker_genes."); + } - return dict; + return results; } /// @@ -203,6 +233,16 @@ namespace RJW_Genes } + public static String GetXenotypeDefName(Either def) + { + if (def == null) + return null; + else if (def.isLeft) + return def.left.defName; + else + return def.right.name; + } + public static HiveOffspringChanceDef LookupDefaultHiveInheritanceChances() { IEnumerable offspringChanceDefs = DefDatabase.AllDefs; @@ -217,11 +257,16 @@ namespace RJW_Genes return defaultChance; } - public static HiveOffspringChanceDef LookupHiveInheritanceChances(XenotypeDef queenDef) + public static HiveOffspringChanceDef LookupHiveInheritanceChances(Either queenDef) { + if (queenDef == null) + return LookupDefaultHiveInheritanceChances(); + + String queenDefName = queenDef.isLeft ? queenDef.left.defName : queenDef.right.name; + IEnumerable offspringChanceDefs = DefDatabase.AllDefs; - return offspringChanceDefs.FirstOrFallback(t => t.queenXenotype == queenDef.defName, LookupDefaultHiveInheritanceChances()); + return offspringChanceDefs.FirstOrFallback(t => t.queenXenotype == queenDefName, LookupDefaultHiveInheritanceChances()); } diff --git a/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs b/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs index fe9155e..5c5e98d 100644 --- a/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs +++ b/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs @@ -34,8 +34,8 @@ namespace RJW_Genes Pawn pawn = (Pawn)__result; - XenotypeDef queenDef = HiveBirthLogic.TryFindParentQueenXenotype(pawn) ?? TryFindParentQueenXenotypeFromEgg(__instance); - XenotypeDef droneDef = HiveBirthLogic.TryFindParentDroneXenotype(pawn) ?? TryFindParentDroneXenotypeFromEgg(__instance); + Either queenDef = HiveBirthLogic.TryFindParentQueenXenotype(pawn) ?? TryFindParentQueenXenotypeFromEgg(__instance); + Either droneDef = HiveBirthLogic.TryFindParentDroneXenotype(pawn) ?? TryFindParentDroneXenotypeFromEgg(__instance); bool hasQueenParent = queenDef != null; bool hasDroneParent = droneDef != null; @@ -47,6 +47,15 @@ namespace RJW_Genes } else { if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Ignoring Postfix Hediff_InsectEgg::ProcessHumanLikeInsectEgg - No Queen Parent - No Action."); + + // Extra Debug for #56 + if (RJW_Genes_Settings.rjw_genes_detailed_debug) + { + ModLog.Message($"Implanter was: ({__instance.implanter.genes.xenotypeName}|{__instance.implanter.genes.Xenotype}), Fertilizer was: ({__instance.father.genes.xenotypeName}|{__instance.father.genes.Xenotype})"); + ModLog.Message($"Implanter Xenotype From helper: {HiveUtility.TryGetQueenXenotype(__instance.implanter)} and has Queen {__instance.implanter.genes.HasGene(GeneDefOf.rjw_genes_queen)}"); + ModLog.Message($"Father Xenotype From helper: {HiveUtility.TryGetDroneXenotype(__instance.implanter)} and has Drone {__instance.father.genes.HasGene(GeneDefOf.rjw_genes_drone)}"); + CustomXenotype custom = __instance.implanter.genes.CustomXenotype; + } } } @@ -59,9 +68,9 @@ namespace RJW_Genes /// /// An Egg for which queens are looked up for /// The relevant xenotypedef of a queen, or null. - public static XenotypeDef TryFindParentQueenXenotypeFromEgg(Hediff_InsectEgg egg) + public static Either TryFindParentQueenXenotypeFromEgg(Hediff_InsectEgg egg) { - XenotypeDef queenDef = null; + Either queenDef = null; if (egg == null) return null; @@ -85,9 +94,9 @@ namespace RJW_Genes /// /// An Egg for which drones are looked up for /// The relevant xenotypedef of a drone, or null. - public static XenotypeDef TryFindParentDroneXenotypeFromEgg(Hediff_InsectEgg egg) + public static Either TryFindParentDroneXenotypeFromEgg(Hediff_InsectEgg egg) { - XenotypeDef droneDef = null; + Either droneDef = null; if (egg == null) return null; diff --git a/Source/Genes/Life_Force/Defs/LifeForceEmpathExtension.cs b/Source/Genes/Life_Force/Defs/LifeForceEmpathExtension.cs new file mode 100644 index 0000000..ccc037b --- /dev/null +++ b/Source/Genes/Life_Force/Defs/LifeForceEmpathExtension.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class LifeForceEmpathExtension : DefModExtension + { + public float aheagoIncrement; + public float satisfactionIncrement; + public float frustratedDecrement; + } +} diff --git a/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs b/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs index f2e9a99..7f3c32b 100644 --- a/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs +++ b/Source/Genes/Life_Force/Events/SuccubusVisit/LordJob_SuccubusVisit.cs @@ -85,7 +85,7 @@ namespace RJW_Genes 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); + Find.LetterStack.ReceiveLetter("rjw_genes_succubus_joins_letter_label".Translate(), string.Format("rjw_genes_succubus_joins_letter_description".Translate(), xxx.get_pawnname(pawn)), LetterDefOf.PositiveEvent, pawn, null, null, null, null); } else { diff --git a/Source/Genes/Life_Force/Genes/Gene_LifeForce_Empath.cs b/Source/Genes/Life_Force/Genes/Gene_LifeForce_Empath.cs new file mode 100644 index 0000000..2fec1a7 --- /dev/null +++ b/Source/Genes/Life_Force/Genes/Gene_LifeForce_Empath.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using Verse; +using RimWorld; + +namespace RJW_Genes +{ + public class Gene_LifeForce_Empath : Gene + { + + const int EMPATH_DISTANCE_FALLBACK = 25; + const int TICK_INTERVAL_FALLBACK = 60000 / 48; + + const float AHEAGO_FALLBACK = 0.02f, SATISFIED_FALLBACK = 0.01f, FRUSTRATED_FALLBACK = -0.01f; + + int empathDistance = 25; + int tickInterval = 60000 / 48 ; // 60k = 1 day, we want 0.5h which is 1/48th of 1 day. + + float aheagoIncrement = 0.02f; + float satisfiedIncrement = 0.01f; + float frustratedDecrement = -0.01f; + + + Gene_LifeForce_Empath() : base() + { + SetValuesFromExtension(); + } + + private void SetValuesFromExtension() + { + LifeForceEmpathExtension empathExt = GeneDefOf.rjw_genes_lifeforce_empath.GetModExtension(); + + tickInterval = ModExtensionHelper.GetTickIntervalFromModExtension(GeneDefOf.rjw_genes_lifeforce_empath, TICK_INTERVAL_FALLBACK); + empathDistance = ModExtensionHelper.GetTickIntervalFromModExtension(GeneDefOf.rjw_genes_lifeforce_empath, EMPATH_DISTANCE_FALLBACK); + + aheagoIncrement = empathExt?.aheagoIncrement ?? AHEAGO_FALLBACK; + satisfiedIncrement = empathExt?.satisfactionIncrement ?? SATISFIED_FALLBACK; + frustratedDecrement = empathExt?.frustratedDecrement ?? FRUSTRATED_FALLBACK; + } + + public override void Tick() + { + base.Tick(); + if (this.pawn.IsHashIntervalTick(tickInterval) && this.pawn.Map != null) + { + foreach (Pawn pawn in this.AffectedPawns(this.pawn.Position, this.pawn.Map)) + { + this.FarmLifeForce(pawn); + } + + } + } + + /// + /// Creates an IEnumerable of all pawns which are closeby and in lineofsight, self and other pawns with lifeforce gene are skipped (to prevent loops). + /// + /// The position of the empath on the map + /// The map the empath is on + /// A list of all pawns that are close enough for the empath to connect. + private IEnumerable AffectedPawns(IntVec3 pos, Map map) + { + foreach (Pawn pawn in map.mapPawns.AllPawns) + { + // Return for trivial errors + if (pawn == null || this.pawn == null || pawn == this.pawn) + continue; + // Check for position-existance + if (pawn.Position == null || pos == null || pawn.Map == null) + continue; + // Do nothing if pawn is carried + if (pawn.CarriedBy != null) + continue; + // Do nothing if Pawn is Baby or Child (#25) + if (!pawn.ageTracker.Adult) + continue; + // Do nothing for pawns that also have lifeforce + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_lifeforce)) + continue; + + // Actual Logic: + // Pawn qualifies in right distance and needs line of sight. + if (pos.DistanceTo(pawn.Position) < empathDistance && GenSight.LineOfSight(pos, pawn.Position, pawn.Map)) + { + yield return pawn; + } + } + + yield break; + } + + /// + /// Adjust the empaths lifeforce depending on the farmed pawns sexneed. + /// + /// The pawn affecting the empath, increasing or decreasing his lifeforce. + private void FarmLifeForce(Pawn farmedPawn) + { + // Short rename to make rest more obvious. + Pawn empath = pawn; + + if (farmedPawn == null) + return; + + var sexneed = farmedPawn.needs.TryGetNeed(); + + // Shortwire: do nothing on no sexneed. + if (sexneed == null) + return; + + if (sexneed.CurLevel >= sexneed.thresh_ahegao()) + GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(empath), aheagoIncrement); + else if (sexneed.CurLevel >= sexneed.thresh_satisfied()) + GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(empath), satisfiedIncrement); + else if (sexneed.CurLevel <= sexneed.thresh_frustrated()) + GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(empath), frustratedDecrement); + + } + + } +} diff --git a/Source/Genes/Special/AgeTransferExtension.cs b/Source/Genes/Special/Defs/AgeTransferExtension.cs similarity index 100% rename from Source/Genes/Special/AgeTransferExtension.cs rename to Source/Genes/Special/Defs/AgeTransferExtension.cs diff --git a/Source/Genes/Special/Defs/HormonalSalivaExtension.cs b/Source/Genes/Special/Defs/HormonalSalivaExtension.cs new file mode 100644 index 0000000..7c212f0 --- /dev/null +++ b/Source/Genes/Special/Defs/HormonalSalivaExtension.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class HormonalSalivaExtension : DefModExtension + { + /// + /// How much the genitalia will growth per interaction. + /// This is applied "flat", so if you have penis 0.5 and growthRate 0.05 it goes to 0.55, 0.60, 0.65 etc. + /// + public float sizeIncrement; + /// + /// Upper Limit for the body size - default should be 2-3 + /// + public float maxBodySize; + /// + /// How much more cum the pawn will make. + /// This is applied as multiplication, so if you have cum 20 and multiplier 1.1 you will have 22,24,27 etc. + /// This leads to exponential growth, so try to keep it kinda low. + /// + public float cumMultiplier; + } +} diff --git a/Source/Genes/Special/Gene_Aphrodisiac_Pheromones.cs b/Source/Genes/Special/Genes/Gene_Aphrodisiac_Pheromones.cs similarity index 81% rename from Source/Genes/Special/Gene_Aphrodisiac_Pheromones.cs rename to Source/Genes/Special/Genes/Gene_Aphrodisiac_Pheromones.cs index 875d1dd..0d13fb6 100644 --- a/Source/Genes/Special/Gene_Aphrodisiac_Pheromones.cs +++ b/Source/Genes/Special/Genes/Gene_Aphrodisiac_Pheromones.cs @@ -11,8 +11,8 @@ namespace RJW_Genes // 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 int APHRODISIAC_DISTANCE_FALLBACK = 25; + const int TICK_INTERVAL_FALLBACK = 60000 / 48 ; // 60k = 1 day, we want 0.5h which is 1/48th of 1 day. const float SEXFREQ_THRESHOLD = 0.5f; @@ -20,7 +20,10 @@ namespace RJW_Genes public override void Tick() { base.Tick(); - if (this.pawn.IsHashIntervalTick(TICK_INTERVAL) && this.pawn.Map != null) + + int tickInterval = ModExtensionHelper.GetTickIntervalFromModExtension(GeneDefOf.rjw_genes_aphrodisiac_pheromones, TICK_INTERVAL_FALLBACK); + + if (this.pawn.IsHashIntervalTick(tickInterval) && this.pawn.Map != null) { // Only spread pheromones if sexdrive above 1 float sexfrequency = this.pawn.GetStatValue(StatDef.Named("SexFrequency")); @@ -57,7 +60,8 @@ namespace RJW_Genes // Actual Logic: // Pawn qualifies in right distance and needs line of sight. - if (pos.DistanceTo(pawn.Position) < APHRODISIAC_DISTANCE && GenSight.LineOfSight(pos, pawn.Position, pawn.Map)) + int effectDistance = ModExtensionHelper.GetDistanceFromModExtension(GeneDefOf.rjw_genes_aphrodisiac_pheromones, APHRODISIAC_DISTANCE_FALLBACK); + if (pos.DistanceTo(pawn.Position) < effectDistance && GenSight.LineOfSight(pos, pawn.Position, pawn.Map)) { yield return pawn; } diff --git a/Source/Genes/Special/Patch_AgeDrain.cs b/Source/Genes/Special/Patches/Patch_AgeDrain.cs similarity index 100% rename from Source/Genes/Special/Patch_AgeDrain.cs rename to Source/Genes/Special/Patches/Patch_AgeDrain.cs diff --git a/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs b/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs new file mode 100644 index 0000000..150eeec --- /dev/null +++ b/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs @@ -0,0 +1,76 @@ +using HarmonyLib; +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + [HarmonyPatch(typeof(SexUtility), "Aftersex")] + public class Patch_HormonalSaliva + { + // TODO: Reduce to 0.02 after debug. + const float SIZE_INCREMENT_FALLBACK = 0.02f; + const float MAX_BODY_SIZE_FALLBACK = 2.5f; + const float CUM_MULTIPLIER_FALLBACK = 1.05f; + + public static void Postfix(SexProps props) + { + if (props == null || props.pawn == null || props.partner == null || props.partner.IsAnimal()) + { + return; + } + + Pawn pawn = props.pawn; + Pawn partner = props.partner; + + + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hormonal_saliva) && (props.sexType == xxx.rjwSextype.Oral || props.sexType == xxx.rjwSextype.Sixtynine || props.sexType == xxx.rjwSextype.Fellatio)) + { + GrowPenisses(partner); + } + + if (GeneUtility.HasGeneNullCheck(partner, GeneDefOf.rjw_genes_hormonal_saliva) && (props.sexType == xxx.rjwSextype.Oral || props.sexType == xxx.rjwSextype.Sixtynine || props.sexType == xxx.rjwSextype.Fellatio)) + { + GrowPenisses(pawn); + } + + } + + private static void GrowPenisses(Pawn pawn) + { + + HormonalSalivaExtension salivaExt = GeneDefOf.rjw_genes_hormonal_saliva.GetModExtension(); + + float size_increment = salivaExt?.sizeIncrement ?? SIZE_INCREMENT_FALLBACK; + float maximum_body_size = salivaExt?.maxBodySize ?? MAX_BODY_SIZE_FALLBACK; + float cum_multiplier = salivaExt?.cumMultiplier ?? CUM_MULTIPLIER_FALLBACK; + + + List AllPenisses = Genital_Helper.get_AllPartsHediffList(pawn).FindAll(x => Genital_Helper.is_penis(x)); + foreach (Hediff penis in AllPenisses) + { + CompHediffBodyPart CompHediff = penis.TryGetComp(); + if (penis.Severity < 1.00) + { + penis.Severity = Math.Min(1.01f, penis.Severity + size_increment); + } + else + { + if (CompHediff != null && CompHediff.SizeOwner <= maximum_body_size) + { + CompHediff.SizeOwner += size_increment; + } + } + + // Increase Fluid + if (CompHediff != null) + CompHediff.FluidAmmount *= cum_multiplier; + } + } + + } +} diff --git a/Source/Genes/Special/Patch_OrgasmMytosis.cs b/Source/Genes/Special/Patches/Patch_OrgasmMytosis.cs similarity index 100% rename from Source/Genes/Special/Patch_OrgasmMytosis.cs rename to Source/Genes/Special/Patches/Patch_OrgasmMytosis.cs diff --git a/Source/Genes/Special/Patch_OrgasmRush.cs b/Source/Genes/Special/Patches/Patch_OrgasmRush.cs similarity index 100% rename from Source/Genes/Special/Patch_OrgasmRush.cs rename to Source/Genes/Special/Patches/Patch_OrgasmRush.cs diff --git a/Source/Genes/Special/Patch_Youth_Fountain.cs b/Source/Genes/Special/Patches/Patch_Youth_Fountain.cs similarity index 100% rename from Source/Genes/Special/Patch_Youth_Fountain.cs rename to Source/Genes/Special/Patches/Patch_Youth_Fountain.cs diff --git a/Source/HediffDefOf.cs b/Source/HediffDefOf.cs index 4e3b052..30e34df 100644 --- a/Source/HediffDefOf.cs +++ b/Source/HediffDefOf.cs @@ -17,6 +17,8 @@ namespace RJW_Genes public static readonly HediffDef rjw_genes_orgasm_rush_hediff; public static readonly HediffDef rjw_genes_fertilin_craving; + public static readonly HediffDef rjw_genes_evergrowth_sideeffect; + public static readonly HediffDef rjw_genes_orgasmic_mytosis_hediff; public static readonly HediffDef rjw_genes_mytosis_shock_hediff; } diff --git a/Source/RJW_Genes.cs b/Source/RJW_Genes.cs index db4ffbf..44cf60d 100644 --- a/Source/RJW_Genes.cs +++ b/Source/RJW_Genes.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Verse; @@ -14,9 +15,8 @@ namespace RJW_Genes { ModLog.Message($"{HiveUtility.getQueenXenotypes().EnumerableCount()} Queen-Xenotypes ({string.Join(",", HiveUtility.getQueenXenotypes().Select(t => t.defName))})"); ModLog.Message($"{HiveUtility.getDroneXenotypes().EnumerableCount()} Drone-Xenotypes ({string.Join(",", HiveUtility.getDroneXenotypes().Select(t => t.defName))})"); - ModLog.Message($"Found {HiveUtility.GetQueenWorkerMappings().Count} Queen-Worker Mappings ({string.Join(",", HiveUtility.GetQueenWorkerMappings().Keys.Select(t => t.defName))} + Default) "); - + ModLog.Message($"Found {HiveUtility.GetQueenWorkerMappings().Count} Queen-Worker Mappings ({string.Join(",", HiveUtility.GetQueenWorkerMappings().Keys.Select(t => t))} + Default) "); IEnumerable offspringChanceDefs = DefDatabase.AllDefs; IEnumerable faultOffspringDefs = offspringChanceDefs.Where(t => t.queenChance + t.workerChance + t.workerChance > 1.02 || t.queenChance + t.workerChance + t.workerChance < 0.98 ); ModLog.Message($"Found {offspringChanceDefs.Count()} OffspringChanceDefs, of which {faultOffspringDefs.Count()} had faulty chances ({string.Join(",", faultOffspringDefs.Select(t => t.defName))})"); diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index 0ece225..148f8d4 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -39,11 +39,18 @@ + + + + + + + @@ -110,6 +117,8 @@ + + @@ -139,9 +148,11 @@ - - - + + + + + @@ -156,10 +167,10 @@ - + - - + + @@ -199,6 +210,7 @@ ..\..\RJW-Sexperience-1.1.4.0\1.4\Assemblies\RJWSexperience.dll + False @@ -216,6 +228,8 @@ False - + + + \ No newline at end of file