From 65ff62cbf94f23a5045f8bfa321c876c967eeb59 Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 08:20:34 +0200 Subject: [PATCH 1/8] Added a ImmunityExtension --- Common/Defs/GeneDefs/GeneDefs_Diseases.xml | 17 +++ .../Defs/ImmunityAgainstGenesExtension.cs | 19 +++ Source/Genes/Diseases/DiseaseHelper.cs | 111 ++++++++++++++++++ ...AftersexUtility_TransferGeneticDiseases.cs | 65 +--------- Source/Rjw-Genes.csproj | 2 + 5 files changed, 154 insertions(+), 60 deletions(-) create mode 100644 Source/Genes/Diseases/Defs/ImmunityAgainstGenesExtension.cs create mode 100644 Source/Genes/Diseases/DiseaseHelper.cs diff --git a/Common/Defs/GeneDefs/GeneDefs_Diseases.xml b/Common/Defs/GeneDefs/GeneDefs_Diseases.xml index ecc3ee8..d5a8d3a 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Diseases.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Diseases.xml @@ -202,4 +202,21 @@ + + rjw_genes_stretcher + + Pawns with this gene have a chance to make sexual partners prefer large genitalia as part of their genetics. + UI/Icons/ColonistBar/Idle + 1 + 0 + 12 + +
  • + +
  • rjw_genes_size_blinded
  • + + +
    +
    + \ No newline at end of file diff --git a/Source/Genes/Diseases/Defs/ImmunityAgainstGenesExtension.cs b/Source/Genes/Diseases/Defs/ImmunityAgainstGenesExtension.cs new file mode 100644 index 0000000..18fe8e0 --- /dev/null +++ b/Source/Genes/Diseases/Defs/ImmunityAgainstGenesExtension.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class ImmunityAgainstGenesExtension : DefModExtension + { + /// + /// A list of the exact defnames of disease-genes that this extension will make immune against. + /// Must perfectly match! + /// + public List givesImmunityAgainst; + } + +} diff --git a/Source/Genes/Diseases/DiseaseHelper.cs b/Source/Genes/Diseases/DiseaseHelper.cs new file mode 100644 index 0000000..1af745b --- /dev/null +++ b/Source/Genes/Diseases/DiseaseHelper.cs @@ -0,0 +1,111 @@ +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public static class DiseaseHelper + { + + /// + /// Checks for a pawn if it is immune against a disease. + /// + /// The pawn for which immunity is checked + /// The genetic disease that is checked against + /// True if the pawn is immune, false if the pawn can be infected by it. + public static bool IsImmuneAgainstGeneticDisease(Pawn pawn, GeneDef disease) + { + // Case 1: Something is null / not working, return Immune (to have less follow up effects) + if (pawn == null || pawn.genes == null) return true; + if (disease == null) return true; + // Case 1.B: Dead people can spread, but not receive, diseases. + if (pawn.Dead) return true; + + // Case 2: The pawn has general genetic immunity to diseases + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_genetic_disease_immunity)) + return true; + + // Case 3: The pawn already has the genetic disease + if (GeneUtility.HasGeneNullCheck(pawn, disease)) + return true; + + // Case 4: Check all genes if one of them has the Immunity Extension that covers the GeneDef + List genes = pawn.genes.GenesListForReading; + genes = genes.Where(x => pawn.genes.HasActiveGene(x.def)).ToList(); + + foreach (Gene gene in genes) + { + ImmunityAgainstGenesExtension ext = gene.def.GetModExtension(); + if (ext != null) { + foreach (string defname in ext.givesImmunityAgainst) + if (disease.defName == defname) + return true; + } + } + + // Case 5: Nothing special happens, so return false (not immune) + return false; + } + + /// + /// Returns all active Genes with the `GeneticDiseaseExtension`. + /// + /// + /// List of all active Genes with the `GeneticDiseaseExtension` in pawn + public static List GetGeneticDiseaseGenes(Pawn pawn) + { + if (pawn != null && pawn.genes != null) + { + return pawn.genes + .GenesListForReading + .ConvertAll(gene => gene.def) + .Where(genedef => pawn.genes.HasActiveGene(genedef)) + .Where(IsGeneticDiseaseGene) + .ToList(); + } + + return new List() { }; + } + + /// + /// Checks if the performed sex was penetrative. + /// Condom check is not done here! + /// + /// The sexprops + /// + public static bool IsPenetrativeSex(SexProps props) + { + if (props == null) return false; + + return props.sexType == + xxx.rjwSextype.Vaginal + || props.sexType == xxx.rjwSextype.Anal + || props.sexType == xxx.rjwSextype.Oral + || props.sexType == xxx.rjwSextype.DoublePenetration + || props.sexType == xxx.rjwSextype.Fellatio + || props.sexType == xxx.rjwSextype.Sixtynine; + } + + public static bool IsGeneticDiseaseGene(GeneDef geneDef) + { + if (geneDef == null) return false; + GeneticDiseaseExtension diseaseExt = geneDef.GetModExtension(); + return diseaseExt != null; + } + + public static float LookupDiseaseInfectionChance(GeneDef geneDef) + { + if (IsGeneticDiseaseGene(geneDef)) + { + GeneticDiseaseExtension diseaseExt = geneDef.GetModExtension(); + return diseaseExt != null ? diseaseExt.infectionChance : 0.0f; + } + else + return 0.0f; + } + } +} diff --git a/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs b/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs index 6bf8e88..b068c38 100644 --- a/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs +++ b/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs @@ -29,7 +29,7 @@ namespace RJW_Genes.Genes.Diseases.Patches if (props.usedCondom) return; // Exit early if settings require penetrative sex, but this is not penetrative sex - if (!IsPenetrativeSex(props) && RJW_Genes_Settings.rjw_genes_genetic_disease_spread_only_on_penetrative_sex) return; + if (!DiseaseHelper.IsPenetrativeSex(props) && RJW_Genes_Settings.rjw_genes_genetic_disease_spread_only_on_penetrative_sex) return; ModLog.Debug($"Firing Patch_TransferGeneticDiseases for {pawn} and {partner}"); TryTransferGeneticDiseases(pawn, partner, props); @@ -38,74 +38,19 @@ namespace RJW_Genes.Genes.Diseases.Patches private static void TryTransferGeneticDiseases(Pawn infector, Pawn infected, SexProps props) { - if (infected.genes.HasActiveGene(GeneDefOf.rjw_genes_genetic_disease_immunity)) - { - ModLog.Debug($"{infected} is immune to genetic diseases"); - return; - } - if (infected.Dead) - { - // Dead people can spread, but not receive, diseases. - return; - } - - foreach (GeneDef disease in GetGeneticDiseaseGenes(infector)) { + + foreach (GeneDef disease in DiseaseHelper.GetGeneticDiseaseGenes(infector)) { ModLog.Debug($"Found genetic disease {disease} in {infector}, trying to infect {infected}"); - if (infected.genes.HasActiveGene(disease)) + if (DiseaseHelper.IsImmuneAgainstGeneticDisease(infected,disease)) continue; - if ((new Random()).NextDouble() <= LookupDiseaseInfectionChance(disease)) + if ((new Random()).NextDouble() <= DiseaseHelper.LookupDiseaseInfectionChance(disease)) { infected.genes.AddGene(disease, !RJW_Genes_Settings.rjw_genes_genetic_disease_as_endogenes); } } } - private static List GetGeneticDiseaseGenes(Pawn pawn) - { - if (pawn != null && pawn.genes != null) - { - return pawn.genes - .GenesListForReading - .ConvertAll(gene => gene.def) - .Where(genedef => pawn.genes.HasActiveGene(genedef)) - .Where(IsGeneticDiseaseGene) - .ToList(); - } - - return new List() { }; - } - - private static bool IsPenetrativeSex(SexProps props) - { - if (props == null) return false; - - return props.sexType == - xxx.rjwSextype.Vaginal - || props.sexType == xxx.rjwSextype.Anal - || props.sexType == xxx.rjwSextype.Oral - || props.sexType == xxx.rjwSextype.DoublePenetration - || props.sexType == xxx.rjwSextype.Fellatio - || props.sexType == xxx.rjwSextype.Sixtynine; - } - - private static bool IsGeneticDiseaseGene(GeneDef geneDef) - { - if (geneDef == null) return false; - GeneticDiseaseExtension diseaseExt = geneDef.GetModExtension(); - return diseaseExt != null; - } - - private static float LookupDiseaseInfectionChance(GeneDef geneDef) - { - if (IsGeneticDiseaseGene(geneDef)) - { - GeneticDiseaseExtension diseaseExt = geneDef.GetModExtension(); - return diseaseExt != null ? diseaseExt.infectionChance : 0.0f; - } - else - return 0.0f; - } } } diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index 51b80a1..bd03e87 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -76,6 +76,8 @@ + + From 56f8c2b6b263e3113203ebc8a52dbac05f8a3b44 Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 09:19:34 +0200 Subject: [PATCH 2/8] Added the first genetic infector gene, stretcher, and docs for it --- CHANGELOG.md | 49 +++++++++++++++- Common/Defs/GeneDefs/GeneDefs_Diseases.xml | 8 ++- .../Diseases/Defs/GeneticInfectorExtension.cs | 17 ++++++ Source/Genes/Diseases/DiseaseHelper.cs | 34 +++++++++++ ...h_AfterSexUtility_ApplyGeneticInfectors.cs | 57 +++++++++++++++++++ ...AftersexUtility_TransferGeneticDiseases.cs | 4 +- Source/Rjw-Genes.csproj | 2 + 7 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 Source/Genes/Diseases/Defs/GeneticInfectorExtension.cs create mode 100644 Source/Genes/Diseases/Patches/Patch_AfterSexUtility_ApplyGeneticInfectors.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index c177c58..d41f131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # 2.2.0 (dd-mm-2024) -**Genetic Diseases** +## Explanations + +**Genetic Diseases**: This update introduces genetic diseases that are shared on sex. Infection is handled when sex finishes, so a coitus-interruptus will not result in infections. @@ -20,6 +22,50 @@ Most of the genes so far were positive or neutral, so I got some fair requests to introduce negative genes to keep xenotypes balanced. I know that this is some overlap with the STD mod, but well ... you are free to turn things off? +**Genetic Infectors**: + +These Genes can apply a genetic disease, but are not genetic diseases themselves. +A single infector gene can have multiple resulting diseases, see this extension example: + +```xml +
  • + 0.05 + +
  • rjw_genes_size_blinded
  • +
  • rjw_genes_infectious_bisexuality
  • + + +``` + +The infection-chance is applied per gene - for the example above there would be a 5% chance to apply `size_blinded` and 5% chance to apply `infectious_bisexuality`. +Multiple infections can happen on a single sex. +The `infectionGenes` can be any gene, this is not limited to genetic diseases (e.g. ugly or something). + +*Infectors* are always applied even if the genetic disease spread is turned off. +The created genetic diseases will follow the logic outlined above. + +**Disease Immunity**: + +Pawns can be immune to genetic diseases. + +This is either done with a specialised gene (`rjw_genes_genetic_disease_immunity`) +or by genes giving specific immunities. + +Any gene can give immunity against any genetic disease using an extension: + +```xml +
  • + +
  • rjw_genes_size_blinded
  • + + +``` + +These extensions can be slapped on any gene, +but they are meant mostly to have infectors immune against their own diseases. + +## Changelog + **Additions:** - Passive Gene: *Genetic Disease Immunity* - cannot get infected by any genetic diseases, and won't be affected by some other genes (see relevant genes) @@ -28,6 +74,7 @@ I know that this is some overlap with the STD mod, but well ... you are free to - Disease Gene: Infectious Homosexuality & Bisexuality - Disease Gene: Fluctual Sexual Need. (Configurable) Chance to reset sex-need to near-zero and gain a bit of rest-need. - Disease Gene: Size Blinded. Pawns have a higher chance for hooking up with pawns with a big cock, lower chance for small cocks. +- Infector Gene: Genetic Stretcher. Pawns can infect other pawns with *Size Blinded* **Fixes:** diff --git a/Common/Defs/GeneDefs/GeneDefs_Diseases.xml b/Common/Defs/GeneDefs/GeneDefs_Diseases.xml index d5a8d3a..2570b65 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Diseases.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Diseases.xml @@ -205,7 +205,7 @@ rjw_genes_stretcher - Pawns with this gene have a chance to make sexual partners prefer large genitalia as part of their genetics. + Pawns with this gene have a chance to alter the genes of their sexual partners to prefer large cocks. UI/Icons/ColonistBar/Idle 1 0 @@ -216,6 +216,12 @@
  • rjw_genes_size_blinded
  • +
  • + 0.05 + +
  • rjw_genes_size_blinded
  • + +
    diff --git a/Source/Genes/Diseases/Defs/GeneticInfectorExtension.cs b/Source/Genes/Diseases/Defs/GeneticInfectorExtension.cs new file mode 100644 index 0000000..2f00ce5 --- /dev/null +++ b/Source/Genes/Diseases/Defs/GeneticInfectorExtension.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class GeneticInfectorExtension : DefModExtension + { + public float infectionChance; + + public List infectionGenes; + } + +} diff --git a/Source/Genes/Diseases/DiseaseHelper.cs b/Source/Genes/Diseases/DiseaseHelper.cs index 1af745b..873a0e1 100644 --- a/Source/Genes/Diseases/DiseaseHelper.cs +++ b/Source/Genes/Diseases/DiseaseHelper.cs @@ -71,6 +71,31 @@ namespace RJW_Genes return new List() { }; } + public static List GetGeneticInfectorGenes(Pawn pawn) + { + if (pawn != null && pawn.genes != null) + { + return pawn.genes + .GenesListForReading + .ConvertAll(gene => gene.def) + .Where(genedef => pawn.genes.HasActiveGene(genedef)) + .Where(IsGeneticInfectorGene) + .ToList(); + } + + return new List() { }; + } + + public static List LookupInfectionGeneDefs(GeneticInfectorExtension infectorExt) + { + if (infectorExt == null) new List(); + + return RimWorld.GeneUtility + .GenesInOrder + .Where(genedef => infectorExt.infectionGenes.Contains(genedef.defName)) + .ToList(); + } + /// /// Checks if the performed sex was penetrative. /// Condom check is not done here! @@ -97,6 +122,13 @@ namespace RJW_Genes return diseaseExt != null; } + public static bool IsGeneticInfectorGene(GeneDef geneDef) + { + if (geneDef == null) return false; + GeneticInfectorExtension infectorExt = geneDef.GetModExtension(); + return infectorExt != null; + } + public static float LookupDiseaseInfectionChance(GeneDef geneDef) { if (IsGeneticDiseaseGene(geneDef)) @@ -107,5 +139,7 @@ namespace RJW_Genes else return 0.0f; } + + } } diff --git a/Source/Genes/Diseases/Patches/Patch_AfterSexUtility_ApplyGeneticInfectors.cs b/Source/Genes/Diseases/Patches/Patch_AfterSexUtility_ApplyGeneticInfectors.cs new file mode 100644 index 0000000..1ee1e9f --- /dev/null +++ b/Source/Genes/Diseases/Patches/Patch_AfterSexUtility_ApplyGeneticInfectors.cs @@ -0,0 +1,57 @@ +using HarmonyLib; +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Remoting.Lifetime; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + + [HarmonyPatch(typeof(SexUtility), "Aftersex")] + public class Patch_AfterSexUtility_ApplyGeneticInfectors + { + public static void Postfix(SexProps props) + { + if (props == null || props.pawn == null || props.partner == null) return; + + Pawn pawn = props.pawn; + Pawn partner = props.partner; + + if (pawn == partner) return; + if (pawn.IsAnimal() || partner.IsAnimal()) return; + if (pawn.genes == null || partner.genes == null) return; + // No Infections on Condom Use + if (props.usedCondom) return; + + // Exit early if settings require penetrative sex, but this is not penetrative sex + if (!DiseaseHelper.IsPenetrativeSex(props) && RJW_Genes_Settings.rjw_genes_genetic_disease_spread_only_on_penetrative_sex) return; + + TryApplyGeneticInfections(pawn, partner); + TryApplyGeneticInfections(partner, pawn); + } + + private static void TryApplyGeneticInfections(Pawn infector, Pawn partner) + { + foreach (GeneDef infectorGeneDef in DiseaseHelper.GetGeneticInfectorGenes(infector)) + { + GeneticInfectorExtension diseaseExt = infectorGeneDef.GetModExtension(); + if (diseaseExt == null) continue; + float application_chance = diseaseExt.infectionChance; + + foreach (GeneDef diseaseGeneDef in DiseaseHelper.LookupInfectionGeneDefs(diseaseExt)) + { + if (DiseaseHelper.IsImmuneAgainstGeneticDisease(partner, diseaseGeneDef)) + continue; + + if ((new Random()).NextDouble() < application_chance) + partner.genes.AddGene(diseaseGeneDef, !RJW_Genes_Settings.rjw_genes_genetic_disease_as_endogenes); + } + } + } + + } +} diff --git a/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs b/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs index b068c38..e33079f 100644 --- a/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs +++ b/Source/Genes/Diseases/Patches/Patch_AftersexUtility_TransferGeneticDiseases.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using Verse; -namespace RJW_Genes.Genes.Diseases.Patches +namespace RJW_Genes { [HarmonyPatch(typeof(SexUtility), "Aftersex")] public class Patch_AftersexUtility_TransferGeneticDiseases @@ -31,7 +31,7 @@ namespace RJW_Genes.Genes.Diseases.Patches // Exit early if settings require penetrative sex, but this is not penetrative sex if (!DiseaseHelper.IsPenetrativeSex(props) && RJW_Genes_Settings.rjw_genes_genetic_disease_spread_only_on_penetrative_sex) return; - ModLog.Debug($"Firing Patch_TransferGeneticDiseases for {pawn} and {partner}"); + //ModLog.Debug($"Firing Patch_TransferGeneticDiseases for {pawn} and {partner}"); TryTransferGeneticDiseases(pawn, partner, props); TryTransferGeneticDiseases(partner, pawn, props); } diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index bd03e87..f42e885 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -76,9 +76,11 @@ + + From ae31f2df3bc8bb70217500cef49c460bea68bf77 Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 11:24:27 +0200 Subject: [PATCH 3/8] Started on Progenity Gene --- Common/Defs/GeneDefs/GeneDefs_Breeding.xml | 39 +++++++++++++++++++ .../Languages/English/Keyed/StatsReports.xml | 8 ++++ Source/GeneDefOf.cs | 1 + .../ConditionalStatAffecter_ManyChildren.cs | 34 ++++++++++++++++ .../ConditionalStatAffecter_NoChildren.cs | 39 +++++++++++++++++++ ...onditionalStatAffecter_VeryManyChildren.cs | 32 +++++++++++++++ Source/Rjw-Genes.csproj | 3 ++ 7 files changed, 156 insertions(+) create mode 100644 Common/Languages/English/Keyed/StatsReports.xml create mode 100644 Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs create mode 100644 Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs create mode 100644 Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs diff --git a/Common/Defs/GeneDefs/GeneDefs_Breeding.xml b/Common/Defs/GeneDefs/GeneDefs_Breeding.xml index bb6fbe4..e90dc89 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Breeding.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Breeding.xml @@ -115,4 +115,43 @@ -1 + + rjw_genes_hardwired_progenity + + Carriers of this gene need to procreate. They suffer negative effects if they are childless, and have increased capabilities if they reach a high amount of offsprings. + Genes/Icons/RJW_Genes_PheromoneSpit + 70 + + +
  • + + 0.7 + + + -0.5 + 1.2 + +
  • +
  • + + 1.05 + + + 0.1 + 0.1 + +
  • +
  • + + 1.1 + + + 0.25 + +
  • +
    + + 1 + 0 +
    \ No newline at end of file diff --git a/Common/Languages/English/Keyed/StatsReports.xml b/Common/Languages/English/Keyed/StatsReports.xml new file mode 100644 index 0000000..715bccb --- /dev/null +++ b/Common/Languages/English/Keyed/StatsReports.xml @@ -0,0 +1,8 @@ + + + + Pawn doesn't have any children. + Pawn has a decent amount of children. + Pawn has a lot of children. + + diff --git a/Source/GeneDefOf.cs b/Source/GeneDefOf.cs index 2e59f20..f7612cc 100644 --- a/Source/GeneDefOf.cs +++ b/Source/GeneDefOf.cs @@ -73,6 +73,7 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_fervent_ovipositor; public static readonly GeneDef rjw_genes_insectbreeder; public static readonly GeneDef rjw_genes_insectincubator; + public static readonly GeneDef rjw_genes_hardwired_progenity; // Cum public static readonly GeneDef rjw_genes_no_cum; diff --git a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs new file mode 100644 index 0000000..3743889 --- /dev/null +++ b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs @@ -0,0 +1,34 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class ConditionalStatAffecter_ManyChildren : ConditionalStatAffecter + { + public override string Label => (string)"StatsReport_ManyChildren".Translate(); + + public const int THRESHOLD_FOR_CHILDREN = 3; + + public override bool Applies(StatRequest req) + { + if (req == null || req.Thing == null || !req.Thing.Spawned) return false; + + if (req.Thing is Pawn pawn) + { + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hardwired_progenity)) + { + // This "middle" Conditional Stat Affecter only fires if the other one does not apply + return pawn.relations.ChildrenCount >= THRESHOLD_FOR_CHILDREN + && pawn.relations.ChildrenCount < ConditionalStatAffecter_VeryManyChildren.THRESHOLD_FOR_CHILDREN; + } + } + + return false; + } + } +} diff --git a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs new file mode 100644 index 0000000..eb63ff1 --- /dev/null +++ b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs @@ -0,0 +1,39 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + /// + /// This conditional stat affecter "fires" if the pawn has no children. + /// + /// DevNote: I salvaged this from 1.3.3 Halamyr Conditional Stat Affecters. + /// It seems that with RW 1.5 there was a change how these work, as the req.Pawn seems to be null. + /// Now, the pawn is in req.Thing. + /// + public class ConditionalStatAffecter_NoChildren : ConditionalStatAffecter + { + public override string Label => (string)"StatsReport_NoChildren".Translate(); + + public override bool Applies(StatRequest req) + { + if (req == null || req.Thing == null || !req.Thing.Spawned) return false; + + if (req.Thing is Pawn pawn) + { + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hardwired_progenity)) + { + return pawn.relations.ChildrenCount == 0; + } + } + + return false; + } + + } + +} diff --git a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs new file mode 100644 index 0000000..aea272b --- /dev/null +++ b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs @@ -0,0 +1,32 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class ConditionalStatAffecter_VeryManyChildren : ConditionalStatAffecter + { + public override string Label => (string)"StatsReport_VeryManyChildren".Translate(); + + public const int THRESHOLD_FOR_CHILDREN = 8; + + public override bool Applies(StatRequest req) + { + if (req == null || req.Thing == null || !req.Thing.Spawned) return false; + + if (req.Thing is Pawn pawn) + { + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hardwired_progenity)) + { + return pawn.relations.ChildrenCount >= THRESHOLD_FOR_CHILDREN; + } + } + + return false; + } + } +} diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index f42e885..728b22f 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -71,6 +71,9 @@ + + + From 5920de6bbd5af3536d5bd3a1b22ba5be1a1f4600 Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 11:31:36 +0200 Subject: [PATCH 4/8] Simple Age Check for the ConditionalStatAffecters --- .../ConditionalStatAffecter_ManyChildren.cs | 4 ++++ .../ConditionalStatAffecter_NoChildren.cs | 4 ++++ .../ConditionalStatAffecter_VeryManyChildren.cs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs index 3743889..c483eb3 100644 --- a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs +++ b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_ManyChildren.cs @@ -20,6 +20,10 @@ namespace RJW_Genes if (req.Thing is Pawn pawn) { + // Do nothing if Pawn is Baby or Child (#25) + if (!pawn.ageTracker.Adult) + return false; + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hardwired_progenity)) { // This "middle" Conditional Stat Affecter only fires if the other one does not apply diff --git a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs index eb63ff1..4f50994 100644 --- a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs +++ b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_NoChildren.cs @@ -25,6 +25,10 @@ namespace RJW_Genes if (req.Thing is Pawn pawn) { + // Do nothing if Pawn is Baby or Child (#25) + if (!pawn.ageTracker.Adult) + return false; + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hardwired_progenity)) { return pawn.relations.ChildrenCount == 0; diff --git a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs index aea272b..e14d4f1 100644 --- a/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs +++ b/Source/Genes/Breeding/ConditionalStatAffecters/ConditionalStatAffecter_VeryManyChildren.cs @@ -20,6 +20,10 @@ namespace RJW_Genes if (req.Thing is Pawn pawn) { + // Do nothing if Pawn is Baby or Child (#25) + if (!pawn.ageTracker.Adult) + return false; + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_hardwired_progenity)) { return pawn.relations.ChildrenCount >= THRESHOLD_FOR_CHILDREN; From 35454db937efa017c8aeb673b0b348e328a3f90a Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 12:26:15 +0200 Subject: [PATCH 5/8] Added a thoughtworker for pawns to dislike pawns with more genetic diseases --- CHANGELOG.md | 2 + Common/Defs/ThoughtDefs/Thoughts_Disease.xml | 22 +++++++ ...ughtWorker_HasMoreDiseasesThanMe_Social.cs | 59 +++++++++++++++++++ .../ThoughtWorker_SizeBlinded_Social.cs | 1 - Source/Rjw-Genes.csproj | 1 + Source/ThoughtDefOf.cs | 1 + 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 Source/Genes/Diseases/Thoughts/ThoughtWorker_HasMoreDiseasesThanMe_Social.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index d41f131..2c4c8e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,8 @@ but they are meant mostly to have infectors immune against their own diseases. - Disease Gene: Fluctual Sexual Need. (Configurable) Chance to reset sex-need to near-zero and gain a bit of rest-need. - Disease Gene: Size Blinded. Pawns have a higher chance for hooking up with pawns with a big cock, lower chance for small cocks. - Infector Gene: Genetic Stretcher. Pawns can infect other pawns with *Size Blinded* +- Gene: Hardwired Progenity. Pawns with this get a malus on having no-children, and bonus on having a lot. +- Pawns will have negative thoughts about pawns with more genetic diseases than themselves. **Fixes:** diff --git a/Common/Defs/ThoughtDefs/Thoughts_Disease.xml b/Common/Defs/ThoughtDefs/Thoughts_Disease.xml index d0721ee..8997a52 100644 --- a/Common/Defs/ThoughtDefs/Thoughts_Disease.xml +++ b/Common/Defs/ThoughtDefs/Thoughts_Disease.xml @@ -24,4 +24,26 @@ + + rjw_genes_has_more_diseases + Thought_SituationalSocial + RJW_Genes.ThoughtWorker_HasMoreDiseasesThanMe_Social + true + + +
  • + + -3 +
  • +
  • + + -8 +
  • +
  • + + -18 +
  • +
    +
    + diff --git a/Source/Genes/Diseases/Thoughts/ThoughtWorker_HasMoreDiseasesThanMe_Social.cs b/Source/Genes/Diseases/Thoughts/ThoughtWorker_HasMoreDiseasesThanMe_Social.cs new file mode 100644 index 0000000..7a85eb3 --- /dev/null +++ b/Source/Genes/Diseases/Thoughts/ThoughtWorker_HasMoreDiseasesThanMe_Social.cs @@ -0,0 +1,59 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class ThoughtWorker_HasMoreDiseasesThanMe_Social : ThoughtWorker + { + protected override ThoughtState CurrentSocialStateInternal(Pawn pawn, Pawn other) + { + // Return for trivial errors + if (pawn == null || other == null || pawn == other) + return (ThoughtState)false; + // Check for position-existance + if (pawn.Position == null || other.Position == null || pawn.Map == null || other.Map == null) + return (ThoughtState)false; + // Do nothing if pawn is carried + if (pawn.CarriedBy != null) + return (ThoughtState)false; + // Do nothing if Pawn is Baby or Child (#25) + if (!pawn.ageTracker.Adult) + return (ThoughtState)false; + if (!other.ageTracker.Adult) + return (ThoughtState)false; + // Only check if they are spawned humans + if (!pawn.Spawned || !other.Spawned) + return (ThoughtState)false; + if (!pawn.RaceProps.Humanlike) + return (ThoughtState)false; + if (!other.RaceProps.Humanlike) + return (ThoughtState)false; + + // Pawns that have not "met" wont give each other Mali + // Known-Each-Other is a key-word for Rimworld that shows they have had any interaction and stored each other in relations. + if (!RelationsUtility.PawnsKnowEachOther(pawn, other)) + return (ThoughtState)false; + // If the pawn is not on Map (e.g. caravan), no mali + if (!MapUtility.PawnIsOnHomeMap(pawn)) + return (ThoughtState)false; + + int pawn_diseases = DiseaseHelper.GetGeneticDiseaseGenes(pawn).Count(); + int other_diseases = DiseaseHelper.GetGeneticDiseaseGenes(other).Count(); + int disease_diff = other_diseases - pawn_diseases; + + if (disease_diff >= 5) + return ThoughtState.ActiveAtStage(2); + else if (disease_diff >= 2) + return ThoughtState.ActiveAtStage(1); + else if (disease_diff >= 1) + return ThoughtState.ActiveAtStage(0); + else + return (ThoughtState)false; + } + } +} diff --git a/Source/Genes/Diseases/Thoughts/ThoughtWorker_SizeBlinded_Social.cs b/Source/Genes/Diseases/Thoughts/ThoughtWorker_SizeBlinded_Social.cs index 871b276..61199a6 100644 --- a/Source/Genes/Diseases/Thoughts/ThoughtWorker_SizeBlinded_Social.cs +++ b/Source/Genes/Diseases/Thoughts/ThoughtWorker_SizeBlinded_Social.cs @@ -44,7 +44,6 @@ namespace RJW_Genes if (!MapUtility.PawnIsOnHomeMap(pawn)) return (ThoughtState)false; - //ModLog.Debug($"ThoughtWorker Checks Size Blinded {pawn} -> {other}"); // Do nothing if there is no size-blinded involved if (!GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_size_blinded)) diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index 728b22f..0e0df2d 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -86,6 +86,7 @@ + diff --git a/Source/ThoughtDefOf.cs b/Source/ThoughtDefOf.cs index 50f2a00..596ecc0 100644 --- a/Source/ThoughtDefOf.cs +++ b/Source/ThoughtDefOf.cs @@ -16,6 +16,7 @@ namespace RJW_Genes public static readonly ThoughtDef rjw_genes_pheromone_carrier_nearby; public static readonly ThoughtDef rjw_genes_appealing_cock; + public static readonly ThoughtDef rjw_genes_has_more_diseases; //Others with same names but other defs than in genedefof public static readonly InteractionDef rjw_genes_flirt; From 614ce2bd035cd8122fd6c5bf46711cf23eac2dbf Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 12:52:52 +0200 Subject: [PATCH 6/8] Minor changes to the Statoffsets - still not all showing --- Common/Defs/GeneDefs/GeneDefs_Breeding.xml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Common/Defs/GeneDefs/GeneDefs_Breeding.xml b/Common/Defs/GeneDefs/GeneDefs_Breeding.xml index e90dc89..b3a9844 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Breeding.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Breeding.xml @@ -124,29 +124,27 @@
  • - - 0.7 - - -0.5 + -0.1 1.2 + 1.2 + -0.15 + -0.1
  • - - 1.05 - + 0.05 0.1 0.1 + 0.4
  • - - 1.1 - + 0.15 0.25 + 0.25
  • From b15f0c4d56e695ae10f0322f39a57f0c90b5ad78 Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 13:13:25 +0200 Subject: [PATCH 7/8] Simple Genes for Sex need and Fertility --- CHANGELOG.md | 2 + Common/Defs/GeneDefs/GeneDefs_Diseases.xml | 63 ++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c4c8e1..df36886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,8 @@ but they are meant mostly to have infectors immune against their own diseases. - Disease Gene: Vulnerability. Pawn is likelier to be raped - Disease Gene: Infectious Hypersexuality - Disease Gene: Infectious Homosexuality & Bisexuality +- Disease Gene: Infectious lower fertility +- Disease Gene: Infectious higher sex need - Disease Gene: Fluctual Sexual Need. (Configurable) Chance to reset sex-need to near-zero and gain a bit of rest-need. - Disease Gene: Size Blinded. Pawns have a higher chance for hooking up with pawns with a big cock, lower chance for small cocks. - Infector Gene: Genetic Stretcher. Pawns can infect other pawns with *Size Blinded* diff --git a/Common/Defs/GeneDefs/GeneDefs_Diseases.xml b/Common/Defs/GeneDefs/GeneDefs_Diseases.xml index 2570b65..b9c1a45 100644 --- a/Common/Defs/GeneDefs/GeneDefs_Diseases.xml +++ b/Common/Defs/GeneDefs/GeneDefs_Diseases.xml @@ -85,6 +85,69 @@ + + rjw_genes_infectious_low_fertility + + Carriers of this genetic disease have lower fertility. + 1 + 1 + 0.9 + UI/Icons/ColonistBar/Idle + 5 + + + -0.15 + + + +
  • + 0.05 +
  • +
    +
    + + + rjw_genes_infectious_increased_sex_need + + Carriers of this genetic disease need more sex. + 0 + 1 + 0.9 + UI/Icons/ColonistBar/Idle + 5 + + + 0.15 + + + +
  • + 0.08 +
  • +
    +
    + + + rjw_genes_infectious_major_increased_sex_need + + Carriers of this genetic disease need a lot more sex. + 1 + 2 + 0.85 + UI/Icons/ColonistBar/Idle + 5 + + + 1.0 + + + +
  • + 0.03 +
  • +
    +
    + rjw_genes_infectious_hypersexuality From b12e9afbc09f12f134895e43af27ad297e62213f Mon Sep 17 00:00:00 2001 From: Vegapnk Date: Thu, 4 Jul 2024 16:04:51 +0200 Subject: [PATCH 8/8] Added two genes for steal and swap genes on sex --- CHANGELOG.md | 4 +- Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml | 33 ++++++++- Source/Common/Defs/ChanceExtension.cs | 15 ++++ Source/GeneDefOf.cs | 2 + .../Special/Patches/Patch_GeneticSexSwap.cs | 69 +++++++++++++++++++ .../Special/Patches/Patch_GeneticSexThief.cs | 68 ++++++++++++++++++ .../Special/Patches/Patch_HormonalSaliva.cs | 1 - Source/Rjw-Genes.csproj | 3 + 8 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 Source/Common/Defs/ChanceExtension.cs create mode 100644 Source/Genes/Special/Patches/Patch_GeneticSexSwap.cs create mode 100644 Source/Genes/Special/Patches/Patch_GeneticSexThief.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index df36886..5b63394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,7 +68,7 @@ but they are meant mostly to have infectors immune against their own diseases. **Additions:** -- Passive Gene: *Genetic Disease Immunity* - cannot get infected by any genetic diseases, and won't be affected by some other genes (see relevant genes) +- Passive Gene: Genetic Disease Immunity. cannot get infected by any genetic diseases, and won't be affected by some other genes (see relevant genes) - Disease Gene: Vulnerability. Pawn is likelier to be raped - Disease Gene: Infectious Hypersexuality - Disease Gene: Infectious Homosexuality & Bisexuality @@ -78,6 +78,8 @@ but they are meant mostly to have infectors immune against their own diseases. - Disease Gene: Size Blinded. Pawns have a higher chance for hooking up with pawns with a big cock, lower chance for small cocks. - Infector Gene: Genetic Stretcher. Pawns can infect other pawns with *Size Blinded* - Gene: Hardwired Progenity. Pawns with this get a malus on having no-children, and bonus on having a lot. +- Gene: Sexual Genetic Swap. Pawns have a chance to switch a random gene with their sexpartner. +- (Archite) Gene: Sexual Genetic Thief. Pawns have a chance to steal a gene from their sexpartner. Genetic Disease Immunity shields against this. - Pawns will have negative thoughts about pawns with more genetic diseases than themselves. **Fixes:** diff --git a/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml b/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml index 189a6c8..0fe012a 100644 --- a/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml +++ b/Common/Defs/GeneDefs/GeneDefs_SexSpecial.xml @@ -140,7 +140,7 @@ rjw_genes_sex_tamer - + sextamer Bestiality has a chance to tame animals or advance their training. Genes/Icons/RJW_Genes_SexualTamer @@ -149,4 +149,35 @@ -1 + + rjw_genes_sexual_genetic_swap + + Carriers with this gene may switch a gene with their sex-partner. Switched Genes are always endogenes. + UI/Icons/Genes/Gene_PsychicBonding + 20 + 3 + 0 + +
  • + 0.1 +
  • +
    +
    + + + rjw_genes_sexual_genetic_thief + + Carriers with this gene may steal a gene from their sex-partner. Stolen genes are always xenogenes. + UI/Icons/Genes/Gene_PsychicBonding + 21 + 5 + -2 + 1 + +
  • + 0.2 +
  • +
    +
    + \ No newline at end of file diff --git a/Source/Common/Defs/ChanceExtension.cs b/Source/Common/Defs/ChanceExtension.cs new file mode 100644 index 0000000..ff8b260 --- /dev/null +++ b/Source/Common/Defs/ChanceExtension.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class ChanceExtension : DefModExtension + { + public float chance; + } + +} diff --git a/Source/GeneDefOf.cs b/Source/GeneDefOf.cs index f7612cc..873df6f 100644 --- a/Source/GeneDefOf.cs +++ b/Source/GeneDefOf.cs @@ -105,6 +105,8 @@ namespace RJW_Genes public static readonly GeneDef rjw_genes_hormonal_saliva; public static readonly GeneDef rjw_genes_cocoonweaver; public static readonly GeneDef rjw_genes_sex_tamer; + public static readonly GeneDef rjw_genes_sexual_genetic_swap; + public static readonly GeneDef rjw_genes_sexual_genetic_thief; // Cosmetic public static readonly GeneDef rjw_genes_succubus_tail; diff --git a/Source/Genes/Special/Patches/Patch_GeneticSexSwap.cs b/Source/Genes/Special/Patches/Patch_GeneticSexSwap.cs new file mode 100644 index 0000000..377b71d --- /dev/null +++ b/Source/Genes/Special/Patches/Patch_GeneticSexSwap.cs @@ -0,0 +1,69 @@ +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_GeneticSexSwap + { + 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 (pawn.genes == null || partner.genes == null) return; + + // If both have the swap gene, nothing happens + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_sexual_genetic_swap) + && GeneUtility.HasGeneNullCheck(partner, GeneDefOf.rjw_genes_sexual_genetic_swap)) + return; + // If neither has the swap gene, nothing happens + if (!GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_sexual_genetic_swap) + && !GeneUtility.HasGeneNullCheck(partner, GeneDefOf.rjw_genes_sexual_genetic_swap)) + return; + + ChanceExtension chanceExt = GeneDefOf.rjw_genes_sexual_genetic_swap.GetModExtension(); + if (chanceExt != null && (new Random()).NextDouble() < chanceExt.chance) + SwapOneRandomGene(pawn, partner); + } + + /// + /// Removes a random gene from one pawn and adds it too the other as xenogene. + /// The "gene swap" gene cannot be swapped! + /// + private static void SwapOneRandomGene(Pawn a, Pawn b, bool AddAsXenogene = true) + { + + var geneFromA = a.genes.GenesListForReading + .Where(gene => a.genes.HasActiveGene(gene.def)) + .Where(gene => gene.def != GeneDefOf.rjw_genes_sexual_genetic_swap) + .RandomElement(); + var geneFromB = b.genes.GenesListForReading + .Where(gene => b.genes.HasActiveGene(gene.def)) + .Where(gene => gene.def != GeneDefOf.rjw_genes_sexual_genetic_swap) + .RandomElement(); + + if (geneFromA == null || geneFromB == null) return; + + ModLog.Debug($"Sexual Genetic Swap: Swapping {geneFromA.def} from {a} with {geneFromB.def} from {b}"); + + a.genes.AddGene(geneFromB.def, AddAsXenogene); + b.genes.AddGene(geneFromA.def, AddAsXenogene); + a.genes.RemoveGene(geneFromA); + b.genes.RemoveGene(geneFromB); + } + + } +} diff --git a/Source/Genes/Special/Patches/Patch_GeneticSexThief.cs b/Source/Genes/Special/Patches/Patch_GeneticSexThief.cs new file mode 100644 index 0000000..ecc2201 --- /dev/null +++ b/Source/Genes/Special/Patches/Patch_GeneticSexThief.cs @@ -0,0 +1,68 @@ +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_GeneticSexThief + { + 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 (pawn.genes == null || partner.genes == null) return; + + // If both have the swap gene, nothing happens + if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_sexual_genetic_thief) + && GeneUtility.HasGeneNullCheck(partner, GeneDefOf.rjw_genes_sexual_genetic_thief)) + return; + + if (GeneUtility.HasGeneNullCheck(pawn,GeneDefOf.rjw_genes_sexual_genetic_thief) && + !GeneUtility.HasGeneNullCheck(partner, GeneDefOf.rjw_genes_genetic_disease_immunity)) + { + ChanceExtension chanceExt = GeneDefOf.rjw_genes_sexual_genetic_thief.GetModExtension(); + if (chanceExt != null && (new Random()).NextDouble() < chanceExt.chance) + StealRandomGene(pawn, partner); + } + + if (GeneUtility.HasGeneNullCheck(partner, GeneDefOf.rjw_genes_sexual_genetic_thief) && + !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_genetic_disease_immunity)) + { + ChanceExtension chanceExt = GeneDefOf.rjw_genes_sexual_genetic_thief.GetModExtension(); + if (chanceExt != null && (new Random()).NextDouble() < chanceExt.chance) + StealRandomGene(partner, pawn); + } + } + + /// + /// Removes a random gene from one pawn and adds it too the other as xenogene. + /// + private static void StealRandomGene(Pawn stealer, Pawn victim, bool AddAsXenogene = true) + { + var stolenGene = victim.genes.GenesListForReading + .Where(gene => victim.genes.HasActiveGene(gene.def)) + .RandomElement(); + + if (stolenGene == null) return; + + ModLog.Debug($"Sexual Gene Thief: {stealer} steals {stolenGene.def} from {victim}"); + + stealer.genes.AddGene(stolenGene.def, AddAsXenogene); + victim.genes.RemoveGene(stolenGene); + } + + } +} diff --git a/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs b/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs index 150eeec..fed69d7 100644 --- a/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs +++ b/Source/Genes/Special/Patches/Patch_HormonalSaliva.cs @@ -12,7 +12,6 @@ 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; diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index 0e0df2d..306bcb7 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -56,6 +56,7 @@ + @@ -188,6 +189,8 @@ + +