mirror of
				https://github.com/vegapnk/RJW-Genes.git
				synced 2024-08-15 00:23:31 +00:00 
			
		
		
		
	1.5 update
This commit is contained in:
		
							parent
							
								
									7d9e399a47
								
							
						
					
					
						commit
						e6db43f31d
					
				
					 231 changed files with 95 additions and 6968 deletions
				
			
		| 
						 | 
				
			
			@ -32,7 +32,8 @@ 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;
 | 
			
		||||
        public static readonly GeneDef rjw_genes_femboy;
 | 
			
		||||
        public static readonly GeneDef rjw_genes_featureless_chest;
 | 
			
		||||
 | 
			
		||||
        // Genitalia Sizes
 | 
			
		||||
        public static readonly GeneDef rjw_genes_big_male_genitalia;
 | 
			
		||||
| 
						 | 
				
			
			@ -52,8 +53,6 @@ namespace RJW_Genes
 | 
			
		|||
 | 
			
		||||
		// Breeding
 | 
			
		||||
		public static readonly GeneDef rjw_genes_mechbreeder;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_insectincubator;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_insectbreeder;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_zoophile;
 | 
			
		||||
 | 
			
		||||
		// Cum 
 | 
			
		||||
| 
						 | 
				
			
			@ -83,35 +82,7 @@ namespace RJW_Genes
 | 
			
		|||
		public static readonly GeneDef rjw_genes_sexual_mytosis;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_hormonal_saliva;
 | 
			
		||||
 | 
			
		||||
        // LifeForce
 | 
			
		||||
        public static readonly GeneDef rjw_genes_lifeforce;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_pussyhealing;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_lifeforce_drain;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_cum_eater;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_fertilin_absorber;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_drainer;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_seduce;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_paralysingkiss;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_cockeater;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_lifeforce_empath;
 | 
			
		||||
 | 
			
		||||
        // Cosmetic
 | 
			
		||||
        public static readonly GeneDef rjw_genes_succubus_tail;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_succubus_wings;
 | 
			
		||||
 | 
			
		||||
		// Hive 
 | 
			
		||||
		public static readonly GeneDef rjw_genes_queen;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_drone;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_worker;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_zealous_loyalty;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_cocoonweaver;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_spawn_spelopede;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		//Other Defs
 | 
			
		||||
		public static readonly XenotypeDef rjw_genes_succubus;
 | 
			
		||||
		public static readonly DutyDef rjw_genes_flirt;
 | 
			
		||||
		public static readonly MentalBreakDef rjw_genes_lifeforce_randomrape;
 | 
			
		||||
       
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,6 @@ using HarmonyLib;
 | 
			
		|||
using rjw;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using LicentiaLabs;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ using HarmonyLib;
 | 
			
		|||
using rjw;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using LicentiaLabs;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -29,13 +29,6 @@ namespace RJW_Genes
 | 
			
		|||
            // I could have done some transpiler stuff, but that is scary and might need to be adjusted quite a lot 
 | 
			
		||||
            // Hence, I simply re-book the nutrition back to the giver in the Postfix. That should be robust and easy. 
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.IsGenerousDonor(giver)) { 
 | 
			
		||||
                float donatedNutrition = CumflationHelper.CalculateNutritionAmount(giver, cumAmount);
 | 
			
		||||
                // TODO: In theory, there could be something weird happening if the donor has food less than X and the "IgnoreThermodynamics" is set on. 
 | 
			
		||||
                // Then it can happen that the donor ends up with more food than he had before cumshot, but I think that is somewhat funny given that you have ignore Thermodynamics on. 
 | 
			
		||||
                Need_Food inflatorFood = giver.needs.TryGetNeed<Need_Food>();
 | 
			
		||||
                inflatorFood.CurLevel += donatedNutrition;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,51 +0,0 @@
 | 
			
		|||
using LicentiaLabs;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This Gene adds Licentia-Labs Elasticised Hediff to a Pawn. 
 | 
			
		||||
    /// Note: I had a HarmonyPatch first, similar to skipping cumflation, but the Stretching Logic is called quite a lot and for both pawns actually.
 | 
			
		||||
    /// Hence, I think choosing the Elasticiced Hediff was good as then everything is covered by "Licentia-Logic". 
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class Gene_Elasticity : Gene
 | 
			
		||||
    {
 | 
			
		||||
        private const int RESET_INTERVAL = 60000; // 60k should be 1 day 
 | 
			
		||||
 | 
			
		||||
        public override void PostAdd()
 | 
			
		||||
        {
 | 
			
		||||
            base.PostAdd();
 | 
			
		||||
            // Doing it like this will add the hediff with a severity of ~0.5, but it will decay.
 | 
			
		||||
            // Hence we check with the Ticks to update.
 | 
			
		||||
            this.pawn.health.AddHediff(Licentia.HediffDefs.Elasticised); 
 | 
			
		||||
            ResetSeverity();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Tick()
 | 
			
		||||
        {
 | 
			
		||||
            base.Tick();
 | 
			
		||||
            if (pawn.IsHashIntervalTick(RESET_INTERVAL))
 | 
			
		||||
                ResetSeverity();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void PostRemove()
 | 
			
		||||
        {
 | 
			
		||||
            Hediff candidate = pawn.health.hediffSet.GetFirstHediffOfDef(Licentia.HediffDefs.Elasticised);
 | 
			
		||||
            if (candidate != null)
 | 
			
		||||
            {
 | 
			
		||||
                pawn.health.RemoveHediff(candidate);
 | 
			
		||||
            }
 | 
			
		||||
            base.PostRemove();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private void ResetSeverity(float severity = 0.7f)
 | 
			
		||||
        {
 | 
			
		||||
            Hediff candidate = pawn.health.hediffSet.GetFirstHediffOfDef(Licentia.HediffDefs.Elasticised);
 | 
			
		||||
            if (candidate != null)
 | 
			
		||||
            {
 | 
			
		||||
                candidate.Severity = severity;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								Source/Genes/ExtraGenitalia/Gene_Femboy.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Source/Genes/ExtraGenitalia/Gene_Femboy.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
using rjw;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class Gene_Femboy : RJW_Gene
 | 
			
		||||
    {
 | 
			
		||||
        // Token: 0x06000335 RID: 821 RVA: 0x0000401D File Offset: 0x0000221D
 | 
			
		||||
        public override void PostMake()
 | 
			
		||||
        {
 | 
			
		||||
            base.PostMake();
 | 
			
		||||
            if (GenderUtility.IsMale(this.pawn) && this.additional_genital == null)
 | 
			
		||||
            {
 | 
			
		||||
                this.CreateAndAddVagina();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Token: 0x06000336 RID: 822 RVA: 0x00004040 File Offset: 0x00002240
 | 
			
		||||
        public override void PostAdd()
 | 
			
		||||
        {
 | 
			
		||||
            base.PostAdd();
 | 
			
		||||
            if (this.pawn.gender == Gender.Male && this.additional_genital == null)
 | 
			
		||||
            {
 | 
			
		||||
                this.CreateAndAddVagina();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Token: 0x06000337 RID: 823 RVA: 0x0000EE4C File Offset: 0x0000D04C
 | 
			
		||||
        internal void CreateAndAddVagina()
 | 
			
		||||
        {
 | 
			
		||||
            if (this.pawn.gender != Gender.Female)
 | 
			
		||||
            {
 | 
			
		||||
                GenderHelper.ChangeSex(this.pawn, delegate ()
 | 
			
		||||
                {
 | 
			
		||||
                    this.pawn.gender = Gender.Female;
 | 
			
		||||
                    GenitaliaChanger.RemoveAllGenitalia(this.pawn);
 | 
			
		||||
                    Sexualizer.sexualize_pawn(this.pawn);
 | 
			
		||||
                });
 | 
			
		||||
                GenderUtility.AdjustBodyToTargetGender(this.pawn, Gender.Female);
 | 
			
		||||
            }
 | 
			
		||||
            BodyPartRecord bodyPartRecord = Genital_Helper.get_genitalsBPR(this.pawn);
 | 
			
		||||
            Hediff hediff = Genital_Helper.get_AllPartsHediffList(this.pawn).FindLast((Hediff x) => Genital_Helper.is_vagina(x));
 | 
			
		||||
            if (hediff != null)
 | 
			
		||||
            {
 | 
			
		||||
                this.pawn.health.RemoveHediff(hediff);
 | 
			
		||||
            }
 | 
			
		||||
            HediffDef penisForGene = GenitaliaUtility.GetPenisForGene(GenitaliaUtility.GetGenitaliaTypeGeneForPawn(this.pawn));
 | 
			
		||||
            BodyPartRecord part = Genital_Helper.get_genitalsBPR(this.pawn);
 | 
			
		||||
            this.additional_genital = HediffMaker.MakeHediff(penisForGene, this.pawn, null);
 | 
			
		||||
            CompHediffBodyPart compHediffBodyPart = this.additional_genital.TryGetComp<CompHediffBodyPart>();
 | 
			
		||||
            if (compHediffBodyPart != null)
 | 
			
		||||
            {
 | 
			
		||||
                compHediffBodyPart.initComp(this.pawn, false);
 | 
			
		||||
                compHediffBodyPart.updatesize(0f);
 | 
			
		||||
            }
 | 
			
		||||
            this.pawn.health.AddHediff(this.additional_genital, part, null, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Token: 0x040001B0 RID: 432
 | 
			
		||||
        internal Hediff additional_genital;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,6 @@ namespace RJW_Genes
 | 
			
		|||
            } 
 | 
			
		||||
 | 
			
		||||
            // Force Redraw at the spot
 | 
			
		||||
            pawn.Drawer.renderer.graphics.SetAllGraphicsDirty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fetch these once at load time because they don't change inside RJW
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -138,7 +138,6 @@ namespace RJW_Genes
 | 
			
		|||
 | 
			
		||||
            SwitchBreasts();
 | 
			
		||||
 | 
			
		||||
            RemoveLicentiaVaginaHediffs();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -199,38 +198,7 @@ namespace RJW_Genes
 | 
			
		|||
        /// Checks the pawn if it has any of the vagina-related hediffs (e.g. stretched) and removes them.
 | 
			
		||||
        /// Anal Soreness, Stretching etc. remains. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        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.
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
       
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			@ -252,8 +220,6 @@ namespace RJW_Genes
 | 
			
		|||
                
 | 
			
		||||
                || (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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,81 +7,10 @@ namespace RJW_Genes
 | 
			
		|||
    public class GeneUtility
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        //Split function so I can offsetlifeforce from gene without needing to look for the gene agian (for the constant drain tick)
 | 
			
		||||
        public static Gene_LifeForce GetLifeForceGene(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            Pawn_GeneTracker genes = pawn.genes;
 | 
			
		||||
            Gene_LifeForce gene_LifeForce = genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
            return gene_LifeForce;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void OffsetLifeForce(IGeneResourceDrain drain, float offset)
 | 
			
		||||
        {                
 | 
			
		||||
            if (drain.Resource != null && drain.Resource.Active) {  
 | 
			
		||||
                float old_value = drain.Resource.Value;
 | 
			
		||||
                drain.Resource.Value += offset;
 | 
			
		||||
                PostOffSetLifeForce(drain, old_value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void PostOffSetLifeForce(IGeneResourceDrain drain, float old_value)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            if (drain.Resource != null && drain.Resource.Active)
 | 
			
		||||
            {
 | 
			
		||||
                if (old_value > 0.2f && drain.Resource.Value <= 0.2f)
 | 
			
		||||
                {
 | 
			
		||||
                    //TODO: Mood debuff
 | 
			
		||||
                }
 | 
			
		||||
                else if (old_value > 0f && drain.Resource.Value <= 0f)
 | 
			
		||||
                {
 | 
			
		||||
                    Pawn pawn = drain.Pawn;
 | 
			
		||||
                    if (!drain.Pawn.health.hediffSet.HasHediff(HediffDefOf.rjw_genes_fertilin_craving))
 | 
			
		||||
                    {
 | 
			
		||||
                        drain.Pawn.health.AddHediff(HediffDefOf.rjw_genes_fertilin_craving);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static bool HasLowLifeForce(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            if (HasLifeForce(pawn))
 | 
			
		||||
            {
 | 
			
		||||
                Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType<Gene_LifeForce>(); 
 | 
			
		||||
                if (gene == null || !gene.Active)
 | 
			
		||||
                    return false;
 | 
			
		||||
                if (gene.Resource.Value < gene.targetValue)
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool HasCriticalLifeForce(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            if (HasLifeForce(pawn))
 | 
			
		||||
            {
 | 
			
		||||
                Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
                if (gene == null || !gene.Active)
 | 
			
		||||
                    return false;
 | 
			
		||||
                if (gene.Resource.Value < gene.MinLevelForAlert)
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static float MaxEggSizeMul(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            float MaxEggSize = 1;
 | 
			
		||||
            if (IsInsectIncubator(pawn))
 | 
			
		||||
            {
 | 
			
		||||
                MaxEggSize *= 2;
 | 
			
		||||
            }
 | 
			
		||||
          
 | 
			
		||||
            return MaxEggSize;
 | 
			
		||||
        }
 | 
			
		||||
        public static List<Gene_GenitaliaResizingGene> GetGenitaliaResizingGenes(Pawn pawn)
 | 
			
		||||
| 
						 | 
				
			
			@ -115,21 +44,13 @@ namespace RJW_Genes
 | 
			
		|||
            return pawn.genes.HasGene(genedef);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool HasLifeForce(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_lifeforce); }
 | 
			
		||||
        public static bool IsMechbreeder(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_mechbreeder); }
 | 
			
		||||
        public static bool IsInsectIncubator(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_insectincubator); }
 | 
			
		||||
        public static bool IsYouthFountain(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_youth_fountain); }
 | 
			
		||||
        public static bool IsAgeDrainer(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_sex_age_drain); }
 | 
			
		||||
        public static bool IsInsectBreeder(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_insectbreeder); }
 | 
			
		||||
        public static bool IsElastic(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_elasticity); }
 | 
			
		||||
        public static bool IsCumflationImmune(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_cumflation_immunity); }
 | 
			
		||||
        public static bool IsGenerousDonor(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_generous_donor); }
 | 
			
		||||
        public static bool IsPussyHealer(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_pussyhealing); }
 | 
			
		||||
        public static bool IsUnbreakable(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_unbreakable); }
 | 
			
		||||
        public static bool HasParalysingKiss(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_paralysingkiss); }
 | 
			
		||||
        public static bool HasSeduce(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_seduce); }
 | 
			
		||||
        public static bool IsSexualDrainer(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_drainer); }
 | 
			
		||||
        public static bool IsCumEater(Pawn pawn) { return HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_cum_eater); }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,81 +0,0 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// The CocoonWeaver Ability applies the RJW-Cocoon to a pawn.
 | 
			
		||||
	/// Friendly Pawns can always be cocooned, neutral and hostile pawns must be downed. 
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public class CompAbilityEffect_CocoonWeaver : CompAbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		private new CompProperties_AbilityCocoonWeaver Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (CompProperties_AbilityCocoonWeaver)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
 | 
			
		||||
		{
 | 
			
		||||
			base.Apply(target, dest);
 | 
			
		||||
 | 
			
		||||
			Pawn CocooningPawn = this.parent.pawn;
 | 
			
		||||
			Pawn PawnToCocoon = target.Pawn;
 | 
			
		||||
			
 | 
			
		||||
			// Error Case - Null Pawn
 | 
			
		||||
			if (PawnToCocoon == null)
 | 
			
		||||
			{
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			PawnToCocoon.health.AddHediff(HediffDef.Named("RJW_Cocoon"));
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// For validity, there are a few checks:
 | 
			
		||||
		/// 0. Target is not already cocooned 
 | 
			
		||||
		/// 1. Target is either Colonist / Prisoner 
 | 
			
		||||
		/// 2. If the Target is an enemy or neutral, it must be downed. 
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn cocoonTarget = target.Pawn;
 | 
			
		||||
			if (cocoonTarget != null)
 | 
			
		||||
			{
 | 
			
		||||
				bool CocoonTargetIsColonistOrPrisoner = cocoonTarget.Faction == this.parent.pawn.Faction || cocoonTarget.IsPrisonerOfColony;
 | 
			
		||||
				bool CocoonTargetIsHostile = cocoonTarget.HostileTo(this.parent.pawn);
 | 
			
		||||
				bool CocoonTargetIsDowned = cocoonTarget.Downed;
 | 
			
		||||
 | 
			
		||||
				if (cocoonTarget.health.hediffSet.hediffs.Any(t => t.def.defName == "RJW_Cocoon"))
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
						Messages.Message(cocoonTarget.Name + " is already cocooned.", cocoonTarget, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
				if (!CocoonTargetIsColonistOrPrisoner && !(CocoonTargetIsHostile && CocoonTargetIsDowned))
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						if(CocoonTargetIsHostile && !CocoonTargetIsDowned)
 | 
			
		||||
                        {
 | 
			
		||||
							Messages.Message(cocoonTarget.Name + " is hostile, but not downed.", cocoonTarget, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
						}
 | 
			
		||||
						else if (!CocoonTargetIsColonistOrPrisoner)
 | 
			
		||||
						{
 | 
			
		||||
							Messages.Message(cocoonTarget.Name + " is not a part of the colony or hostile.", cocoonTarget, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return base.Valid(target, throwMessages);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,80 +0,0 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using RimWorld.Planet;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// Spawns tame spelopedes at the caster.
 | 
			
		||||
    /// 
 | 
			
		||||
    /// TODO: Play some sound? I think this can be done with some CompProperties. 
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public class CompAbilityEffect_SpawnSpelopede : CompAbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
        public CompProperties_AbilitySpawnSpelopede Props => (CompProperties_AbilitySpawnSpelopede) this.props;
 | 
			
		||||
 | 
			
		||||
        public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
 | 
			
		||||
        {
 | 
			
		||||
            base.Apply(target, dest);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            int spelopedesToSpawn = CalculateSpelopedeAmount();
 | 
			
		||||
            if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Using Spelopede Spawn, spawning {spelopedesToSpawn}");
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < spelopedesToSpawn; i++) { 
 | 
			
		||||
                var request =  new PawnGenerationRequest(
 | 
			
		||||
                    this.Props.pawnKindDef, 
 | 
			
		||||
                    faction: this.parent.pawn.Faction, 
 | 
			
		||||
                    forceGenerateNewPawn: true,
 | 
			
		||||
                    fixedBiologicalAge: 0.0f,
 | 
			
		||||
                    fixedChronologicalAge: 0.0f,
 | 
			
		||||
                    canGeneratePawnRelations: false,
 | 
			
		||||
                    colonistRelationChanceFactor: 0.0f
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                Pawn insect = PawnGenerator.GeneratePawn(request);
 | 
			
		||||
                PawnUtility.TrySpawnHatchedOrBornPawn(insect, this.parent.pawn);
 | 
			
		||||
 | 
			
		||||
                if (Props.tamed)
 | 
			
		||||
                {
 | 
			
		||||
                    insect.training.Train(TrainableDefOf.Tameness, this.parent.pawn, true);
 | 
			
		||||
                    insect.training.Train(TrainableDefOf.Obedience, this.parent.pawn, true);
 | 
			
		||||
                    insect.training.Train(TrainableDefOf.Release, this.parent.pawn, true);
 | 
			
		||||
 | 
			
		||||
                    // I could do bonding here, but I think it's nicer if the queen is not "bonded" to their offspring. 
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MakeDirt(1);
 | 
			
		||||
 | 
			
		||||
            if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message("Finished Spelopede Spawn");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private int CalculateSpelopedeAmount()
 | 
			
		||||
        {
 | 
			
		||||
            Pawn caster = this.parent.pawn;
 | 
			
		||||
            float spelopedes = Props.sensitivityMultiplier * caster.psychicEntropy.PsychicSensitivity;
 | 
			
		||||
            return (spelopedes > 1.49f) ? (int)Math.Round(spelopedes) : 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void MakeDirt(int multiplier = 1)
 | 
			
		||||
        {
 | 
			
		||||
            Pawn caster = this.parent.pawn;
 | 
			
		||||
 | 
			
		||||
            FilthMaker.TryMakeFilth(caster.Position, caster.Map, ThingDefOf.Filth_AmnioticFluid, caster.LabelIndefinite(), count: Rand.Range(5,5*multiplier));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
 | 
			
		||||
        {
 | 
			
		||||
            if (!target.Cell.Filled(this.parent.pawn.Map) && (target.Cell.GetEdifice(this.parent.pawn.Map) == null))
 | 
			
		||||
                return true;
 | 
			
		||||
            if (throwMessages)
 | 
			
		||||
                Messages.Message((string)("CannotUseAbility".Translate((NamedArgument)this.parent.def.label) + ": " + "AbilityOccupiedCells".Translate()), (LookTargets)target.ToTargetInfo(this.parent.pawn.Map), MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompProperties_AbilityCocoonWeaver : CompProperties_AbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		public CompProperties_AbilityCocoonWeaver()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_CocoonWeaver);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,21 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompProperties_AbilitySpawnSpelopede : CompProperties_AbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		public PawnKindDef pawnKindDef;
 | 
			
		||||
		public float sensitivityMultiplier;
 | 
			
		||||
		public bool tamed;
 | 
			
		||||
		public CompProperties_AbilitySpawnSpelopede()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_SpawnSpelopede);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class HiveOffspringChanceDef : Def 
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        public string queenXenotype;
 | 
			
		||||
 | 
			
		||||
        // Chance of the below should be 1 when summed up! 
 | 
			
		||||
        // Otherwise the roll-logic fails.
 | 
			
		||||
 | 
			
		||||
        public double queenChance;
 | 
			
		||||
        public double droneChance;
 | 
			
		||||
        public double workerChance;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This def covers the birth of workers for each queen-xenotype. 
 | 
			
		||||
    /// 
 | 
			
		||||
    /// It is used when a baby is born to a pawn with the queen-xenotype; 
 | 
			
		||||
    /// There is a random check for the type of the baby, and if the baby is born to be a worker, 
 | 
			
		||||
    /// additional genes are looked up here. 
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class QueenWorkerMappingDef : Def
 | 
			
		||||
    {
 | 
			
		||||
        public string queenXenotype;
 | 
			
		||||
        public List<string> workerGenes;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Checks if there are multiple queens on the map.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class ConditionalStatAffecter_MultipleQueens : ConditionalStatAffecter
 | 
			
		||||
    {
 | 
			
		||||
        public override string Label => (string)"StatsReport_MultipleQueens".Translate();
 | 
			
		||||
 | 
			
		||||
        public override bool Applies(StatRequest req)
 | 
			
		||||
        {
 | 
			
		||||
            if (req.Pawn == null || !req.Pawn.Spawned)
 | 
			
		||||
                return false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(req.Pawn))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty))
 | 
			
		||||
            {
 | 
			
		||||
                return HiveUtility.QueensOnMap() >= 2;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        } 
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Checks if there is no queen on the map.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class ConditionalStatAffecter_QueenAbsent : ConditionalStatAffecter
 | 
			
		||||
    {
 | 
			
		||||
        public override string Label => (string)"StatsReport_QueenAbsent".Translate();
 | 
			
		||||
 | 
			
		||||
        public override bool Applies(StatRequest req)
 | 
			
		||||
        {
 | 
			
		||||
            if (req.Pawn == null || !req.Pawn.Spawned)
 | 
			
		||||
                return false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(req.Pawn))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty))
 | 
			
		||||
            {
 | 
			
		||||
                return HiveUtility.QueensOnMap() == 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,55 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Checks if there is (exactly) one queen nearby. 
 | 
			
		||||
    /// If the pawn is a queen itself, it's checked if there are OTHER queens nearby.
 | 
			
		||||
    /// While this is used for mostly positive things for workers and drones, for queens it checks if there is a rival nearby.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class ConditionalStatAffecter_QueenCloseBy : ConditionalStatAffecter
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        const float EFFECT_DISTANCE = 10.0f;
 | 
			
		||||
 | 
			
		||||
        public override string Label => (string)"StatsReport_QueenCloseBy".Translate();
 | 
			
		||||
 | 
			
		||||
        public override bool Applies(StatRequest req)
 | 
			
		||||
        {
 | 
			
		||||
            if (req.Pawn == null || !req.Pawn.Spawned)
 | 
			
		||||
                return false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(req.Pawn))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            // Case A: Check for Loyal Pawns if their One Queen is nearby
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 1)
 | 
			
		||||
            {
 | 
			
		||||
                Pawn queen = HiveUtility.GetQueensOnMap()[0];
 | 
			
		||||
 | 
			
		||||
                return req.Pawn.Position.DistanceTo(queen.Position) <= EFFECT_DISTANCE;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Case A: Check for Queen if another Queen is nearby
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() >= 2)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (Pawn queen in HiveUtility.GetQueensOnMap())
 | 
			
		||||
                {
 | 
			
		||||
                    if (queen != req.Pawn && req.Pawn.Position.DistanceTo(queen.Position) <= EFFECT_DISTANCE)
 | 
			
		||||
                        return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,42 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using Verse;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Manages the rjw_genes_fervent_ovipositor to grow eggs much faster.
 | 
			
		||||
    /// 
 | 
			
		||||
    /// TODO: Move the Multiplier into XML 
 | 
			
		||||
    /// TODO: This gene only works after the first egg, the first egg for two new pawns spawns at the same time (strange). 
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class Gene_FerventOvipositor : Gene
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        const int MULTIPLIER = 3; // Tick 3 times as much, making a pawn with this Gene Produce Eggs 4 times as fast as the normal.
 | 
			
		||||
 | 
			
		||||
        public override void Tick()
 | 
			
		||||
        {
 | 
			
		||||
            base.Tick();
 | 
			
		||||
 | 
			
		||||
            if (pawn == null) return;
 | 
			
		||||
 | 
			
		||||
            Hediff_PartBaseNatural OvipositorF = (Hediff_PartBaseNatural) pawn.health.hediffSet.GetFirstHediffOfDef(rjw.Genital_Helper.ovipositorF);
 | 
			
		||||
 | 
			
		||||
            if (OvipositorF == null) return;
 | 
			
		||||
 | 
			
		||||
            OvipositorF.nextEggTick = Math.Max(OvipositorF.nextEggTick - MULTIPLIER, -1);
 | 
			
		||||
 | 
			
		||||
            // DevNote: I first had a for-loop calling OviPositorF.tick(), but I fear that would be a performance sink.
 | 
			
		||||
            // Also, it would double other aspects as well, such as bleeding out through your insect-PP or dropping out the eggs.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,69 +0,0 @@
 | 
			
		|||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This Gene checks for all parasitic Insect-Eggs in a Pawn:
 | 
			
		||||
    /// 1. Is it fertilized ? => tick it down "extra".
 | 
			
		||||
    /// 2. Is it not fertilized? => fertilize it with the Incubator as parent
 | 
			
		||||
    /// 
 | 
			
		||||
    /// To save performance, this gene fires (default) every 0.5h, which also means a slight delay until fertilization happens. 
 | 
			
		||||
    /// 
 | 
			
		||||
    /// Important: The other half of the behavior for the gene (more egg-capacity) is in `Patch_InsectINcubator_PregnancyHelper`.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class Gene_InsectIncubator : Gene
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        const int TICK_INTERVAL = 60000 / 48; // 60k = 1 day, we want 0.5h which is 1/48th of 1 day. 
 | 
			
		||||
 | 
			
		||||
        public override void Tick()
 | 
			
		||||
        {
 | 
			
		||||
            base.Tick();
 | 
			
		||||
 | 
			
		||||
            // Don't check too often, only in the HashTickInterval to safe some computing power
 | 
			
		||||
            if (this.pawn.IsHashIntervalTick(TICK_INTERVAL) && this.pawn.Map != null)
 | 
			
		||||
            {
 | 
			
		||||
                List<Hediff_InsectEgg> eggs = new List<Hediff_InsectEgg>();
 | 
			
		||||
                pawn.health.hediffSet.GetHediffs<Hediff_InsectEgg>(ref eggs);
 | 
			
		||||
                // This part works as intended and shows Non-Human Eggs too
 | 
			
		||||
                //if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Gene_InsectIncubator: Found {eggs.Count} Hediff_InsectEgg in {pawn}");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                foreach (Hediff_InsectEgg egg in eggs)
 | 
			
		||||
                {
 | 
			
		||||
                    // The implanter check checks if the egg is still in an ovipositor. 
 | 
			
		||||
                    if (egg.implanter == null || egg.implanter == pawn)
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
                    if (!egg.fertilized && egg.implanter != null) { 
 | 
			
		||||
                        egg.Fertilize(pawn);
 | 
			
		||||
                        // DevNote Issue 38: Sometimes Eggs are not fertilized here, because the normal Fertilize Function is called which has an upper Limit on Gestation.
 | 
			
		||||
                        // I will not do anything about it here, maybe upstream, but I print here. 
 | 
			
		||||
                        if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (egg.fertilized)
 | 
			
		||||
                                ModLog.Message($"Gene_InsectIncubator: fertilized egg {egg} in {pawn}");
 | 
			
		||||
                            else if (egg.GestationProgress > 0.5)
 | 
			
		||||
                                ModLog.Message($"Gene_InsectIncubator: Failed to fertilize {egg} in {pawn} due to high gestation progress");
 | 
			
		||||
                            else
 | 
			
		||||
                                ModLog.Message($"Gene_InsectIncubator: failed to fertiliz egg {egg} in {pawn}");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    // DevNote: There is an issue with Eggs reaching too much gestation progress (>100%), which causes DownStream bugs. To avoid this, there are some extra checks in place.  
 | 
			
		||||
                    else if (egg.fertilized && egg.GestationProgress <= .93)
 | 
			
		||||
                    {
 | 
			
		||||
                        egg.lastTick += TICK_INTERVAL;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,202 +0,0 @@
 | 
			
		|||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection.Emit;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// DevNote: Issue #37 came along because I checked for getMother() and getFather(), but it can happen that a pawn has two mothers. 
 | 
			
		||||
    /// They are called Mother if they have a ParentRelation and are female.
 | 
			
		||||
    /// New behaviour iterates over all parents and returns the first queen/drone or null.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class HiveBirthLogic
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Central function for the Hive-Birth logic used in Patches. 
 | 
			
		||||
        /// *Only* run this, if the pawn has a queen parent (either as mother/father, or as implanter in case of egg-logic).
 | 
			
		||||
        /// Covers the following behavior:
 | 
			
		||||
        /// 1. look up the Defs for the mother and HiveOffspringChances (or defaults)
 | 
			
		||||
        /// 2. If there is no drone involved, default to worker
 | 
			
		||||
        /// 3. Roll a random dice
 | 
			
		||||
        /// 3.1 Make a queen
 | 
			
		||||
        /// 3.2 Make a drone 
 | 
			
		||||
        /// 3.3 Make a worker
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn">The pawn born, that maybe becomes a hive-xenotype.</param>
 | 
			
		||||
        /// <param name="hasDroneParent">whether there was a drone parent involved</param>
 | 
			
		||||
        public static void ManageHiveBirth(Pawn pawn, bool hasDroneParent = false, Either<XenotypeDef, CustomXenotype> fallbackQueenDef = null, Either<XenotypeDef, CustomXenotype> fallbackDroneDef = null)
 | 
			
		||||
        {
 | 
			
		||||
            Either<XenotypeDef,CustomXenotype> queenDef = TryFindParentQueenXenotype(pawn);
 | 
			
		||||
            if (queenDef == null) queenDef = fallbackQueenDef;
 | 
			
		||||
            HiveOffspringChanceDef hiveOffspringChanceDef = HiveUtility.LookupHiveInheritanceChances(queenDef);
 | 
			
		||||
 | 
			
		||||
            // Case 1: Mother is Queen, Father is something else. Produce Worker.
 | 
			
		||||
            if (!hasDroneParent)
 | 
			
		||||
            {
 | 
			
		||||
                if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} was born as a worker, as it did not have Drone Father ({100}% chance)");
 | 
			
		||||
                MakeWorker(pawn, queenDef);
 | 
			
		||||
            }
 | 
			
		||||
            // Case 2: Mother is Queen, Father is drone. Apply xenotype as per chance.
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                double roll = (new Random()).NextDouble();
 | 
			
		||||
                // Case 2.a: New Queen born
 | 
			
		||||
                if (roll < hiveOffspringChanceDef.queenChance)
 | 
			
		||||
                {
 | 
			
		||||
                    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)
 | 
			
		||||
                {
 | 
			
		||||
                    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
 | 
			
		||||
                {
 | 
			
		||||
                    if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a worker ({(hiveOffspringChanceDef.workerChance) * 100}% chance,rolled {roll}))");
 | 
			
		||||
                    MakeWorker(pawn, queenDef);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void MakeQueen(Pawn pawnToBeQueen, Either<XenotypeDef,CustomXenotype> 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<XenotypeDef, CustomXenotype> 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}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Turns a given pawn into a worker, by looking up the relevant genes as per queen.
 | 
			
		||||
        /// 
 | 
			
		||||
        /// If the queen xenotype has no mapping, the  "rjw_genes_default_worker_xenotype" are used instead.
 | 
			
		||||
        /// The genes are added as endogenes, so the worker can still become a xenotype. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawnTobeWorker">The pawn for which the genes are added.</param>
 | 
			
		||||
        /// <param name="queenDef">The xenotype of the queen, used for lookup.</param>
 | 
			
		||||
        private static void MakeWorker(Pawn pawnTobeWorker, Either<XenotypeDef, CustomXenotype> queenDef)
 | 
			
		||||
        {
 | 
			
		||||
            if (pawnTobeWorker == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var mappings = HiveUtility.GetQueenWorkerMappings();
 | 
			
		||||
            String queenDefName = HiveUtility.GetXenotypeDefName(queenDef);
 | 
			
		||||
            if (queenDef == null || mappings.NullOrEmpty())
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var genes = mappings.TryGetValue(queenDefName, HiveUtility.LookupDefaultWorkerGenes());
 | 
			
		||||
            if (genes == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            foreach (var gene in genes)
 | 
			
		||||
                pawnTobeWorker.genes.AddGene(gene, false);
 | 
			
		||||
 | 
			
		||||
            pawnTobeWorker.genes.xenotypeName = "Worker";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Looks up if there is a Xenotype with Drone-Gene for the pawns parents. 
 | 
			
		||||
        /// This is to account that maybe father or mother are the drone (instead of hardcoding things for father).
 | 
			
		||||
        /// If both are drones, the mothers is returned.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn">The pawn for whichs parent the xenotypes is looked up.</param>
 | 
			
		||||
        /// <returns>The Drone-Xenotype of a parent or null. If both are drones, mothers are preferred.</returns>
 | 
			
		||||
        public static Either<XenotypeDef,CustomXenotype> TryFindParentDroneXenotype(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            if (pawn == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            List<DirectPawnRelation> parentRelations = pawn.relations.DirectRelations.FindAll(rel => rel.def.Equals(PawnRelationDefOf.Parent));
 | 
			
		||||
            foreach (DirectPawnRelation parent in parentRelations)
 | 
			
		||||
            {
 | 
			
		||||
                var xenotype = HiveUtility.TryGetDroneXenotype(parent.otherPawn);
 | 
			
		||||
                if (xenotype != null) return xenotype;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void MakeQueenBornLetter(Pawn bornQueen)
 | 
			
		||||
        {
 | 
			
		||||
            if (bornQueen == null) return;
 | 
			
		||||
 | 
			
		||||
            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); 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Looks up if there is a Xenotype with Queen-Gene for the pawns parents. 
 | 
			
		||||
        /// This is to account that maybe father or mother are the queen (instead of hardcoding things for father).
 | 
			
		||||
        /// If both are queens, the first is returned.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn">The pawn for whichs parent the xenotypes is looked up.</param>
 | 
			
		||||
        /// <returns>The Queen-Xenotype of a parent or null. If both are queens, mothers are preferred.</returns>
 | 
			
		||||
        public static Either<XenotypeDef,CustomXenotype> TryFindParentQueenXenotype(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            if (pawn == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            List<DirectPawnRelation> parentRelations = pawn.relations.DirectRelations.FindAll(rel => rel.def.Equals(PawnRelationDefOf.Parent));
 | 
			
		||||
            foreach (var parent in parentRelations)
 | 
			
		||||
            {
 | 
			
		||||
                var xenotype = HiveUtility.TryGetQueenXenotype(parent.otherPawn);
 | 
			
		||||
                if (xenotype != null) return xenotype;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,274 +0,0 @@
 | 
			
		|||
using RimWorld;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    internal class HiveUtility
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks for existance of the RJW-Gene `queen`, if the pawn is spawned and if the pawn has reached adulthood.
 | 
			
		||||
        /// Despite the naming, a Queen can also be male.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn">The pawn that could be an Adult Queen</param>
 | 
			
		||||
        /// <returns>Whether the pawn is an adult queen.</returns>
 | 
			
		||||
        public static bool IsAdultQueen(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            if (pawn == null || !pawn.Spawned)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_queen)) 
 | 
			
		||||
            { 
 | 
			
		||||
                return pawn.ageTracker.Adult;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static int QueensOnMap() => GetQueensOnMap().Count;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks for all pawns on the Players Home Map if they are an adult queen.
 | 
			
		||||
        /// Adultness is determined by Base-Game Logic, Queen is determined by the rjw_genes_queen GeneDefOf (Not Xenotype). 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>A list of queens on the players HomeMap</returns>
 | 
			
		||||
        public static List<Pawn> GetQueensOnMap()
 | 
			
		||||
        {
 | 
			
		||||
            Map map = Find.Maps.Where(mapCandidate => mapCandidate.IsPlayerHome).First();
 | 
			
		||||
 | 
			
		||||
            if (map != null)
 | 
			
		||||
            {
 | 
			
		||||
                List<Pawn> playersPawns = map.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer);
 | 
			
		||||
                return playersPawns.FindAll(pawn => pawn.Spawned && IsAdultQueen(pawn));
 | 
			
		||||
            }
 | 
			
		||||
            // Fallback: Something is wrong with Map 
 | 
			
		||||
            return new List<Pawn>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks if the pawn is on the players home map. 
 | 
			
		||||
        /// 
 | 
			
		||||
        /// Reason is that drones should only be punished for absence of queen if they are on the map and there is no queen.
 | 
			
		||||
        /// If they are on a mission, transport-pod etc. they should not get boni or mali. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn">The pawn for which to check map-presence.</param>
 | 
			
		||||
        /// <returns>True if the pawn is on the home-map, False otherwise.</returns>
 | 
			
		||||
        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
 | 
			
		||||
                && pawn.Spawned
 | 
			
		||||
                && pawn.Map == homeMap;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns the Xenotype of a pawn if the pawn has a xenotype with the queen gene.
 | 
			
		||||
        /// Null otherwise.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn"></param>
 | 
			
		||||
        /// <returns>A xenotype with a queen gene, or null.</returns>
 | 
			
		||||
        public static Either<XenotypeDef,CustomXenotype> TryGetQueenXenotype(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            if (pawn == null)
 | 
			
		||||
                return null; 
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_queen))
 | 
			
		||||
            {
 | 
			
		||||
                var potentialXenotype = pawn.genes.Xenotype;
 | 
			
		||||
                if (potentialXenotype != null && potentialXenotype.genes.Contains(GeneDefOf.rjw_genes_queen))
 | 
			
		||||
                {
 | 
			
		||||
                    return new Either<XenotypeDef,CustomXenotype>(potentialXenotype);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var potentialCustomXenotype = pawn.genes.CustomXenotype;
 | 
			
		||||
                if (potentialCustomXenotype != null && potentialCustomXenotype.genes.Contains(GeneDefOf.rjw_genes_queen))
 | 
			
		||||
                {
 | 
			
		||||
                    return new Either<XenotypeDef, CustomXenotype>(potentialCustomXenotype);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns the Xenotype of a pawn if the pawn has a xenotype with the drone gene.
 | 
			
		||||
        /// Null otherwise.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn"></param>
 | 
			
		||||
        /// <returns>A xenotype with a drone gene, or null.</returns>
 | 
			
		||||
        public static Either<XenotypeDef,CustomXenotype> TryGetDroneXenotype(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            if (pawn == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_drone))
 | 
			
		||||
            {
 | 
			
		||||
                var potentialXenotype = pawn.genes.Xenotype;
 | 
			
		||||
                if (potentialXenotype != null && potentialXenotype.genes.Contains(GeneDefOf.rjw_genes_drone))
 | 
			
		||||
                {
 | 
			
		||||
                    return new Either<XenotypeDef,CustomXenotype>(potentialXenotype);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var potentialCustomXenotype = pawn.genes.CustomXenotype;
 | 
			
		||||
                if (potentialCustomXenotype != null && potentialCustomXenotype.genes.Contains(GeneDefOf.rjw_genes_drone))
 | 
			
		||||
                {
 | 
			
		||||
                    return new Either<XenotypeDef, CustomXenotype>(potentialCustomXenotype);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Looks up the Queen-WorkerMappings and returns a cleaned / updated dictionary.
 | 
			
		||||
        /// 
 | 
			
		||||
        /// This method takes care of genes maybe not existing (from other mods) or misspellings etc. 
 | 
			
		||||
        /// Prints a bigger piece of information when debug printing is enabled. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>A mapping which Queen-Xenotypes should produce which worker genes.</returns>
 | 
			
		||||
        public static Dictionary<String,List<GeneDef>> GetQueenWorkerMappings()
 | 
			
		||||
        {
 | 
			
		||||
            IEnumerable<QueenWorkerMappingDef> mappingDefs = DefDatabase<QueenWorkerMappingDef>.AllDefs;
 | 
			
		||||
 | 
			
		||||
            Dictionary<string, List<GeneDef>> results = new Dictionary<string, List<GeneDef>>();
 | 
			
		||||
 | 
			
		||||
            // 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<XenotypeDef>.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<GeneDef> workerGenes = new List<GeneDef>();
 | 
			
		||||
                    foreach (string geneName in mappingDef.workerGenes)
 | 
			
		||||
                    {
 | 
			
		||||
                        GeneDef workerGene = DefDatabase<GeneDef>.GetNamed(geneName);
 | 
			
		||||
                        if (workerGene != null)
 | 
			
		||||
                            workerGenes.Add(workerGene);
 | 
			
		||||
                        else if(RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
                            ModLog.Warning($"Could not look up Gene {geneName} for {mappingDef.queenXenotype}.");
 | 
			
		||||
                    }
 | 
			
		||||
                    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 results;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Looks up the default genes for any queen offspring that has no other definition for it. 
 | 
			
		||||
        /// This is done by looking for the mapping with *exactly* defName rjw_genes_default_worker_genes. 
 | 
			
		||||
        /// 
 | 
			
		||||
        /// The idea is that players can edit the default types, but that this is a protected keyword. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>A list of genes for workers that do not have specific mappings defined.</returns>
 | 
			
		||||
        public static List<GeneDef> LookupDefaultWorkerGenes()
 | 
			
		||||
        {
 | 
			
		||||
            IEnumerable<QueenWorkerMappingDef> mappingDefs = DefDatabase<QueenWorkerMappingDef>.AllDefs;
 | 
			
		||||
 | 
			
		||||
            List<GeneDef> workerGenes = new List<GeneDef>();
 | 
			
		||||
 | 
			
		||||
            var defaultMapping = mappingDefs.First(m => m.defName == "rjw_genes_default_worker_genes");
 | 
			
		||||
            if (defaultMapping == null)
 | 
			
		||||
            {
 | 
			
		||||
                ModLog.Error("Did not find default worker genes for queen-offspring! Please make sure you did not rename the 'rjw_genes_default_worker_genes'.");
 | 
			
		||||
                return workerGenes;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (string geneName in defaultMapping.workerGenes)
 | 
			
		||||
            {
 | 
			
		||||
                GeneDef workerGene = DefDatabase<GeneDef>.GetNamed(geneName);
 | 
			
		||||
                if (workerGene != null)
 | 
			
		||||
                    workerGenes.Add(workerGene);
 | 
			
		||||
                else if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
                    ModLog.Warning($"Could not look up gene {geneName} for rjw_genes_default_worker_genes.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return workerGenes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IEnumerable<XenotypeDef> getQueenXenotypes()
 | 
			
		||||
        {
 | 
			
		||||
            return DefDatabase<XenotypeDef>.AllDefs.Where(type => type.genes.Contains(GeneDefOf.rjw_genes_queen));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IEnumerable<XenotypeDef> getDroneXenotypes()
 | 
			
		||||
        {
 | 
			
		||||
            return DefDatabase<XenotypeDef>.AllDefs.Where(type => type.genes.Contains(GeneDefOf.rjw_genes_drone));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static String GetXenotypeDefName(Either<XenotypeDef, CustomXenotype> def)
 | 
			
		||||
        {
 | 
			
		||||
            if (def == null)
 | 
			
		||||
                return null;
 | 
			
		||||
            else if (def.isLeft)
 | 
			
		||||
                return def.left.defName;
 | 
			
		||||
            else
 | 
			
		||||
                return def.right.name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static HiveOffspringChanceDef LookupDefaultHiveInheritanceChances()
 | 
			
		||||
        {
 | 
			
		||||
            IEnumerable<HiveOffspringChanceDef> offspringChanceDefs = DefDatabase<HiveOffspringChanceDef>.AllDefs;
 | 
			
		||||
 | 
			
		||||
            List<GeneDef> workerGenes = new List<GeneDef>();
 | 
			
		||||
 | 
			
		||||
            var defaultChance = offspringChanceDefs.First(m => m.defName == "rjw_genes_default_hive_offspring_chances");
 | 
			
		||||
 | 
			
		||||
            if (defaultChance == null)
 | 
			
		||||
                ModLog.Warning("Did not find `rjw_genes_default_hive_offspring_chances`. Someone likely changed the defname!");
 | 
			
		||||
 | 
			
		||||
            return defaultChance;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static HiveOffspringChanceDef LookupHiveInheritanceChances(Either<XenotypeDef, CustomXenotype> queenDef)
 | 
			
		||||
        {
 | 
			
		||||
            if (queenDef == null)
 | 
			
		||||
                return LookupDefaultHiveInheritanceChances();
 | 
			
		||||
 | 
			
		||||
            String queenDefName = queenDef.isLeft ? queenDef.left.defName : queenDef.right.name;
 | 
			
		||||
 | 
			
		||||
            IEnumerable<HiveOffspringChanceDef> offspringChanceDefs = DefDatabase<HiveOffspringChanceDef>.AllDefs;
 | 
			
		||||
 | 
			
		||||
            return offspringChanceDefs.FirstOrFallback(t => t.queenXenotype == queenDefName, LookupDefaultHiveInheritanceChances());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,53 +0,0 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Patches the method `ApplyBirthOutcome` from `PregnancyUtility`. 
 | 
			
		||||
    /// 
 | 
			
		||||
    /// The 'ApplyBirthOutcome' returns the finished baby, for which we alter the pawn according to our xenotypes.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    
 | 
			
		||||
    [HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome))]
 | 
			
		||||
    public class Patch_BirthOutcome_SetHiveGenes
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [HarmonyPostfix]
 | 
			
		||||
        static void HandleHiveBasedInheritance(ref Thing __result)
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
            // Check: Was the born thing a pawn? 
 | 
			
		||||
            if (__result == null || !(__result is Pawn))
 | 
			
		||||
            {
 | 
			
		||||
                if (RJW_Genes_Settings.rjw_genes_detailed_debug)  ModLog.Message("There was a birth of something non-human - not entering logic for queen-drone-xenotype inheritance.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Pawn pawn = (Pawn)__result;
 | 
			
		||||
 | 
			
		||||
            // Important: Not all pawns have mother/father. Some Pawns are born in Growth-Vats or born from mod. 
 | 
			
		||||
            bool hasQueenParent = HiveBirthLogic.TryFindParentQueenXenotype(pawn) != null;
 | 
			
		||||
            bool hasDroneParent = HiveBirthLogic.TryFindParentDroneXenotype(pawn) != null;
 | 
			
		||||
 | 
			
		||||
            if (hasQueenParent)
 | 
			
		||||
            {
 | 
			
		||||
                if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"PostFix PregnancyUtility::ApplyBirthOutcome - Checking Hive Inheritance because {pawn} has a queen parent.");
 | 
			
		||||
 | 
			
		||||
                HiveBirthLogic.ManageHiveBirth(pawn, hasDroneParent);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Ignoring Postfix PregnancyUtility::ApplyBirthOutcome - No Quene Parent - Doing Nothing");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,99 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using Verse;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This Class patches the AfterSexUtility to also fertilize eggs if Pawn A has "InsectBreeder" and Pawn B has Insect Eggs.
 | 
			
		||||
    /// Patched Class is https://gitgud.io/Ed86/rjw/-/blob/master/1.4/Source/Common/Helpers/SexUtility.cs
 | 
			
		||||
    /// 
 | 
			
		||||
    /// Normal Egg-Pregnancy logic is in https://gitgud.io/Ed86/rjw/-/blob/master/1.4/Source/Modules/Pregnancy/Pregnancy_Helper.cs
 | 
			
		||||
    /// Gene: rjw_genes_insectbreeder 
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [HarmonyPatch(typeof(SexUtility), "Aftersex")]
 | 
			
		||||
    static class Patch_InsectBreeder_EggFertilization
 | 
			
		||||
    {
 | 
			
		||||
        public static void Postfix(SexProps props)
 | 
			
		||||
        {
 | 
			
		||||
            // Only Fertilize on vaginal / anal sex
 | 
			
		||||
            if (!(props.sexType == xxx.rjwSextype.Vaginal || props.sexType == xxx.rjwSextype.Anal))
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (canDoEggFertilization(props.pawn, props.partner))
 | 
			
		||||
            {
 | 
			
		||||
                // Pawn has gene and Partner has eggs
 | 
			
		||||
                if (props.pawn.genes.GenesListForReading.Any(x => x.def == GeneDefOf.rjw_genes_insectbreeder) && !getEggsforPawn(props.partner).NullOrEmpty())
 | 
			
		||||
                {
 | 
			
		||||
                    Pawn eggHolder = props.partner;
 | 
			
		||||
                    Pawn impregnator = props.pawn;
 | 
			
		||||
 | 
			
		||||
                    foreach (Hediff_InsectEgg egg in getEggsforPawn(eggHolder))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!egg.fertilized)
 | 
			
		||||
                            egg.Fertilize(impregnator);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Partner has gene and Pawn has eggs
 | 
			
		||||
                if (props.partner.genes.GenesListForReading.Any(x => x.def == GeneDefOf.rjw_genes_insectbreeder) && !getEggsforPawn(props.pawn).NullOrEmpty())
 | 
			
		||||
                {
 | 
			
		||||
                    Pawn eggHolder = props.pawn;
 | 
			
		||||
                    Pawn impregnator = props.partner;
 | 
			
		||||
 | 
			
		||||
                    foreach (Hediff_InsectEgg egg in getEggsforPawn(eggHolder))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!egg.fertilized)
 | 
			
		||||
                            egg.Fertilize(impregnator);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private static bool canDoEggFertilization(Pawn a, Pawn b)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            // No Partner / Other Errors
 | 
			
		||||
            if (a != null || b != null)
 | 
			
		||||
                return false;
 | 
			
		||||
            // None of the pawns has the relevant gene
 | 
			
		||||
            if (!a.genes.GenesListForReading.Any(x => x.def == GeneDefOf.rjw_genes_insectbreeder) && !b.genes.GenesListForReading.Any(x => x.def == GeneDefOf.rjw_genes_insectbreeder))
 | 
			
		||||
                return false;
 | 
			
		||||
            // None of the pawns has eggs
 | 
			
		||||
            if (getEggsforPawn(a).NullOrEmpty() && getEggsforPawn(b).NullOrEmpty())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            // A has gene and B has eggs
 | 
			
		||||
            if (a.genes.GenesListForReading.Any(x => x.def == GeneDefOf.rjw_genes_insectbreeder) && !getEggsforPawn(b).NullOrEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            // B has gene and A has eggs
 | 
			
		||||
            if (b.genes.GenesListForReading.Any(x => x.def == GeneDefOf.rjw_genes_insectbreeder) && !getEggsforPawn(a).NullOrEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            // Any other case: Do nothing
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static List<Hediff_InsectEgg> getEggsforPawn(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            List<Hediff_InsectEgg> eggs = new List<Hediff_InsectEgg>();
 | 
			
		||||
            pawn.health.hediffSet.GetHediffs(ref eggs);
 | 
			
		||||
            foreach (var egg in eggs)
 | 
			
		||||
                egg.Fertilize(pawn);
 | 
			
		||||
 | 
			
		||||
            return eggs;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,112 +0,0 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Patches the method `ProcessHumanLikeInsectEgg` from `Hediff_InsectEgg`. 
 | 
			
		||||
    /// 
 | 
			
		||||
    /// The 'ProcessHumanLikeInsectEgg' returns the finished baby, for which we alter the pawn according to our xenotypes.
 | 
			
		||||
    /// Note: This covers Insect-Egg Pregnancies only, and there is a (very similar) class `Patch_BirthOutCome_SetHiveGenes.cs` that handles normal pregnancies
 | 
			
		||||
    /// </summary>
 | 
			
		||||
 | 
			
		||||
    [HarmonyPatch(typeof(Hediff_InsectEgg), "ProcessHumanLikeInsectEgg")]
 | 
			
		||||
    public class Patch_InsectEgg_BirthBaby_SetHiveGenes
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [HarmonyPostfix]
 | 
			
		||||
        static void HandleHiveBasedInheritance(ref Thing __result, ref Hediff_InsectEgg __instance)
 | 
			
		||||
        {
 | 
			
		||||
            // Check: Was the born thing a pawn? 
 | 
			
		||||
            if (__result == null || !(__result is Pawn))
 | 
			
		||||
            {
 | 
			
		||||
                if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message("There was a birth of something non-human - not entering logic for queen-drone-xenotype inheritance.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Pawn pawn = (Pawn)__result;
 | 
			
		||||
 | 
			
		||||
            Either<XenotypeDef,CustomXenotype> queenDef = HiveBirthLogic.TryFindParentQueenXenotype(pawn) ?? TryFindParentQueenXenotypeFromEgg(__instance);
 | 
			
		||||
            Either<XenotypeDef, CustomXenotype> droneDef = HiveBirthLogic.TryFindParentDroneXenotype(pawn) ?? TryFindParentDroneXenotypeFromEgg(__instance);
 | 
			
		||||
 | 
			
		||||
            bool hasQueenParent = queenDef != null;
 | 
			
		||||
            bool hasDroneParent = droneDef != null;
 | 
			
		||||
 | 
			
		||||
            if (hasQueenParent)
 | 
			
		||||
            {
 | 
			
		||||
                if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"PostFix Hediff_InsectEgg::ProcessHumanLikeInsectEgg - Checking Hive Inheritance because {pawn} has a queen parent.");
 | 
			
		||||
                HiveBirthLogic.ManageHiveBirth(pawn, hasDroneParent, fallbackQueenDef: queenDef, fallbackDroneDef: droneDef);
 | 
			
		||||
            } 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;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Tries to retrieve a queen-xenotype-def from a given egg. 
 | 
			
		||||
        /// Checking priority goes: Implanter > Fertilizer > Null Otherwise. 
 | 
			
		||||
        /// 
 | 
			
		||||
        /// This is meant to be a fallback to the parent-relations which were not present in RJW 5.3.1. 
 | 
			
		||||
        /// Some comments and thoughts are captured in Issue #37. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="egg">An Egg for which queens are looked up for</param>
 | 
			
		||||
        /// <returns>The relevant xenotypedef of a queen, or null.</returns>
 | 
			
		||||
        public static Either<XenotypeDef, CustomXenotype> TryFindParentQueenXenotypeFromEgg(Hediff_InsectEgg egg)
 | 
			
		||||
        {
 | 
			
		||||
            Either<XenotypeDef, CustomXenotype> queenDef = null;
 | 
			
		||||
            if (egg == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            if (egg.implanter != null)
 | 
			
		||||
                queenDef = HiveUtility.TryGetQueenXenotype(egg.implanter);
 | 
			
		||||
 | 
			
		||||
            if (queenDef == null && egg.father != null)
 | 
			
		||||
                queenDef = HiveUtility.TryGetQueenXenotype(egg.implanter);
 | 
			
		||||
 | 
			
		||||
            return queenDef;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Tries to retrieve a drone-xenotype-def from a given egg. 
 | 
			
		||||
        /// Checking priority goes: Implanter > Fertilizer > Null Otherwise. 
 | 
			
		||||
        /// 
 | 
			
		||||
        /// This is meant to be a fallback to the parent-relations which were not present in RJW 5.3.1. 
 | 
			
		||||
        /// Some comments and thoughts are captured in Issue #37. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="egg">An Egg for which drones are looked up for</param>
 | 
			
		||||
        /// <returns>The relevant xenotypedef of a drone, or null.</returns>
 | 
			
		||||
        public static Either<XenotypeDef, CustomXenotype> TryFindParentDroneXenotypeFromEgg(Hediff_InsectEgg egg)
 | 
			
		||||
        {
 | 
			
		||||
            Either<XenotypeDef, CustomXenotype> droneDef = null;
 | 
			
		||||
            if (egg == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            if (egg.implanter != null)
 | 
			
		||||
                droneDef = HiveUtility.TryGetQueenXenotype(egg.implanter);
 | 
			
		||||
 | 
			
		||||
            if (droneDef == null && egg.father != null)
 | 
			
		||||
                droneDef = HiveUtility.TryGetQueenXenotype(egg.implanter);
 | 
			
		||||
 | 
			
		||||
            return droneDef;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,56 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection.Emit;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This Class patches the RJW-DoEgg to allow up to MaxEggSizeMul times the original amount of eggs.
 | 
			
		||||
    /// This harmony patch was kindly provided by 'shabalox' https://github.com/Shabalox/RJW_Genes_Addons/
 | 
			
		||||
    /// 
 | 
			
		||||
    /// For Gene: rjw_genes_insectincubator 
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [HarmonyPatch(typeof(PregnancyHelper), "DoEgg")]
 | 
			
		||||
    static class Patch_InsectIncubator_PregnancyHelper
 | 
			
		||||
    {
 | 
			
		||||
        [HarmonyTranspiler]
 | 
			
		||||
        public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator il)
 | 
			
		||||
        {
 | 
			
		||||
            //MethodInfo isinsectincubator = AccessTools.Method(typeof(GeneUtility), "IsInsectIncubator");
 | 
			
		||||
            MethodInfo maxeggsizemul = AccessTools.Method(typeof(GeneUtility), "MaxEggSizeMul");
 | 
			
		||||
            FieldInfo partner = AccessTools.Field(typeof(SexProps), "partner");
 | 
			
		||||
 | 
			
		||||
            Label skiplabel = il.DefineLabel();
 | 
			
		||||
            bool finished = false;
 | 
			
		||||
            foreach (CodeInstruction codeInstruction in instructions)
 | 
			
		||||
            {
 | 
			
		||||
                if (!finished)
 | 
			
		||||
                {
 | 
			
		||||
                    if (codeInstruction.opcode == OpCodes.Ldc_R4 && codeInstruction.operand.ToString() == "0")
 | 
			
		||||
                    {
 | 
			
		||||
                        yield return new CodeInstruction(OpCodes.Ldarg_0, null);
 | 
			
		||||
                        yield return new CodeInstruction(OpCodes.Ldfld, partner);
 | 
			
		||||
                        //yield return new CodeInstruction(OpCodes.Call, isinsectincubator);
 | 
			
		||||
                        yield return new CodeInstruction(OpCodes.Callvirt, maxeggsizemul);
 | 
			
		||||
                        //yield return new CodeInstruction(OpCodes.Brfalse_S, skiplabel);
 | 
			
		||||
                        yield return new CodeInstruction(OpCodes.Ldloc_0, null);
 | 
			
		||||
                        //yield return new CodeInstruction(OpCodes.Ldc_R4, 2f);
 | 
			
		||||
                        yield return new CodeInstruction(OpCodes.Mul, null);
 | 
			
		||||
                        yield return new CodeInstruction(OpCodes.Stloc_0, null);
 | 
			
		||||
                        //codeInstruction.labels.Add(skiplabel);
 | 
			
		||||
                        finished = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                yield return codeInstruction;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,43 +0,0 @@
 | 
			
		|||
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_QueenPresent_Social : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
        protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn other)
 | 
			
		||||
        {
 | 
			
		||||
            // p is the pawn `thinking`, and other is the pawn being thought about.
 | 
			
		||||
            // here: p = loyal pawn, other = potential queen  
 | 
			
		||||
 | 
			
		||||
            if (!p.RaceProps.Humanlike)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
 | 
			
		||||
            if (!other.RaceProps.Humanlike)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
 | 
			
		||||
            if (!RelationsUtility.PawnsKnowEachOther(p, other))
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
 | 
			
		||||
            // Only check if they are spawned 
 | 
			
		||||
            if (!p.Spawned || !other.Spawned)
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(p))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 1)
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState) HiveUtility.IsAdultQueen(other);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (ThoughtState)false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,39 +0,0 @@
 | 
			
		|||
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_RivalQueen_Social : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
        protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn other)
 | 
			
		||||
        {
 | 
			
		||||
            if (!p.RaceProps.Humanlike)
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            if (!other.RaceProps.Humanlike)
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (!RelationsUtility.PawnsKnowEachOther(p, other))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(p))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            // Only check if they are spawned 
 | 
			
		||||
            if (!p.Spawned || !other.Spawned)
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(HiveUtility.IsAdultQueen(p) && HiveUtility.IsAdultQueen(other))
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState)true;
 | 
			
		||||
            }
 | 
			
		||||
            return (ThoughtState)false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,39 +0,0 @@
 | 
			
		|||
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_WorkerDespised_Social : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
        protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn other)
 | 
			
		||||
        {
 | 
			
		||||
            // p is the pawn `thinking`, and other is the pawn being thought about.
 | 
			
		||||
            // here: p = queen, other = potential worker 
 | 
			
		||||
 | 
			
		||||
            if (!p.RaceProps.Humanlike)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
 | 
			
		||||
            if (!other.RaceProps.Humanlike)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
 | 
			
		||||
            if (!RelationsUtility.PawnsKnowEachOther(p, other))
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
 | 
			
		||||
            // Only check if they are spawned 
 | 
			
		||||
            if (!p.Spawned || !other.Spawned)
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen) && GeneUtility.HasGeneNullCheck(other, GeneDefOf.rjw_genes_worker))
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState)true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (ThoughtState)false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
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_MultipleQueens_Mood : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        protected override ThoughtState CurrentStateInternal(Pawn p)
 | 
			
		||||
        {
 | 
			
		||||
            // Error Handling and Check for Pawn being on Map
 | 
			
		||||
            if (p == null || !p.Spawned)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
            // Queens cannot have loyalty thoughts
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(p))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() >= 2)
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState)true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (ThoughtState) false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
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_QueenAbsent_Mood : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        protected override ThoughtState CurrentStateInternal(Pawn p)
 | 
			
		||||
        {
 | 
			
		||||
            // Error Handling and Check for Pawn being on Map
 | 
			
		||||
            if (p == null || !p.Spawned)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
            // Queens cannot have loyalty thoughts
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(p))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState)true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (ThoughtState) false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
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_QueenPresent_Mood : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        protected override ThoughtState CurrentStateInternal(Pawn p)
 | 
			
		||||
        {
 | 
			
		||||
            // Error Handling and Check for Pawn being on Map
 | 
			
		||||
            if (p == null || !p.Spawned)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
            // Queens cannot have loyalty thoughts
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(p))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 1)
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState)true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (ThoughtState) false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
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_RivalQueen_Mood : ThoughtWorker
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        protected override ThoughtState CurrentStateInternal(Pawn p)
 | 
			
		||||
        {
 | 
			
		||||
            if (p == null || !p.Spawned)
 | 
			
		||||
                return (ThoughtState) false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(p))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
            if (HiveUtility.IsAdultQueen(p) && HiveUtility.QueensOnMap() >= 2)
 | 
			
		||||
            {
 | 
			
		||||
                return (ThoughtState) true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (ThoughtState) false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,71 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse.Sound;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using rjw.Modules.Interactions.Helpers;
 | 
			
		||||
using rjw.Modules.Interactions.Enums;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class AbilityUtility
 | 
			
		||||
    {
 | 
			
		||||
        public static void PussyHeal(SexProps props)
 | 
			
		||||
        {
 | 
			
		||||
            if (InteractionHelper.GetWithExtension(props.dictionaryKey).DominantHasFamily(GenitalFamily.Vagina) || InteractionHelper.GetWithExtension(props.dictionaryKey).SubmissiveHasFamily(GenitalFamily.Vagina))
 | 
			
		||||
            {
 | 
			
		||||
                Pawn pawn = props.pawn;
 | 
			
		||||
                Pawn partner = props.partner;
 | 
			
		||||
                FloatRange tendQualityRange;
 | 
			
		||||
                tendQualityRange.min = 0.4f;
 | 
			
		||||
                tendQualityRange.max = 0.8f;
 | 
			
		||||
                if (GeneUtility.IsPussyHealer(pawn))
 | 
			
		||||
                {
 | 
			
		||||
                    Heal(partner, tendQualityRange);
 | 
			
		||||
                }
 | 
			
		||||
                if (GeneUtility.IsPussyHealer(partner))
 | 
			
		||||
                {
 | 
			
		||||
                    Heal(pawn, tendQualityRange);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool Heal(Pawn pawn, FloatRange tendQualityRange)
 | 
			
		||||
        {
 | 
			
		||||
            bool any_wound_tended = false;
 | 
			
		||||
            List<Hediff> hediffs = pawn.health.hediffSet.hediffs;
 | 
			
		||||
            for (int i = hediffs.Count - 1; i >= 0; i--)
 | 
			
		||||
            {
 | 
			
		||||
                if ((hediffs[i] is Hediff_Injury || hediffs[i] is Hediff_MissingPart) && hediffs[i].TendableNow(false))
 | 
			
		||||
                {
 | 
			
		||||
                    hediffs[i].Tended(tendQualityRange.RandomInRange, tendQualityRange.TrueMax, 1);
 | 
			
		||||
                    any_wound_tended = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return any_wound_tended;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static float LifeForceCost(Ability ability)
 | 
			
		||||
        {
 | 
			
		||||
            if (ability.comps != null)
 | 
			
		||||
            {
 | 
			
		||||
                using (List<AbilityComp>.Enumerator enumerator = ability.comps.GetEnumerator())
 | 
			
		||||
                {
 | 
			
		||||
                    while (enumerator.MoveNext())
 | 
			
		||||
                    {
 | 
			
		||||
                        CompAbilityEffect_LifeForceCost compAbilityEffect_HemogenCost;
 | 
			
		||||
                        if ((compAbilityEffect_HemogenCost = (enumerator.Current as CompAbilityEffect_LifeForceCost)) != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            return compAbilityEffect_HemogenCost.Props.fertilinCost;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return 0f;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	//Summary//
 | 
			
		||||
	//Returns invalid if a pawn is not naked
 | 
			
		||||
	//Summary//
 | 
			
		||||
	public class CompAbilityEffect_CasterIsNaked : CompAbilityEffect_WithDest
 | 
			
		||||
	{
 | 
			
		||||
		private new CompProperties_CasterIsNaked Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (CompProperties_CasterIsNaked)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool GizmoDisabled(out string reason)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn pawn = this.CasterPawn;
 | 
			
		||||
			if (pawn != null)
 | 
			
		||||
			{
 | 
			
		||||
				//Copied from ThoughtWorker_NudistNude.CurrentStateInternal
 | 
			
		||||
				List<Apparel> wornApparel = pawn.apparel.WornApparel;
 | 
			
		||||
				for (int i = 0; i < wornApparel.Count; i++)
 | 
			
		||||
				{
 | 
			
		||||
					Apparel apparel = wornApparel[i];
 | 
			
		||||
					if (apparel.def.apparel.countsAsClothingForNudity)
 | 
			
		||||
					{
 | 
			
		||||
						for (int j = 0; j < apparel.def.apparel.bodyPartGroups.Count; j++)
 | 
			
		||||
						{
 | 
			
		||||
							if (apparel.def.apparel.bodyPartGroups[j] == BodyPartGroupDefOf.Torso)
 | 
			
		||||
							{
 | 
			
		||||
								reason = pawn.Name + " is not naked";
 | 
			
		||||
								return true;
 | 
			
		||||
							}
 | 
			
		||||
							if (apparel.def.apparel.bodyPartGroups[j] == BodyPartGroupDefOf.Legs)
 | 
			
		||||
							{
 | 
			
		||||
								reason = pawn.Name + " is not naked";
 | 
			
		||||
								return true;
 | 
			
		||||
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			reason = null;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,121 +0,0 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// The CockEater Ability bites off the first found non-artifical cock of an target pawn. 
 | 
			
		||||
	/// It will restore {MINIMUM_LIFEFORCE_GAIN} multiplied by up to 2-times the Cock-Size. 
 | 
			
		||||
	/// Consuming a "towering" cock will give 2*{MINIMUM_LIFEFORCE_GAIN}, resulting in default 0.5f LifeForce. 
 | 
			
		||||
	/// This number is reduced for consuming animals by Settings.
 | 
			
		||||
	/// 
 | 
			
		||||
	/// Balancing note: With the Cock-Eaters a drain of 0.08 is normal per day. This means 1 average cock should hold for 3-4 days of fertilin-fuel and half a day for an animal.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public class CompAbilityEffect_CockEater : CompAbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		private new CompProperties_AbilityCockEater Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (CompProperties_AbilityCockEater)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public const float MINIMUM_LIFEFORCE_GAIN = 0.25f;
 | 
			
		||||
 | 
			
		||||
		public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
 | 
			
		||||
		{
 | 
			
		||||
			base.Apply(target, dest);
 | 
			
		||||
			Pawn CockBiter = this.parent.pawn;
 | 
			
		||||
			Pawn CockBittenPawn = target.Pawn;
 | 
			
		||||
			if (CockBittenPawn == null)
 | 
			
		||||
			{
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			var partBPR = Genital_Helper.get_genitalsBPR(CockBittenPawn);
 | 
			
		||||
			var parts = Genital_Helper.get_PartsHediffList(CockBittenPawn, partBPR);
 | 
			
		||||
			if (!parts.NullOrEmpty())
 | 
			
		||||
			{
 | 
			
		||||
				foreach (Hediff part in parts)
 | 
			
		||||
				{
 | 
			
		||||
					if (GenitaliaChanger.IsArtificial(part))
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					if (Genital_Helper.is_penis(part))
 | 
			
		||||
					{
 | 
			
		||||
						float gained_lifeforce = MINIMUM_LIFEFORCE_GAIN * (1 + part.Severity);
 | 
			
		||||
						if (CockBittenPawn.IsAnimal())
 | 
			
		||||
                        {
 | 
			
		||||
							gained_lifeforce *= RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor;
 | 
			
		||||
                        }
 | 
			
		||||
						// Increase LifeForce for Biter
 | 
			
		||||
						GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(CockBiter), gained_lifeforce);
 | 
			
		||||
						// Handle Damage for Bitten 
 | 
			
		||||
						CockBittenPawn.TakeDamage(new DamageInfo(DamageDefOf.Bite, 99999f, 999f, hitPart: Genital_Helper.get_genitalsBPR(CockBittenPawn)));
 | 
			
		||||
						//CockBittenPawn.health.RemoveHediff(part);
 | 
			
		||||
						CockBittenPawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.rjw_genes_cock_eaten, CockBittenPawn, null);
 | 
			
		||||
 | 
			
		||||
						//Only one penis at the time
 | 
			
		||||
						break; 
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// For validity, there are a few checks:
 | 
			
		||||
		/// 1. Target has Penis 
 | 
			
		||||
		/// 2. Target is either Colonist / Prisoner 
 | 
			
		||||
		/// 3. If the Target is an enemy, it must be downed. 
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn CockBiteTarget = target.Pawn;
 | 
			
		||||
			if (CockBiteTarget != null)
 | 
			
		||||
			{
 | 
			
		||||
				bool CockBiteTargetIsColonistOrPrisoner = CockBiteTarget.Faction == this.parent.pawn.Faction || CockBiteTarget.IsPrisonerOfColony;
 | 
			
		||||
				bool CockBiteTargetIsHostile = CockBiteTarget.HostileTo(this.parent.pawn);
 | 
			
		||||
				bool CockBiteTargetIsDowned = CockBiteTarget.Downed;
 | 
			
		||||
 | 
			
		||||
				if (!CockBiteTargetIsColonistOrPrisoner && !(CockBiteTargetIsHostile && CockBiteTargetIsDowned))
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						if(CockBiteTargetIsHostile && !CockBiteTargetIsDowned)
 | 
			
		||||
                        {
 | 
			
		||||
							Messages.Message(CockBiteTarget.Name + " is hostile, but not downed.", CockBiteTarget, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
						}
 | 
			
		||||
						else if (!CockBiteTargetIsColonistOrPrisoner)
 | 
			
		||||
						{
 | 
			
		||||
							Messages.Message(CockBiteTarget.Name + " is not a part of the colony or hostile.", CockBiteTarget, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				if (!Genital_Helper.has_penis_fertile(CockBiteTarget))
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message(CockBiteTarget.Name + " has no penis", CockBiteTarget, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return base.Valid(target, throwMessages);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool GizmoDisabled(out string reason)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn_GeneTracker genes = this.parent.pawn.genes;
 | 
			
		||||
			Gene_LifeForce gene_LifeForce = (genes != null) ? genes.GetFirstGeneOfType<Gene_LifeForce>() : null;
 | 
			
		||||
			if (gene_LifeForce == null)
 | 
			
		||||
			{
 | 
			
		||||
				reason = "AbilityDisabledNoFertilinGene".Translate(this.parent.pawn);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			reason = null;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,107 +0,0 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompAbilityEffect_LifeForceCost : CompAbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		public new CompProperties_AbilityLifeForceCost Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (CompProperties_AbilityLifeForceCost)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool HasEnoughFertilin
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				Pawn_GeneTracker genes = this.parent.pawn.genes;
 | 
			
		||||
				Gene_LifeForce gene_lifeforce = (genes != null) ? genes.GetFirstGeneOfType < Gene_LifeForce>() : null;
 | 
			
		||||
				return gene_lifeforce != null && gene_lifeforce.Value >= this.Props.fertilinCost;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
 | 
			
		||||
		{
 | 
			
		||||
			base.Apply(target, dest);
 | 
			
		||||
			GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(this.parent.pawn), -this.Props.fertilinCost);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		public override bool GizmoDisabled(out string reason)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn_GeneTracker genes = this.parent.pawn.genes;
 | 
			
		||||
			Gene_LifeForce gene_LifeForce = (genes != null) ? genes.GetFirstGeneOfType<Gene_LifeForce>() : null;
 | 
			
		||||
			if (gene_LifeForce == null)
 | 
			
		||||
			{
 | 
			
		||||
				reason = "AbilityDisabledNoFertilinGene".Translate(this.parent.pawn);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			if (gene_LifeForce.Value < this.Props.fertilinCost)
 | 
			
		||||
			{
 | 
			
		||||
				reason = "AbilityDisabledNoFertilin".Translate(this.parent.pawn);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			float num = this.TotalLifeForceCostOfQueuedAbilities();
 | 
			
		||||
			float num2 = this.Props.fertilinCost + num;
 | 
			
		||||
			if (this.Props.fertilinCost > 1E-45f && num2 > gene_LifeForce.Value)
 | 
			
		||||
			{
 | 
			
		||||
				reason = "AbilityDisabledNoFertilin".Translate(this.parent.pawn);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			reason = null;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool AICanTargetNow(LocalTargetInfo target)
 | 
			
		||||
		{
 | 
			
		||||
			return this.HasEnoughFertilin;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private float TotalLifeForceCostOfQueuedAbilities()
 | 
			
		||||
		{
 | 
			
		||||
			Pawn_JobTracker jobs = this.parent.pawn.jobs;
 | 
			
		||||
			object obj;
 | 
			
		||||
			if (jobs == null)
 | 
			
		||||
			{
 | 
			
		||||
				obj = null;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				Job curJob = jobs.curJob;
 | 
			
		||||
				obj = ((curJob != null) ? curJob.verbToUse : null);
 | 
			
		||||
			}
 | 
			
		||||
			Verb_CastAbility verb_CastAbility = obj as Verb_CastAbility;
 | 
			
		||||
			float num;
 | 
			
		||||
			if (verb_CastAbility == null)
 | 
			
		||||
			{
 | 
			
		||||
				num = 0f;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				Ability ability = verb_CastAbility.ability;
 | 
			
		||||
				num = ((ability != null) ? AbilityUtility.LifeForceCost(ability) : 0f);
 | 
			
		||||
			}
 | 
			
		||||
			float num2 = num;
 | 
			
		||||
			if (this.parent.pawn.jobs != null)
 | 
			
		||||
			{
 | 
			
		||||
				for (int i = 0; i < this.parent.pawn.jobs.jobQueue.Count; i++)
 | 
			
		||||
				{
 | 
			
		||||
					Verb_CastAbility verb_CastAbility2;
 | 
			
		||||
					if ((verb_CastAbility2 = (this.parent.pawn.jobs.jobQueue[i].job.verbToUse as Verb_CastAbility)) != null)
 | 
			
		||||
					{
 | 
			
		||||
						float num3 = num2;
 | 
			
		||||
						Ability ability2 = verb_CastAbility2.ability;
 | 
			
		||||
						num2 = num3 + ((ability2 != null) ? AbilityUtility.LifeForceCost(ability2) : 0f);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return num2;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,95 +0,0 @@
 | 
			
		|||
using System.Collections.Generic;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompAbilityEffect_PussyHeal : CompAbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		private new CompProperties_AbilityPussyHeal Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (CompProperties_AbilityPussyHeal)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
 | 
			
		||||
		{
 | 
			
		||||
			base.Apply(target, dest);
 | 
			
		||||
			Pawn pawn = target.Pawn;
 | 
			
		||||
			if (pawn == null)
 | 
			
		||||
			{
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			bool any_wound_tended = AbilityUtility.Heal(pawn, this.Props.tendQualityRange);
 | 
			
		||||
			if (any_wound_tended)
 | 
			
		||||
			{
 | 
			
		||||
				MoteMaker.ThrowText(pawn.DrawPos, pawn.Map, "Sex tended wounds", 3.65f);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//Not yet implemented, but the heal should also trigger after normal sex
 | 
			
		||||
		public void AfterSex(Pawn pawn, Pawn target)
 | 
			
		||||
		{
 | 
			
		||||
			List<Hediff> hediffs = target.health.hediffSet.hediffs;
 | 
			
		||||
			for (int i = 0; i < hediffs.Count; i++)
 | 
			
		||||
			{
 | 
			
		||||
				if ((hediffs[i] is Hediff_Injury || hediffs[i] is Hediff_MissingPart) && hediffs[i].TendableNow(false))
 | 
			
		||||
				{
 | 
			
		||||
					//target.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.Pussy_Healed, pawn, null);
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			//InteractionHelper.GetWithExtension(dictionaryKey).DominantHasTag("CanBePenetrated")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn pawn = target.Pawn;
 | 
			
		||||
			if (pawn != null)
 | 
			
		||||
			{
 | 
			
		||||
				//to be replaced with severel checks to make it clear why target is unable to have sex
 | 
			
		||||
				if (!CasualSex_Helper.CanHaveSex(pawn))
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message(pawn.Name + " is unable to have sex", pawn, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				else if (pawn.IsAnimal() && !RJWSettings.bestiality_enabled)
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message("bestiality is disabled", pawn, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				//TODO: Only make pawns targetable that have tendable wounds 
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			return base.Valid(target, throwMessages);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool GizmoDisabled(out string reason)
 | 
			
		||||
		{
 | 
			
		||||
			reason = null;
 | 
			
		||||
			if (!Genital_Helper.has_vagina(this.parent.pawn))
 | 
			
		||||
			{
 | 
			
		||||
				reason = this.parent.pawn.Name + " has no vagina to use.";
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			else if (!RJWSettings.rape_enabled)
 | 
			
		||||
			{
 | 
			
		||||
				reason = "Rape is disabled";
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,90 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompAbilityEffect_Seduce : CompAbilityEffect_WithDest
 | 
			
		||||
	{
 | 
			
		||||
		private new CompProperties_Seduce Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (CompProperties_Seduce)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
 | 
			
		||||
		{
 | 
			
		||||
			base.Apply(target, dest);
 | 
			
		||||
			Pawn pawn = target.Thing as Pawn;
 | 
			
		||||
			Pawn pawn2 = this.parent.pawn;
 | 
			
		||||
			if (pawn != null && pawn2 != null && !pawn.Downed)
 | 
			
		||||
			{
 | 
			
		||||
				Job job = JobMaker.MakeJob(JobDefOf.rjw_genes_lifeforce_seduced, pawn2);
 | 
			
		||||
				job.mote = MoteMaker.MakeThoughtBubble(pawn, this.parent.def.iconPath, true);
 | 
			
		||||
				pawn.jobs.StopAll(false, true);
 | 
			
		||||
				pawn.jobs.StartJob(job, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
			Pawn pawn = target.Pawn;
 | 
			
		||||
			if (pawn != null)
 | 
			
		||||
			{
 | 
			
		||||
				if (!xxx.can_be_fucked(pawn))
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message(pawn.Name + " is unable to have sex", pawn, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				else if (pawn.IsAnimal() && !RJWSettings.bestiality_enabled)
 | 
			
		||||
				{
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message("bestiality is disabled", pawn, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				} 
 | 
			
		||||
				else if (GeneUtility.HasSeduce(pawn))
 | 
			
		||||
                {
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message(pawn.Name + " cannot be seduced, as they also have the Seduce-Ability", pawn, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				else if (pawn.Downed)
 | 
			
		||||
                {
 | 
			
		||||
					if (throwMessages)
 | 
			
		||||
					{
 | 
			
		||||
						Messages.Message(pawn.Name + " is unable to move", pawn, MessageTypeDefOf.RejectInput, false);
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			return base.Valid(target, throwMessages);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool GizmoDisabled(out string reason)
 | 
			
		||||
		{
 | 
			
		||||
			reason = null;
 | 
			
		||||
			if (!RJWSettings.rape_enabled)
 | 
			
		||||
			{
 | 
			
		||||
				reason = "Rape is disabled";
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		} 
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompProperties_AbilityCockEater : CompProperties_AbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		public CompProperties_AbilityCockEater()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_CockEater);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	// Token: 0x02000F65 RID: 3941
 | 
			
		||||
	public class CompProperties_AbilityLifeForceCost : CompProperties_AbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		// Token: 0x06005D16 RID: 23830 RVA: 0x001FA73F File Offset: 0x001F893F
 | 
			
		||||
		public CompProperties_AbilityLifeForceCost()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_LifeForceCost);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Token: 0x06005D17 RID: 23831 RVA: 0x001FA757 File Offset: 0x001F8957
 | 
			
		||||
		public override IEnumerable<string> ExtraStatSummary()
 | 
			
		||||
		{
 | 
			
		||||
			yield return "AbilityFertilinCost" + ": " + Mathf.RoundToInt(this.fertilinCost * 100f);
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Token: 0x040038CD RID: 14541
 | 
			
		||||
		public float fertilinCost;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompProperties_AbilityPussyHeal : CompProperties_AbilityEffect
 | 
			
		||||
	{
 | 
			
		||||
		public CompProperties_AbilityPussyHeal()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_PussyHeal);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public FloatRange tendQualityRange;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompProperties_CasterIsNaked : CompProperties_EffectWithDest
 | 
			
		||||
	{
 | 
			
		||||
		public CompProperties_CasterIsNaked()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_CasterIsNaked);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,21 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class CompProperties_Seduce : CompProperties_EffectWithDest
 | 
			
		||||
	{
 | 
			
		||||
		public CompProperties_Seduce()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(CompAbilityEffect_Seduce);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		public StatDef durationMultiplier;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,16 +0,0 @@
 | 
			
		|||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,135 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using Verse.AI.Group;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class IncidentWorker_SuccubusDreamVisit : IncidentWorker
 | 
			
		||||
    {
 | 
			
		||||
        //This incidint will only fire if there is a pawn asleep and sexneed is lower than 0.25
 | 
			
		||||
        protected override bool CanFireNowSub(IncidentParms parms)
 | 
			
		||||
        {
 | 
			
		||||
            if (!base.CanFireNowSub(parms))
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            Map map = (Map)parms.target;
 | 
			
		||||
            if (!map.mapTemperature.SeasonAcceptableFor(ThingDefOf.Human))
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if (!RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi && !RJW_Genes_Settings.rjw_genes_sexdemon_visit_succubi)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (Pawn pawn in map.mapPawns.FreeColonistsAndPrisonersSpawned)
 | 
			
		||||
            {
 | 
			
		||||
                if (pawn.jobs.curDriver.asleep && xxx.need_some_sex(pawn) > 1f)
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override bool TryExecuteWorker(IncidentParms parms)
 | 
			
		||||
        {
 | 
			
		||||
            Map map = (Map)parms.target;
 | 
			
		||||
            List < Pawn > victims = ValidVictims(map).ToList();
 | 
			
		||||
            if(victims.NullOrEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            Faction faction;
 | 
			
		||||
            if (!this.TryFindFormerFaction(out faction))
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            int pawn_amount = RJW_Genes_Settings.rjw_genes_sexdemon_visit_groups ? Rand.Range(1, victims.Count) : 1;
 | 
			
		||||
            List<Pawn> new_sexdemons = new List<Pawn>();
 | 
			
		||||
            for (int i = 0; i < pawn_amount; i++)
 | 
			
		||||
            {
 | 
			
		||||
                Pawn victim = victims.RandomElement();
 | 
			
		||||
                IntVec3 loc = victim.Position;
 | 
			
		||||
 | 
			
		||||
                PawnKindDef pawnKindDef;
 | 
			
		||||
                Gender gender;
 | 
			
		||||
                if (victim.gender == Gender.Male || !RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                if ((Rand.Bool && RJW_Genes_Settings.rjw_genes_sexdemon_visit_succubi) || !RJW_Genes_Settings.rjw_genes_sexdemon_visit_incubi)
 | 
			
		||||
                {
 | 
			
		||||
                    pawnKindDef = PawnKindDef.Named("rjw_genes_succubus");
 | 
			
		||||
                    gender = Gender.Female;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    pawnKindDef = PawnKindDef.Named("rjw_genes_incubus");
 | 
			
		||||
                    gender = Gender.Male;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //Spawn succubus at pawn
 | 
			
		||||
                Pawn sexdemon = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnKindDef, faction, PawnGenerationContext.NonPlayer, -1,
 | 
			
		||||
                    false, false, false, true, false, 1f, false, true, false, true, true, false, false, false, false, 0f, 0f, null, 1f, null, null,
 | 
			
		||||
                    null, null, null, null, null, gender, null, null, null, null, false, false, false, false, null, null, null, null, null, 0f,
 | 
			
		||||
                    DevelopmentalStage.Adult, null, null, null, false));
 | 
			
		||||
                sexdemon.SetFaction(null, null);
 | 
			
		||||
                GenSpawn.Spawn(sexdemon, loc, map, WipeMode.Vanish);
 | 
			
		||||
                List<Pawn> sexdemons = new List<Pawn> { sexdemon };
 | 
			
		||||
                new_sexdemons.Add(sexdemon);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                LordMaker.MakeNewLord(Faction.OfPlayer, this.CreateLordJob(parms, sexdemon, victim), map, sexdemons);
 | 
			
		||||
 | 
			
		||||
                //Make succubus rape victim.
 | 
			
		||||
                if (RJWSettings.rape_enabled)
 | 
			
		||||
                {
 | 
			
		||||
                    //follow rjw rules
 | 
			
		||||
                    if (SexAppraiser.would_fuck(sexdemon,victim) > 0f)
 | 
			
		||||
                    {
 | 
			
		||||
                        sexdemon.pather.StopDead();
 | 
			
		||||
                        sexdemon.jobs.StopAll();
 | 
			
		||||
                        Job newJob = JobMaker.MakeJob(xxx.RapeRandom, victim);
 | 
			
		||||
                        sexdemon.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Find.LetterStack.ReceiveLetter("rjw_genes_sexdemon_visit_incident_label".Translate(), "rjw_genes_sexdemon_visit_incident_description".Translate(), LetterDefOf.PositiveEvent, new_sexdemons, null, null, null, null);
 | 
			
		||||
            //base.SendStandardLetter(baseLetterLabel, baseLetterText, this.def.letterDef, parms, succubus, Array.Empty<NamedArgument>());
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IEnumerable<Pawn> ValidVictims(Map map)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (Pawn pawn in map.mapPawns.FreeColonistsAndPrisonersSpawned)
 | 
			
		||||
            {
 | 
			
		||||
                if (pawn.jobs.curDriver.asleep && xxx.need_some_sex(pawn) > 1f)
 | 
			
		||||
                {
 | 
			
		||||
                    yield return pawn;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            yield break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool TryFindFormerFaction(out Faction formerFaction)
 | 
			
		||||
        {
 | 
			
		||||
            return Find.FactionManager.TryGetRandomNonColonyHumanlikeFaction(out formerFaction, false, true, TechLevel.Undefined, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected virtual LordJob_SuccubusVisit CreateLordJob(IncidentParms parms, Pawn succubus, Pawn target)
 | 
			
		||||
        {
 | 
			
		||||
            return new LordJob_SuccubusVisit(target);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,102 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI.Group;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    //Based on LordJob_VisitColony
 | 
			
		||||
    public class LordJob_SuccubusVisit : LordJob
 | 
			
		||||
    {
 | 
			
		||||
        public LordJob_SuccubusVisit(){}
 | 
			
		||||
        public LordJob_SuccubusVisit(Pawn target)
 | 
			
		||||
        {
 | 
			
		||||
            this.target = target;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //
 | 
			
		||||
        //Stategraph has lordtoils which say what a pawn should be doing
 | 
			
		||||
        //Transitions say when active lordtoil for pawn should change
 | 
			
		||||
        //
 | 
			
		||||
        public override StateGraph CreateGraph()
 | 
			
		||||
        {
 | 
			
		||||
            StateGraph stateGraph = new StateGraph();
 | 
			
		||||
 | 
			
		||||
            //Flirt
 | 
			
		||||
            LordToil_Flirt lordToil_Flirt = new LordToil_Flirt(this.target, 7f);
 | 
			
		||||
            stateGraph.AddToil(lordToil_Flirt);
 | 
			
		||||
            stateGraph.StartingToil = lordToil_Flirt;
 | 
			
		||||
 | 
			
		||||
            //Leave
 | 
			
		||||
            LordToil_ExitMapRandom lordToil_ExitMapRandom = new LordToil_ExitMapRandom();
 | 
			
		||||
            stateGraph.AddToil(lordToil_ExitMapRandom);
 | 
			
		||||
            LordToil_ExitMapAndDefendSelf lordToil_ExitMapAndDefendSelf = new LordToil_ExitMapAndDefendSelf();
 | 
			
		||||
            stateGraph.AddToil(lordToil_ExitMapAndDefendSelf);
 | 
			
		||||
 | 
			
		||||
            //Leave after some time
 | 
			
		||||
            Transition transition1 = new Transition(lordToil_Flirt, lordToil_ExitMapRandom, false, true);
 | 
			
		||||
            int tickLimit;
 | 
			
		||||
            if (this.durationTicks != null)
 | 
			
		||||
            {
 | 
			
		||||
                tickLimit = this.durationTicks.Value;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                tickLimit = Rand.Range(60000, 180000); //~1-3 days
 | 
			
		||||
            }
 | 
			
		||||
            transition1.AddTrigger(new Trigger_TicksPassed(tickLimit));
 | 
			
		||||
            transition1.AddPreAction(new TransitionAction_Custom(new Action(this.SuccubiLeave))); //Join or leave colony
 | 
			
		||||
            stateGraph.AddTransition(transition1);
 | 
			
		||||
 | 
			
		||||
            //If they become hostile
 | 
			
		||||
            Transition transition3 = new Transition(lordToil_Flirt, lordToil_ExitMapAndDefendSelf, false, true);
 | 
			
		||||
            transition3.AddSource(lordToil_ExitMapRandom); //Not sure what this does 
 | 
			
		||||
            transition3.AddTrigger(new Trigger_BecamePlayerEnemy());
 | 
			
		||||
            transition3.AddTrigger(new Trigger_PawnKilled());
 | 
			
		||||
            transition3.AddPostAction(new TransitionAction_EndAllJobs());
 | 
			
		||||
            stateGraph.AddTransition(transition3, false);
 | 
			
		||||
 | 
			
		||||
            Transition transition4 = new Transition(lordToil_ExitMapRandom, lordToil_ExitMapAndDefendSelf, false, true);
 | 
			
		||||
            transition4.AddSource(lordToil_Flirt); //Not sure what this does 
 | 
			
		||||
            transition4.AddTrigger(new Trigger_PawnHarmed(1f, true, Faction.OfPlayer));
 | 
			
		||||
            stateGraph.AddTransition(transition4, false);
 | 
			
		||||
 | 
			
		||||
            return stateGraph;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //add toggleable gizmo to allow playes to have colonists sex the succubus into joining your colony
 | 
			
		||||
        //comfort pawn? cooldown?
 | 
			
		||||
        public override IEnumerable<Gizmo> GetPawnGizmos(Pawn p)
 | 
			
		||||
        {
 | 
			
		||||
            return base.GetPawnGizmos(p);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void ExposeData()
 | 
			
		||||
        {
 | 
			
		||||
            Scribe_Values.Look<int?>(ref this.durationTicks, "durationTicks", null, false);
 | 
			
		||||
            Scribe_References.Look<Pawn>(ref this.target, "target", false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SuccubiLeave()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (Pawn pawn in this.lord.ownedPawns)
 | 
			
		||||
            {
 | 
			
		||||
                if(colonyJoiners.Contains(pawn))
 | 
			
		||||
                {
 | 
			
		||||
                    RecruitUtility.Recruit(pawn, Faction.OfPlayer);
 | 
			
		||||
                    Find.LetterStack.ReceiveLetter("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
 | 
			
		||||
                {
 | 
			
		||||
                    Messages.Message("SuccubusLeaving".Translate(xxx.get_pawnname(pawn)), pawn, MessageTypeDefOf.NeutralEvent, true);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Pawn target;
 | 
			
		||||
        private int? durationTicks;
 | 
			
		||||
        public List<Pawn> colonyJoiners = new List<Pawn>();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,140 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class Gene_LifeForce : Gene_Resource, IGeneResourceDrain
 | 
			
		||||
	{
 | 
			
		||||
        //Gene should only be active if sex is allowed for this pawn 
 | 
			
		||||
        public override bool Active
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				if (this.Overridden)
 | 
			
		||||
				{
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				Pawn pawn = this.pawn;
 | 
			
		||||
				
 | 
			
		||||
				return ((pawn != null) ? pawn.ageTracker : null) == null || 
 | 
			
		||||
					((float)this.pawn.ageTracker.AgeBiologicalYears >= this.def.minAgeActive);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        public override void ExposeData()
 | 
			
		||||
        {
 | 
			
		||||
            base.ExposeData();
 | 
			
		||||
			Scribe_Values.Look<bool>(ref this.StoredCumAllowed, "StoredCumAllowed", true, false);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        public bool ShouldConsumeLifeForceNow()
 | 
			
		||||
		{
 | 
			
		||||
			return this.Value < this.targetValue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//Same as Gene_Hemogen
 | 
			
		||||
		public override IEnumerable<Gizmo> GetGizmos()
 | 
			
		||||
		{
 | 
			
		||||
			foreach (Gizmo gizmo in base.GetGizmos())
 | 
			
		||||
			{
 | 
			
		||||
				yield return gizmo;
 | 
			
		||||
			}
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//every tick it decreases fertilin value and everyday if fertilin is below alert minimum there a ~50 chance for mental break
 | 
			
		||||
		public override void Tick()
 | 
			
		||||
		{
 | 
			
		||||
			base.Tick();
 | 
			
		||||
			if (this.CanOffset && this.Resource != null)
 | 
			
		||||
            {
 | 
			
		||||
				GeneUtility.OffsetLifeForce(this, -this.ResourceLossPerDay / 60000f);
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool StoredCumAllowed = true;
 | 
			
		||||
		public Gene_Resource Resource
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public Pawn Pawn
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.pawn;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public bool CanOffset
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.pawn.Spawned && this.Active;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public float ResourceLossPerDay
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.def.resourceLossPerDay;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public string DisplayLabel
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.def.resourceLabel;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override float InitialResourceMax
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return 1f;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override float MinLevelForAlert
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return 0.2f;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public override float MaxLevelOffset
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return base.MaxLevelOffset;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		protected override Color BarColor
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Color.grey;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		protected override Color BarHighlightColor
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Color.white;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,68 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class Gene_LifeForceDrain : Gene, IGeneResourceDrain
 | 
			
		||||
	{
 | 
			
		||||
		public Gene_Resource Resource
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				if (this.cachedLifeForceGene == null || !this.cachedLifeForceGene.Active)
 | 
			
		||||
				{
 | 
			
		||||
					this.cachedLifeForceGene = this.pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
				}
 | 
			
		||||
				return this.cachedLifeForceGene;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CanOffset
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.Active && this.Resource != null && this.Resource.Active;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public float ResourceLossPerDay
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.def.resourceLossPerDay;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Pawn Pawn
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.pawn;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public string DisplayLabel
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return this.Label + " (" + "Gene".Translate() + ")";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Tick()
 | 
			
		||||
		{
 | 
			
		||||
			base.Tick();
 | 
			
		||||
			if (this.CanOffset && this.Resource != null)
 | 
			
		||||
            {
 | 
			
		||||
				GeneUtility.OffsetLifeForce(this, -this.ResourceLossPerDay / 60000);
 | 
			
		||||
			}			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Unsaved(false)]
 | 
			
		||||
		private Gene_LifeForce cachedLifeForceGene;
 | 
			
		||||
 | 
			
		||||
		private const float MinAgeForDrain = 3f;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,118 +0,0 @@
 | 
			
		|||
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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public Gene_LifeForce_Empath() : base()
 | 
			
		||||
        {
 | 
			
		||||
            SetValuesFromExtension();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SetValuesFromExtension()
 | 
			
		||||
        {
 | 
			
		||||
            LifeForceEmpathExtension empathExt = GeneDefOf.rjw_genes_lifeforce_empath.GetModExtension<LifeForceEmpathExtension>();
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
                }
 | 
			
		||||
                        
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates an IEnumerable of all pawns which are closeby and in lineofsight, self and other pawns with lifeforce gene are skipped (to prevent loops).
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pos">The position of the empath on the map</param>
 | 
			
		||||
        /// <param name="map">The map the empath is on</param>
 | 
			
		||||
        /// <returns>A list of all pawns that are close enough for the empath to connect.</returns>
 | 
			
		||||
        private IEnumerable<Pawn> 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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Adjust the empaths lifeforce depending on the farmed pawns sexneed. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="farmedPawn">The pawn affecting the empath, increasing or decreasing his lifeforce. </param>
 | 
			
		||||
        private void FarmLifeForce(Pawn farmedPawn)
 | 
			
		||||
        {
 | 
			
		||||
            // Short rename to make rest more obvious.
 | 
			
		||||
            Pawn empath = pawn;
 | 
			
		||||
 | 
			
		||||
            if (farmedPawn == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var sexneed = farmedPawn.needs.TryGetNeed<rjw.Need_Sex>();
 | 
			
		||||
 | 
			
		||||
            // 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);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class HediffCompProperties_SeverityFromFertilin : HediffCompProperties
 | 
			
		||||
	{
 | 
			
		||||
		public HediffCompProperties_SeverityFromFertilin()
 | 
			
		||||
		{
 | 
			
		||||
			this.compClass = typeof(HediffComp_SeverityFromFertilin);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Token: 0x04001162 RID: 4450
 | 
			
		||||
		public float severityPerHourEmpty;
 | 
			
		||||
 | 
			
		||||
		// Token: 0x04001163 RID: 4451
 | 
			
		||||
		public float severityPerHourHemogen;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,66 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class HediffComp_SeverityFromFertilin : HediffComp
 | 
			
		||||
	{
 | 
			
		||||
		public HediffCompProperties_SeverityFromFertilin Props
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (HediffCompProperties_SeverityFromFertilin)this.props;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public override bool CompShouldRemove
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				Pawn_GeneTracker genes = base.Pawn.genes;
 | 
			
		||||
				return ((genes != null) ? genes.GetFirstGeneOfType<Gene_LifeForce>() : null) == null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		private Gene_LifeForce LifeForce
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				if (this.cachedLifeForceGene == null)
 | 
			
		||||
				{
 | 
			
		||||
					this.cachedLifeForceGene = base.Pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
				}
 | 
			
		||||
				return this.cachedLifeForceGene;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public override void CompPostTick(ref float severityAdjustment)
 | 
			
		||||
		{
 | 
			
		||||
			base.CompPostTick(ref severityAdjustment);
 | 
			
		||||
			severityAdjustment += ((this.LifeForce.Value > 0f) ? this.Props.severityPerHourHemogen : this.Props.severityPerHourEmpty) / 2500f;
 | 
			
		||||
			this.MentalBreak();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void MentalBreak()
 | 
			
		||||
        {
 | 
			
		||||
			if (cachedLifeForceGene.Resource.Value <= cachedLifeForceGene.Resource.MinLevelForAlert && this.Pawn.IsHashIntervalTick(2500) && Rand.Chance(0.03f)) //~50% chance each day for mental break
 | 
			
		||||
			{
 | 
			
		||||
				if (this.Pawn.genes.HasGene(GeneDefOf.rjw_genes_cum_eater)
 | 
			
		||||
				|| this.Pawn.genes.HasGene(GeneDefOf.rjw_genes_fertilin_absorber) || this.Pawn.genes.HasGene(GeneDefOf.rjw_genes_drainer))
 | 
			
		||||
				{
 | 
			
		||||
					//TODO: use mentalstatedef instead of mentalbreakdef
 | 
			
		||||
					MentalBreakDef randomrape = GeneDefOf.rjw_genes_lifeforce_randomrape;
 | 
			
		||||
					if (ModsConfig.BiotechActive &&
 | 
			
		||||
						this.Pawn.Spawned && !this.Pawn.InMentalState && !this.Pawn.Downed &&
 | 
			
		||||
						randomrape.Worker.BreakCanOccur(this.Pawn))
 | 
			
		||||
					{
 | 
			
		||||
						randomrape.Worker.TryStart(this.Pawn, "MentalBreakNoFertilin".Translate(), false);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private Gene_LifeForce cachedLifeForceGene;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,24 +0,0 @@
 | 
			
		|||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// This class checks for pawns with LifeForce and Cumeater Gene to add Fertilin when eating cum (the Item from RJW-Sexperience).
 | 
			
		||||
	/// </summary>
 | 
			
		||||
    public class IngestionOutcomeDoer_LifeForceOffset : IngestionOutcomeDoer
 | 
			
		||||
	{
 | 
			
		||||
		public const float DEFAULT_FERTILIN_PER_UNIT = 1f;
 | 
			
		||||
		public float FertilinPerUnit = 1f;
 | 
			
		||||
 | 
			
		||||
		protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
 | 
			
		||||
		{
 | 
			
		||||
			if (GeneUtility.HasLifeForce(pawn) && GeneUtility.IsCumEater(pawn))
 | 
			
		||||
            {
 | 
			
		||||
				float num = ingested.stackCount * this.FertilinPerUnit / 100;
 | 
			
		||||
				GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(pawn), num);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,90 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class JobDriver_CastAbilityAfterSex : JobDriver_SexBaseInitiator
 | 
			
		||||
	{
 | 
			
		||||
		//Summary//
 | 
			
		||||
		//Similar to jobdriver rape, but it cast an ability after sex and tries to limit what kind of sexinteractions are allowed.
 | 
			
		||||
		protected override IEnumerable<Toil> MakeNewToils()
 | 
			
		||||
		{
 | 
			
		||||
			base.setup_ticks();
 | 
			
		||||
			//this.FailOnDespawnedOrNull(TargetIndex.A);
 | 
			
		||||
			//this.FailOnCannotTouch(TargetIndex.B, PathEndMode.OnCell);
 | 
			
		||||
			this.FailOnDespawnedNullOrForbidden(this.iTarget);
 | 
			
		||||
			//this.FailOn(() => !target.health.capacities.CanBeAwake);
 | 
			
		||||
			JobDef PartnerJob = xxx.gettin_raped;
 | 
			
		||||
			yield return Toils_Goto.Goto(TargetIndex.A, PathEndMode.OnCell);
 | 
			
		||||
			yield return new Toil
 | 
			
		||||
			{
 | 
			
		||||
				defaultCompleteMode = ToilCompleteMode.Instant,
 | 
			
		||||
				socialMode = RandomSocialMode.Off,
 | 
			
		||||
				initAction = delegate ()
 | 
			
		||||
				{
 | 
			
		||||
					Job newJob = JobMaker.MakeJob(PartnerJob, this.pawn, this.Partner);
 | 
			
		||||
					this.Partner.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			Toil toil = new Toil();
 | 
			
		||||
			toil.defaultCompleteMode = ToilCompleteMode.Never;
 | 
			
		||||
			toil.socialMode = RandomSocialMode.Off;
 | 
			
		||||
			toil.defaultDuration = this.duration;
 | 
			
		||||
			toil.handlingFacing = true;
 | 
			
		||||
			toil.FailOn(() => this.Partner.CurJob.def != PartnerJob);
 | 
			
		||||
			toil.initAction = delegate ()
 | 
			
		||||
			{
 | 
			
		||||
				this.Partner.pather.StopDead();
 | 
			
		||||
				this.Partner.jobs.curDriver.asleep = false;
 | 
			
		||||
 | 
			
		||||
				//Tries to find CompProperties_SexInteractionRequirements and if it finds it it will try and generate sexprops based on the sexpropsrequirements.
 | 
			
		||||
				foreach (AbilityComp comp in this.job.ability.comps)
 | 
			
		||||
				{
 | 
			
		||||
					if (comp.props is CompProperties_SexInteractionRequirements)
 | 
			
		||||
					{
 | 
			
		||||
						CompProperties_SexInteractionRequirements sexpropsreq = comp.props as CompProperties_SexInteractionRequirements;
 | 
			
		||||
						this.Sexprops = CustomSexInteraction_Helper.GenerateSexProps(this.pawn, this.Partner, sexpropsreq);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				this.Start();
 | 
			
		||||
				this.Sexprops.usedCondom = (CondomUtility.TryUseCondom(this.pawn) || CondomUtility.TryUseCondom(this.Partner));
 | 
			
		||||
			};
 | 
			
		||||
			toil.AddPreTickAction(delegate
 | 
			
		||||
			{
 | 
			
		||||
				if (this.pawn.IsHashIntervalTick(this.ticks_between_hearts))
 | 
			
		||||
				{
 | 
			
		||||
					this.ThrowMetaIconF(this.pawn.Position, this.pawn.Map, FleckDefOf.Heart);
 | 
			
		||||
				}
 | 
			
		||||
				this.SexTick(this.pawn, this.Partner, true, true);
 | 
			
		||||
				SexUtility.reduce_rest(this.Partner, 1f);
 | 
			
		||||
				SexUtility.reduce_rest(this.pawn, 1f);
 | 
			
		||||
				if (this.ticks_left <= 0)
 | 
			
		||||
				{
 | 
			
		||||
					this.ReadyForNextToil();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			toil.AddFinishAction(delegate
 | 
			
		||||
			{
 | 
			
		||||
				this.End();
 | 
			
		||||
			});
 | 
			
		||||
			yield return toil;
 | 
			
		||||
			yield return new Toil
 | 
			
		||||
			{
 | 
			
		||||
				initAction = delegate ()
 | 
			
		||||
				{
 | 
			
		||||
					SexUtility.ProcessSex(this.Sexprops);
 | 
			
		||||
				},
 | 
			
		||||
				defaultCompleteMode = ToilCompleteMode.Instant
 | 
			
		||||
			};
 | 
			
		||||
			yield return Toils_Combat.CastVerb(TargetIndex.A, TargetIndex.B, false);
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,57 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class JobDriver_Flirt : JobDriver
 | 
			
		||||
	{
 | 
			
		||||
		private Pawn Target
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return (Pawn)((Thing)this.pawn.CurJob.GetTarget(TargetIndex.A));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public override bool TryMakePreToilReservations(bool errorOnFailed)
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//Some wait toils to induce delay
 | 
			
		||||
		protected override IEnumerable<Toil> MakeNewToils()
 | 
			
		||||
		{
 | 
			
		||||
			this.FailOnDespawnedOrNull(TargetIndex.A);
 | 
			
		||||
			yield return Toils_Interpersonal.GotoInteractablePosition(TargetIndex.A);
 | 
			
		||||
			yield return Toils_General.Wait(300, TargetIndex.A);
 | 
			
		||||
			yield return Toils_Interpersonal.WaitToBeAbleToInteract(this.pawn);
 | 
			
		||||
			Toil toil = Toils_Interpersonal.GotoInteractablePosition(TargetIndex.A);
 | 
			
		||||
			toil.socialMode = RandomSocialMode.Off;
 | 
			
		||||
			yield return toil;
 | 
			
		||||
			yield return this.InteractToil();
 | 
			
		||||
			Toil toil1 = Toils_General.Wait(300, TargetIndex.A);
 | 
			
		||||
			toil1.socialMode = RandomSocialMode.Off;
 | 
			
		||||
			yield return toil1;
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
		private Toil InteractToil()
 | 
			
		||||
		{
 | 
			
		||||
			return Toils_General.Do(delegate
 | 
			
		||||
			{
 | 
			
		||||
				if (this.pawn.interactions.TryInteractWith(this.Target, ThoughtDefOf.rjw_genes_flirt))
 | 
			
		||||
				{
 | 
			
		||||
					Need_Sex need_Sex = this.Target.needs.TryGetNeed<Need_Sex>();
 | 
			
		||||
					need_Sex.CurLevel += -0.01f;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private const TargetIndex TargetInd = TargetIndex.A;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,55 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
using rjw.Modules.Interactions.Enums;
 | 
			
		||||
using rjw.Modules.Interactions.Helpers;
 | 
			
		||||
using rjw.Modules.Interactions.Objects;
 | 
			
		||||
using rjw.Modules.Interactions.Contexts;
 | 
			
		||||
using rjw.Modules.Interactions.Implementation;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class JobDriver_Seduced : JobDriver
 | 
			
		||||
	{
 | 
			
		||||
		//Summary//
 | 
			
		||||
		//Makes a pawn move to seducing pawn and then tries to rape them.
 | 
			
		||||
		protected override IEnumerable<Toil> MakeNewToils()
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
			this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
 | 
			
		||||
			this.FailOn(() => !this.pawn.CanReserve(TargetA, xxx.max_rapists_per_prisoner, 0, null, false));
 | 
			
		||||
			this.FailOn(() => this.pawn.IsFighting());
 | 
			
		||||
			this.FailOn(() => this.pawn.Drafted);
 | 
			
		||||
	
 | 
			
		||||
			Pawn partner = this.job.GetTarget(TargetIndex.A).Pawn;
 | 
			
		||||
			yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);
 | 
			
		||||
			yield return new Toil
 | 
			
		||||
			{
 | 
			
		||||
				defaultCompleteMode = ToilCompleteMode.Instant,
 | 
			
		||||
				socialMode = RandomSocialMode.Off,
 | 
			
		||||
				initAction = delegate ()
 | 
			
		||||
				{
 | 
			
		||||
					if(partner != null)
 | 
			
		||||
                    {
 | 
			
		||||
						partner.drafter.Drafted = false;
 | 
			
		||||
						this.pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.rjw_genes_seduced, partner, null);
 | 
			
		||||
						Job newJob = JobMaker.MakeJob(JobDefOf.sex_on_spot, pawn);
 | 
			
		||||
						partner.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool TryMakePreToilReservations(bool errorOnFailed)
 | 
			
		||||
		{
 | 
			
		||||
			return this.pawn.Reserve(TargetA, this.job, xxx.max_rapists_per_prisoner, 0, null, errorOnFailed);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,108 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
using rjw.Modules.Interactions.Enums;
 | 
			
		||||
using rjw.Modules.Interactions.Helpers;
 | 
			
		||||
using rjw.Modules.Interactions.Objects;
 | 
			
		||||
using rjw.Modules.Interactions.Contexts;
 | 
			
		||||
using rjw.Modules.Interactions.Implementation;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class JobDriver_SexOnSpot : JobDriver_SexBaseInitiator
 | 
			
		||||
	{
 | 
			
		||||
		protected override IEnumerable<Toil> MakeNewToils()
 | 
			
		||||
		{
 | 
			
		||||
			if (RJWSettings.DebugRape)
 | 
			
		||||
			{
 | 
			
		||||
				ModLog.Message(base.GetType().ToString() + "::MakeNewToils() called");
 | 
			
		||||
			}
 | 
			
		||||
			base.setup_ticks();
 | 
			
		||||
			JobDef PartnerJob = JobDefOf.sex_on_spot_reciever;
 | 
			
		||||
			this.FailOnDespawnedNullOrForbidden(this.iTarget);
 | 
			
		||||
			this.FailOn(() => !this.pawn.CanReserve(this.Partner, xxx.max_rapists_per_prisoner, 0, null, false));
 | 
			
		||||
			this.FailOn(() => this.pawn.IsFighting());
 | 
			
		||||
			this.FailOn(() => this.Partner.IsFighting());
 | 
			
		||||
			this.FailOn(() => this.pawn.Drafted);
 | 
			
		||||
			yield return Toils_Goto.GotoThing(this.iTarget, PathEndMode.Touch);
 | 
			
		||||
			if (this.pawn.HostileTo(this.Partner))
 | 
			
		||||
            {
 | 
			
		||||
				Partner.health.AddHediff(xxx.submitting);
 | 
			
		||||
            }
 | 
			
		||||
			yield return Toils_Goto.GotoThing(this.iTarget, PathEndMode.OnCell);
 | 
			
		||||
			//Give thought malus to partner (I was seduced into having sex against my will)
 | 
			
		||||
			yield return new Toil
 | 
			
		||||
			{
 | 
			
		||||
				defaultCompleteMode = ToilCompleteMode.Instant,
 | 
			
		||||
				socialMode = RandomSocialMode.Off,
 | 
			
		||||
				initAction = delegate ()
 | 
			
		||||
				{
 | 
			
		||||
					if (!(this.Partner.jobs.curDriver is JobDriver_SexOnSpotReciever))
 | 
			
		||||
					{
 | 
			
		||||
						Job newJob = JobMaker.MakeJob(PartnerJob, this.pawn);
 | 
			
		||||
						Building_Bed building_Bed = null;
 | 
			
		||||
						if (this.Partner.GetPosture() == PawnPosture.LayingInBed)
 | 
			
		||||
						{
 | 
			
		||||
							building_Bed = this.Partner.CurrentBed();
 | 
			
		||||
						}
 | 
			
		||||
						this.Partner.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false, false, null, false, true);
 | 
			
		||||
						if (building_Bed != null)
 | 
			
		||||
						{
 | 
			
		||||
							JobDriver_SexOnSpotReciever jobDriver_SexOnSpotReciever = this.Partner.jobs.curDriver as JobDriver_SexOnSpotReciever;
 | 
			
		||||
							if (jobDriver_SexOnSpotReciever == null)
 | 
			
		||||
							{
 | 
			
		||||
								return;
 | 
			
		||||
							}
 | 
			
		||||
							jobDriver_SexOnSpotReciever.Set_bed(building_Bed);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			Toil toil = new Toil();
 | 
			
		||||
			toil.defaultCompleteMode = ToilCompleteMode.Never;
 | 
			
		||||
			toil.defaultDuration = this.duration;
 | 
			
		||||
			toil.handlingFacing = true;
 | 
			
		||||
			toil.FailOn(() => this.Partner.CurJob.def != PartnerJob);
 | 
			
		||||
			toil.initAction = delegate ()
 | 
			
		||||
			{
 | 
			
		||||
				this.Partner.pather.StopDead();
 | 
			
		||||
				this.Partner.jobs.curDriver.asleep = false;
 | 
			
		||||
				this.Start();
 | 
			
		||||
			};
 | 
			
		||||
			toil.tickAction = delegate ()
 | 
			
		||||
			{
 | 
			
		||||
				if (this.pawn.IsHashIntervalTick(this.ticks_between_hearts))
 | 
			
		||||
				{
 | 
			
		||||
					this.ThrowMetaIconF(this.pawn.Position, this.pawn.Map, FleckDefOf.Heart);
 | 
			
		||||
				}
 | 
			
		||||
				this.SexTick(this.pawn, this.Partner, true, true);
 | 
			
		||||
				SexUtility.reduce_rest(this.Partner, 1f);
 | 
			
		||||
				SexUtility.reduce_rest(this.pawn, 2f);
 | 
			
		||||
				if (this.ticks_left <= 0)
 | 
			
		||||
				{
 | 
			
		||||
					this.ReadyForNextToil();
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			toil.AddFinishAction(delegate
 | 
			
		||||
			{
 | 
			
		||||
				this.End();
 | 
			
		||||
			});
 | 
			
		||||
			yield return toil;
 | 
			
		||||
			yield return new Toil
 | 
			
		||||
			{
 | 
			
		||||
				initAction = delegate ()
 | 
			
		||||
				{
 | 
			
		||||
					SexUtility.ProcessSex(this.Sexprops);
 | 
			
		||||
				},
 | 
			
		||||
				defaultCompleteMode = ToilCompleteMode.Instant
 | 
			
		||||
			};
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,83 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
using rjw.Modules.Interactions.Enums;
 | 
			
		||||
using rjw.Modules.Interactions.Helpers;
 | 
			
		||||
using rjw.Modules.Interactions.Objects;
 | 
			
		||||
using rjw.Modules.Interactions.Contexts;
 | 
			
		||||
using rjw.Modules.Interactions.Implementation;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	//Modified JobDriver_SexBaseRecieverLoved from rjw
 | 
			
		||||
	public class JobDriver_SexOnSpotReciever : JobDriver_SexBaseReciever
 | 
			
		||||
	{
 | 
			
		||||
		protected override IEnumerable<Toil> MakeNewToils()
 | 
			
		||||
		{
 | 
			
		||||
			base.setup_ticks();
 | 
			
		||||
			this.parteners.Add(base.Partner);
 | 
			
		||||
			if (this.pawn.relations.OpinionOf(base.Partner) < 0)
 | 
			
		||||
			{
 | 
			
		||||
				this.ticks_between_hearts += 50;
 | 
			
		||||
			}
 | 
			
		||||
			else if (this.pawn.relations.OpinionOf(base.Partner) > 60)
 | 
			
		||||
			{
 | 
			
		||||
				this.ticks_between_hearts -= 25;
 | 
			
		||||
			}
 | 
			
		||||
			this.FailOnDespawnedOrNull(this.iTarget);
 | 
			
		||||
			this.FailOn(() => !base.Partner.health.capacities.CanBeAwake);
 | 
			
		||||
			this.FailOn(() => this.pawn.Drafted);
 | 
			
		||||
			this.FailOn(() => base.Partner.Drafted);
 | 
			
		||||
			yield return Toils_Reserve.Reserve(this.iTarget, 1, 0, null);
 | 
			
		||||
			Toil toil2 = this.MakeSexToil();
 | 
			
		||||
			toil2.handlingFacing = false;
 | 
			
		||||
			yield return toil2;
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private Toil MakeSexToil()
 | 
			
		||||
		{
 | 
			
		||||
			Toil toil = new Toil();
 | 
			
		||||
			toil.defaultCompleteMode = ToilCompleteMode.Never;
 | 
			
		||||
			toil.socialMode = RandomSocialMode.Off;
 | 
			
		||||
			toil.handlingFacing = true;
 | 
			
		||||
			toil.tickAction = delegate ()
 | 
			
		||||
			{
 | 
			
		||||
				if (this.pawn.IsHashIntervalTick(this.ticks_between_hearts))
 | 
			
		||||
				{
 | 
			
		||||
					base.ThrowMetaIconF(this.pawn.Position, this.pawn.Map, FleckDefOf.Heart);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			toil.AddEndCondition(delegate
 | 
			
		||||
			{
 | 
			
		||||
				if (this.parteners.Count <= 0)
 | 
			
		||||
				{
 | 
			
		||||
					return JobCondition.Succeeded;
 | 
			
		||||
				}
 | 
			
		||||
				return JobCondition.Ongoing;
 | 
			
		||||
			});
 | 
			
		||||
			toil.AddFinishAction(delegate
 | 
			
		||||
			{
 | 
			
		||||
				if (xxx.is_human(this.pawn))
 | 
			
		||||
				{
 | 
			
		||||
					this.pawn.Drawer.renderer.graphics.ResolveApparelGraphics();
 | 
			
		||||
				}
 | 
			
		||||
				GlobalTextureAtlasManager.TryMarkPawnFrameSetDirty(this.pawn);
 | 
			
		||||
				Hediff submitting = this.pawn.health.hediffSet.GetFirstHediffOfDef(xxx.submitting);
 | 
			
		||||
				if (submitting != null)
 | 
			
		||||
				{
 | 
			
		||||
					this.pawn.health.RemoveHediff(submitting);
 | 
			
		||||
					this.pawn.stances.stunner.StunFor(60, this.pawn, true, true);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			toil.socialMode = RandomSocialMode.Off;
 | 
			
		||||
			return toil;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,24 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class JobGiver_Flirt : ThinkNode_JobGiver
 | 
			
		||||
	{
 | 
			
		||||
		// Token: 0x0600405A RID: 16474 RVA: 0x0017271C File Offset: 0x0017091C
 | 
			
		||||
		protected override Job TryGiveJob(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn target = pawn.mindState.duty.focus.Pawn;
 | 
			
		||||
			if (pawn.CanReach(target, PathEndMode.InteractionCell, Danger.Deadly) && !target.jobs.curDriver.asleep)
 | 
			
		||||
            {
 | 
			
		||||
				return JobMaker.MakeJob(JobDefOf.rjw_genes_flirt, target);
 | 
			
		||||
			}
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,87 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class JobGiver_GetLifeForce : ThinkNode_JobGiver
 | 
			
		||||
	{
 | 
			
		||||
		protected override Job TryGiveJob(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn_GeneTracker genes = pawn.genes;
 | 
			
		||||
			Gene_LifeForce gene_lifeforce = (genes != null) ? genes.GetFirstGeneOfType<Gene_LifeForce>() : null;
 | 
			
		||||
			if (gene_lifeforce == null)
 | 
			
		||||
			{
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
			if (!gene_lifeforce.ShouldConsumeLifeForceNow())
 | 
			
		||||
			{
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
 | 
			
		||||
			if (ModsConfig.IsActive("rjw.sexperience") && gene_lifeforce.StoredCumAllowed && genes.HasGene(GeneDefOf.rjw_genes_cum_eater))
 | 
			
		||||
            {
 | 
			
		||||
				Thing gatheredCum = this.GetStoredCum(pawn);
 | 
			
		||||
				if (gatheredCum == null)
 | 
			
		||||
				{
 | 
			
		||||
					return null;
 | 
			
		||||
				}
 | 
			
		||||
				IngestionOutcomeDoer_LifeForceOffset ingestionOutcomeDoer = (IngestionOutcomeDoer_LifeForceOffset)gatheredCum.def.ingestible.outcomeDoers.First((IngestionOutcomeDoer x) => x is IngestionOutcomeDoer_LifeForceOffset);
 | 
			
		||||
				if (ingestionOutcomeDoer == null)
 | 
			
		||||
                {
 | 
			
		||||
					return null;
 | 
			
		||||
                }
 | 
			
		||||
				int num = Mathf.RoundToInt(((gene_lifeforce.targetValue - gene_lifeforce.Value) * 100 + 10) / IngestionOutcomeDoer_LifeForceOffset.DEFAULT_FERTILIN_PER_UNIT);
 | 
			
		||||
				if (gatheredCum != null && num > 0)
 | 
			
		||||
				{
 | 
			
		||||
					Job job = JobMaker.MakeJob(RimWorld.JobDefOf.Ingest, gatheredCum);
 | 
			
		||||
					job.count = Mathf.Min(gatheredCum.stackCount, num);
 | 
			
		||||
					job.ingestTotalCount = true;
 | 
			
		||||
					return job;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//From JobGiver_GetHemogen, dont know exactly what this influences
 | 
			
		||||
		public override float GetPriority(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			if (!ModsConfig.BiotechActive)
 | 
			
		||||
			{
 | 
			
		||||
				return 0f;
 | 
			
		||||
			}
 | 
			
		||||
			Pawn_GeneTracker genes = pawn.genes;
 | 
			
		||||
			if (((genes != null) ? genes.GetFirstGeneOfType<Gene_LifeForce>() : null) == null)
 | 
			
		||||
			{
 | 
			
		||||
				return 0f;
 | 
			
		||||
			}
 | 
			
		||||
			return 9.1f;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private Thing GetStoredCum(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			Thing carriedThing = pawn.carryTracker.CarriedThing;
 | 
			
		||||
			ThingDef gatheredCum = ThingDef.Named("GatheredCum");
 | 
			
		||||
			if (carriedThing != null && carriedThing.def == gatheredCum)
 | 
			
		||||
			{
 | 
			
		||||
				return carriedThing;
 | 
			
		||||
			}
 | 
			
		||||
			for (int i = 0; i < pawn.inventory.innerContainer.Count; i++)
 | 
			
		||||
			{
 | 
			
		||||
				if (pawn.inventory.innerContainer[i].def == gatheredCum)
 | 
			
		||||
				{
 | 
			
		||||
					return pawn.inventory.innerContainer[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, pawn.Map.listerThings.ThingsOfDef(gatheredCum), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false, false, false), 9999f, (Thing t) => pawn.CanReserve(t, 1, -1, null, false) && !t.IsForbidden(pawn), null);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,38 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class JobGiver_LifeForce_RandomRape : JobGiver_RandomRape
 | 
			
		||||
    {
 | 
			
		||||
		protected override Job TryGiveJob(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			if (!can_rape(pawn, false))
 | 
			
		||||
			{
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
			Pawn pawn2 = this.find_victim(pawn, pawn.Map);
 | 
			
		||||
			if (pawn2 == null)
 | 
			
		||||
			{
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
			return JobMaker.MakeJob(JobDefOf.rjw_genes_lifeforce_randomrape, pawn2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//same as xxx.canrape from rjw, but without last requirements.
 | 
			
		||||
		public static bool can_rape(Pawn pawn, bool forced = false)
 | 
			
		||||
		{
 | 
			
		||||
			return RJWSettings.rape_enabled && (xxx.is_mechanoid(pawn) || ((xxx.can_fuck(pawn) || 
 | 
			
		||||
				(!xxx.is_male(pawn) && xxx.get_vulnerability(pawn) < RJWSettings.nonFutaWomenRaping_MaxVulnerability && 
 | 
			
		||||
				xxx.can_be_fucked(pawn))) && (!xxx.is_human(pawn) || ((pawn.ageTracker.Growth >= 1f || pawn.ageTracker.CurLifeStage.reproductive)))));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,188 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using rjw;
 | 
			
		||||
using RJWSexperience;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using Verse.AI.Group;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class JobGiver_TryQuickieWith : ThinkNode_JobGiver
 | 
			
		||||
	{
 | 
			
		||||
		protected override Job TryGiveJob(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn target = pawn.mindState.duty.focus.Pawn;
 | 
			
		||||
			Pawn_JobTracker jobs = target.jobs;
 | 
			
		||||
			string pawn_name = xxx.get_pawnname(pawn);
 | 
			
		||||
			string target_name = xxx.get_pawnname(target);
 | 
			
		||||
			//can reserve eachother
 | 
			
		||||
			if (pawn.CanReserveAndReach(target, PathEndMode.InteractionCell, Danger.Some) && target.CanReserve(pawn, 1, 0, null, false))				
 | 
			
		||||
			{
 | 
			
		||||
				//Dont interrupt player
 | 
			
		||||
				if (!(((jobs != null) ? jobs.curJob : null) != null && jobs.curJob.playerForced))
 | 
			
		||||
                {
 | 
			
		||||
					float willingness = TargetWillingness(pawn, target);
 | 
			
		||||
					if (Rand.Chance(willingness))
 | 
			
		||||
                    {
 | 
			
		||||
						Job newJob =JobMaker.MakeJob(xxx.quick_sex, target);
 | 
			
		||||
						
 | 
			
		||||
						//Pawn joins faction when lordJob ends instead of leaving
 | 
			
		||||
						//in the future determine the chance of this another way
 | 
			
		||||
						if (Rand.Chance(JoinChance(pawn, target)))
 | 
			
		||||
                        {
 | 
			
		||||
							Lord lord = pawn.GetLord();
 | 
			
		||||
							LordJob_SuccubusVisit lordJob = lord == null? null : lord.LordJob as LordJob_SuccubusVisit;
 | 
			
		||||
							if (lordJob != null)
 | 
			
		||||
                            {
 | 
			
		||||
								if (!lordJob.colonyJoiners.Contains(pawn))
 | 
			
		||||
                                {
 | 
			
		||||
									lordJob.colonyJoiners.Add(pawn);
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
						}
 | 
			
		||||
						return newJob;
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
                    {
 | 
			
		||||
						if (RJWSettings.DebugLogJoinInBed) //change this when we have our own settigns
 | 
			
		||||
						{
 | 
			
		||||
							ModLog.Message(string.Format("{0} was not interested in having sex with {1}: ({2} chance)", pawn_name, target_name, willingness));
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
                }
 | 
			
		||||
				else
 | 
			
		||||
                {
 | 
			
		||||
					if (RJWSettings.DebugLogJoinInBed) //change this when we have our own settigns
 | 
			
		||||
					{
 | 
			
		||||
						//ModLog.Message(string.Format(" find_pawn_to_fuck({0}): lover has important job ({1}), skipping", pawn_name, target.jobs.curJob.def));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
            {
 | 
			
		||||
				if (RJWSettings.DebugLogJoinInBed) //change this when we have our own settigns
 | 
			
		||||
				{
 | 
			
		||||
					ModLog.Message(" (" + pawn_name + "): cannot reach or reserve " + target_name);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		public static float TargetWillingness(Pawn pawn, Pawn target)
 | 
			
		||||
        {
 | 
			
		||||
			string pawn_name = xxx.get_pawnname(pawn);
 | 
			
		||||
			float willingness = SexAppraiser.would_fuck(target,pawn);
 | 
			
		||||
			bool nymph = xxx.is_nympho(target);
 | 
			
		||||
			bool loverelation = LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target);
 | 
			
		||||
			if (nymph || loverelation)
 | 
			
		||||
            {
 | 
			
		||||
				willingness *= 2;
 | 
			
		||||
            }
 | 
			
		||||
			if (xxx.HasNonPolyPartner(pawn, false) && !loverelation)
 | 
			
		||||
			{
 | 
			
		||||
				if (RJWHookupSettings.NymphosCanCheat && nymph && xxx.is_frustrated(pawn))
 | 
			
		||||
				{
 | 
			
		||||
					if (RJWSettings.DebugLogJoinInBed)
 | 
			
		||||
					{
 | 
			
		||||
						ModLog.Message(" find_partner(" + pawn_name + "): I'm a nympho and I'm so frustrated that I'm going to cheat");
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					if (!pawn.health.hediffSet.HasHediff(HediffDef.Named("AlcoholHigh"), false))
 | 
			
		||||
					{
 | 
			
		||||
						if (RJWSettings.DebugLogJoinInBed)
 | 
			
		||||
						{
 | 
			
		||||
							ModLog.Message(" find_partner(" + pawn_name + "): I interested in banging but that's cheating");
 | 
			
		||||
						}
 | 
			
		||||
						//Succubus has a small chance to seduce even if target is in relationship
 | 
			
		||||
						willingness *= 0.1f;
 | 
			
		||||
					}
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
						if (RJWSettings.DebugLogJoinInBed)
 | 
			
		||||
						{
 | 
			
		||||
							ModLog.Message(" find_partner(" + pawn_name + "): I want to bang and im too drunk to care if its cheating");
 | 
			
		||||
						}
 | 
			
		||||
						//No change
 | 
			
		||||
					}		
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return willingness;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public static float JoinChance(Pawn pawn ,Pawn target)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
			float chance = 0.1f;
 | 
			
		||||
 | 
			
		||||
			//Sex satisfaction, how good the target is at sex
 | 
			
		||||
			chance *= xxx.get_sex_satisfaction(target); 
 | 
			
		||||
			
 | 
			
		||||
			//Succubus mood
 | 
			
		||||
			if (pawn.needs != null && pawn.needs.mood != null)
 | 
			
		||||
            {
 | 
			
		||||
				chance *= pawn.needs.mood.CurLevelPercentage + 0.5f; 
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			//Size of genitals
 | 
			
		||||
			bool size_matters = true; //To be placed in modsettings
 | 
			
		||||
			if (size_matters)
 | 
			
		||||
            {
 | 
			
		||||
				//The larger the penis to greater the chance
 | 
			
		||||
				if (RelationsUtility.AttractedToGender(pawn, Gender.Male))
 | 
			
		||||
				{
 | 
			
		||||
					chance *= GetGenitalSize(target, true) + 0.5f;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				//The tighter the vagine the greater the chance, a size above 1 is considered as 1
 | 
			
		||||
				if (RelationsUtility.AttractedToGender(pawn, Gender.Female))
 | 
			
		||||
				{
 | 
			
		||||
					chance *= 1f - Mathf.Min(GetGenitalSize(target, false),1f) + 0.5f;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Sex ability from sexperience
 | 
			
		||||
			if (ModsConfig.IsActive("rjw.sexperience"))
 | 
			
		||||
            {
 | 
			
		||||
				chance *= RJWSexperience.PawnExtensions.GetSexStat(pawn);
 | 
			
		||||
            }
 | 
			
		||||
			return Mathf.Max(chance,0f);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		//Gets the size of the largest penis or the tightest vagina
 | 
			
		||||
		public static float GetGenitalSize(Pawn pawn, bool penis_else_vagina)
 | 
			
		||||
        {
 | 
			
		||||
			List<Hediff> genitals = rjw.PawnExtensions.GetGenitalsList(pawn);
 | 
			
		||||
			if(!genitals.NullOrEmpty())
 | 
			
		||||
            {
 | 
			
		||||
				if (penis_else_vagina)
 | 
			
		||||
				{
 | 
			
		||||
					List<Hediff> penises = genitals.Where(genital => Genital_Helper.is_penis(genital)).ToList();
 | 
			
		||||
					{
 | 
			
		||||
						if (!penises.NullOrEmpty())
 | 
			
		||||
						{
 | 
			
		||||
							return penises.Max(genital => genital.Severity);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
                {
 | 
			
		||||
					List<Hediff> vaginas = genitals.Where(genital => Genital_Helper.is_vagina(genital)).ToList();
 | 
			
		||||
					{
 | 
			
		||||
						if (!vaginas.NullOrEmpty())
 | 
			
		||||
						{
 | 
			
		||||
							return vaginas.Min(genital => genital.Severity);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return 0f;
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using Verse.AI.Group;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    //Based on LordToil_EscortPawn
 | 
			
		||||
    public class LordToil_Flirt : LordToil
 | 
			
		||||
    {
 | 
			
		||||
        public LordToil_Flirt(Pawn victim, float followRadius)
 | 
			
		||||
        {
 | 
			
		||||
            this.victim = victim;
 | 
			
		||||
            this.followRadius = followRadius;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public override void UpdateAllDuties()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < this.lord.ownedPawns.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                PawnDuty duty = new PawnDuty(GeneDefOf.rjw_genes_flirt, this.victim, this.followRadius);
 | 
			
		||||
                this.lord.ownedPawns[i].mindState.duty = duty;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Pawn victim;
 | 
			
		||||
        public float followRadius;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class LifeForceMentalBreakWorker : MentalBreakWorker
 | 
			
		||||
	{
 | 
			
		||||
		public override bool BreakCanOccur(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			if (pawn.Spawned && base.BreakCanOccur(pawn))
 | 
			
		||||
			{
 | 
			
		||||
				if (!GeneUtility.HasLifeForce(pawn))
 | 
			
		||||
                {
 | 
			
		||||
					return false;
 | 
			
		||||
                }
 | 
			
		||||
				Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
				if( gene.Resource.Value <= 0)
 | 
			
		||||
                {
 | 
			
		||||
					return true;
 | 
			
		||||
                }
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class LifeForceMentalState : MentalState
 | 
			
		||||
	{
 | 
			
		||||
		public override void MentalStateTick()
 | 
			
		||||
		{
 | 
			
		||||
			if (this.pawn.IsHashIntervalTick(150) && !GeneUtility.HasCriticalLifeForce(this.pawn))
 | 
			
		||||
			{
 | 
			
		||||
				Pawn_JobTracker jobs = this.pawn.jobs;
 | 
			
		||||
				if (!(((jobs != null) ? jobs.curDriver : null) is JobDriver_Sex))
 | 
			
		||||
				{
 | 
			
		||||
					base.RecoverFromState();
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			base.MentalStateTick();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class LifeForceMentalStateWorker : MentalStateWorker
 | 
			
		||||
	{
 | 
			
		||||
		public override bool StateCanOccur(Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			return base.StateCanOccur(pawn) && (xxx.is_human(pawn) && JobGiver_LifeForce_RandomRape.can_rape(pawn));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,203 +0,0 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using rjw;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// This Patch hooks after "SatisfyPersonal"(i.E. when the pawn finished fucking) and covers LifeForceGain. 
 | 
			
		||||
	/// If the pawn has LifeForce, all relevant Genes are checked and applied. 
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	[HarmonyPatch(typeof(SexUtility), nameof(SexUtility.SatisfyPersonal))]
 | 
			
		||||
	public static class Patch_SatisfyPersonal_LifeForceGain
 | 
			
		||||
	{
 | 
			
		||||
		public const float LIFEFORCE_GAINED_FROM_DRAINER_GENE = 0.25f;
 | 
			
		||||
 | 
			
		||||
		public static void Postfix(SexProps props)
 | 
			
		||||
		{
 | 
			
		||||
			// ShortCuts: Exit Early if Pawn or Partner are null (can happen with Animals or Masturbation)
 | 
			
		||||
			if (props.pawn == null || !props.hasPartner())
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			// Exit if pawn has fertilin themself, it won't give any if it has lifeforce themself.
 | 
			
		||||
			if (GeneUtility.HasLifeForce(props.pawn))
 | 
			
		||||
			{
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Summary//
 | 
			
		||||
			//We use the positions of the pawn (dom or sub) and based on that which interactions will transfer fertilin 
 | 
			
		||||
			//By checking isreceiver we know if the succubus is the dom or the sub and if the situation is reverse we also swap the function we use
 | 
			
		||||
			float absorb_factor = 0f;
 | 
			
		||||
			if (GeneUtility.HasLifeForce(props.partner))
 | 
			
		||||
			{
 | 
			
		||||
				Pawn PawnWithLifeForce = props.partner;
 | 
			
		||||
 | 
			
		||||
				if (!props.isRevese)
 | 
			
		||||
				{
 | 
			
		||||
					if (props.isReceiver)
 | 
			
		||||
					{
 | 
			
		||||
						// Scenario Dom Succubus, normal
 | 
			
		||||
						absorb_factor = BaseDom(props, PawnWithLifeForce);
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						// Scenario Sub Succubus, normal
 | 
			
		||||
						absorb_factor = BaseSub(props, PawnWithLifeForce);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					if (props.isReceiver)
 | 
			
		||||
					{
 | 
			
		||||
						// Scenario Dom Succubus, Reverse
 | 
			
		||||
						absorb_factor = BaseSub(props, PawnWithLifeForce);
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						// Scenario Sub Succubus, Reverse
 | 
			
		||||
						absorb_factor = BaseDom(props, PawnWithLifeForce);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// If we remove this check fertilin is always lost, but the succubus doesn't always gain any
 | 
			
		||||
				if (absorb_factor != 0f)
 | 
			
		||||
				{
 | 
			
		||||
					TransferFertilin(props, absorb_factor);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Handle Gene: Sexual_Drainer
 | 
			
		||||
				// to be drained, a pawn must not-be-drained-already and drainers cannot be drained either.
 | 
			
		||||
				if (GeneUtility.IsSexualDrainer(PawnWithLifeForce) 
 | 
			
		||||
					&& !props.pawn.health.hediffSet.HasHediff(HediffDefOf.rjw_genes_succubus_drained) 
 | 
			
		||||
					&& !GeneUtility.IsSexualDrainer(props.pawn))
 | 
			
		||||
				{
 | 
			
		||||
					if (GeneUtility.IsGenerousDonor(props.pawn) && RJW_Genes_Settings.rjw_genes_generous_donor_cheatmode)
 | 
			
		||||
					{
 | 
			
		||||
						// Cheatmode is on, do not drain but give life 
 | 
			
		||||
						GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(PawnWithLifeForce), LIFEFORCE_GAINED_FROM_DRAINER_GENE); 
 | 
			
		||||
						if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
							ModLog.Message($"{props.pawn.Name} was not (sexually) drained by {PawnWithLifeForce.Name}, because Cheatmode for Generous Donors is on");
 | 
			
		||||
					} else
 | 
			
		||||
                    {
 | 
			
		||||
						if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
							ModLog.Message($"{props.pawn.Name} has been (sexually) drained by {PawnWithLifeForce.Name}");
 | 
			
		||||
						props.pawn.health.AddHediff(HediffDefOf.rjw_genes_succubus_drained);
 | 
			
		||||
						GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(PawnWithLifeForce), LIFEFORCE_GAINED_FROM_DRAINER_GENE);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void TransferFertilin(SexProps props, float absorb_percentage = 1f)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn_GeneTracker genes = props.partner.genes;
 | 
			
		||||
			Gene_LifeForce gene = genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
 | 
			
		||||
			Hediff fertilin_lost = props.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.rjw_genes_fertilin_lost);
 | 
			
		||||
			//Around quarter get ejected everytime pawn cums
 | 
			
		||||
			float multiplier = Rand.Range(0.10f, 0.40f);
 | 
			
		||||
 | 
			
		||||
			if (GeneUtility.IsGenerousDonor(props.pawn) && RJW_Genes_Settings.rjw_genes_generous_donor_cheatmode)
 | 
			
		||||
			{
 | 
			
		||||
				// Do nothing, Cheatmode is on
 | 
			
		||||
				multiplier = 1;
 | 
			
		||||
			} 
 | 
			
		||||
			else 
 | 
			
		||||
			{ 
 | 
			
		||||
				//Create a new ferilin_lost hediff or increase it
 | 
			
		||||
				if (fertilin_lost == null)
 | 
			
		||||
				{
 | 
			
		||||
					Hediff new_fertilin_lost = HediffMaker.MakeHediff(HediffDefOf.rjw_genes_fertilin_lost, props.pawn);
 | 
			
		||||
					props.pawn.health.AddHediff(new_fertilin_lost);
 | 
			
		||||
					new_fertilin_lost.Severity = multiplier;
 | 
			
		||||
				} else
 | 
			
		||||
				{
 | 
			
		||||
					multiplier *= 1 - fertilin_lost.Severity;
 | 
			
		||||
					fertilin_lost.Severity += multiplier;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			multiplier *= absorb_percentage;
 | 
			
		||||
			//Currently taking the sum of all penises, maybe I should just consider one at random
 | 
			
		||||
			float valuechange = TotalFertilinAmount(props, multiplier);
 | 
			
		||||
 | 
			
		||||
			if (props.partner.IsAnimal())
 | 
			
		||||
            {
 | 
			
		||||
				if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
					ModLog.Message($"Fertilin-Source of {props.pawn.Name} was an Animal, Fertilin-Gain is being adjusted by {RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor}%");
 | 
			
		||||
				valuechange *= RJW_Genes_Settings.rjw_genes_fertilin_from_animals_factor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
			GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(props.partner), valuechange);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static float TotalFertilinAmount(SexProps props, float multiplier)
 | 
			
		||||
        {
 | 
			
		||||
			float total_fluid = CumUtility.GetTotalFluidAmount(props.pawn) / 100;
 | 
			
		||||
 | 
			
		||||
			//More in the tank means more to give
 | 
			
		||||
			if (props.pawn.Has(Quirk.Messy))
 | 
			
		||||
			{
 | 
			
		||||
				total_fluid *= 2;
 | 
			
		||||
			}
 | 
			
		||||
			if (props.pawn.RaceProps.Animal)
 | 
			
		||||
            {
 | 
			
		||||
				total_fluid *= 0.1f; //Should make this settable in settings
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
			return total_fluid;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Handles the Case that the Life-Force wielder initiated the Sex (They are "Dom"). 
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="props">The summary of the sex act, used for checking conditions.</param>
 | 
			
		||||
		/// <param name="PawnWithLifeForce">The pawn that might gain LifeForce through this method.</param>
 | 
			
		||||
		/// <returns>A factor between 0 and 1 how much of output-fertilin will be used for input-lifeforce</returns>
 | 
			
		||||
		public static float BaseDom(SexProps props, Pawn PawnWithLifeForce)
 | 
			
		||||
		{
 | 
			
		||||
			float absorb_factor = 0f;
 | 
			
		||||
			if (props.sexType == xxx.rjwSextype.Sixtynine && GeneUtility.IsCumEater(PawnWithLifeForce))
 | 
			
		||||
			{
 | 
			
		||||
				absorb_factor += 1f;
 | 
			
		||||
			}
 | 
			
		||||
			return absorb_factor;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Handles the Case that the Life-Force wielder got initiated into sex (They are "Sub").
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="props">The summary of the sex act, used for checking conditions.</param>
 | 
			
		||||
		/// <param name="PawnWithLifeForce">The pawn that might gain LifeForce through this method.</param>
 | 
			
		||||
		/// <returns>A factor between 0 and 1 how much of output-fertilin will be used for input-lifeforce</returns>
 | 
			
		||||
		public static float BaseSub(SexProps props, Pawn PawnWithLifeForce)
 | 
			
		||||
        {
 | 
			
		||||
			float absorb_factor = 0f;
 | 
			
		||||
			if ((props.sexType == xxx.rjwSextype.Oral || props.sexType == xxx.rjwSextype.Fellatio || props.sexType == xxx.rjwSextype.Sixtynine) 
 | 
			
		||||
				&& GeneUtility.IsCumEater(PawnWithLifeForce))
 | 
			
		||||
			{
 | 
			
		||||
				absorb_factor += 1f;
 | 
			
		||||
			}
 | 
			
		||||
			else if (props.sexType == xxx.rjwSextype.Vaginal && GeneUtility.HasGeneNullCheck(PawnWithLifeForce, GeneDefOf.rjw_genes_fertilin_absorber))
 | 
			
		||||
			{
 | 
			
		||||
				absorb_factor += 1f;
 | 
			
		||||
			}
 | 
			
		||||
			else if (props.sexType == xxx.rjwSextype.Anal && GeneUtility.HasGeneNullCheck(PawnWithLifeForce, GeneDefOf.rjw_genes_fertilin_absorber))
 | 
			
		||||
			{
 | 
			
		||||
				absorb_factor += 1f;
 | 
			
		||||
			}
 | 
			
		||||
			else if (props.sexType == xxx.rjwSextype.DoublePenetration && GeneUtility.HasGeneNullCheck(PawnWithLifeForce, GeneDefOf.rjw_genes_fertilin_absorber))
 | 
			
		||||
			{
 | 
			
		||||
				absorb_factor += 1f;
 | 
			
		||||
			}
 | 
			
		||||
			else if (props.sexType == xxx.rjwSextype.Scissoring || props.sexType == xxx.rjwSextype.Cunnilingus)
 | 
			
		||||
			{
 | 
			
		||||
				//with vaginal cum absorbtion 
 | 
			
		||||
				//absorb_factor += 1f;
 | 
			
		||||
			}
 | 
			
		||||
			return absorb_factor;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,62 +0,0 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// This patch enables cum-eater pawns to drain cumflations for more fertilin drain by passively having sex.
 | 
			
		||||
	/// It is hooked after RJWs Change-Psyfocus so that pawns that are having prolonged sex (e.g. by overdrive) can fully drain the cumflation over time.
 | 
			
		||||
	/// 
 | 
			
		||||
	/// It is conditionally loaded only when LicentiaLabs is enabled, as this is the necessary source for cumflation-hediffs. 
 | 
			
		||||
	/// The patched function is: [HarmonyPatch(typeof(JobDriver_Sex), nameof(JobDriver_Sex.ChangePsyfocus))]
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public static class Patch_SexTicks_ChangePsyfocus
 | 
			
		||||
	{
 | 
			
		||||
		public const float LIFEFORCE_GAIN_PER_TICK = 0.05f;
 | 
			
		||||
		public const float CUMFLATION_SEVERITY_LOSS_PER_TICK = 0.1f;
 | 
			
		||||
 | 
			
		||||
		//Using ChangePsyfocus as it is something that fires every 60 ticks
 | 
			
		||||
		public static void Postfix(ref JobDriver_Sex __instance, ref Pawn pawn, ref Thing target)
 | 
			
		||||
		{
 | 
			
		||||
			SexProps props = __instance.Sexprops;
 | 
			
		||||
			if (props != null && props.sexType == xxx.rjwSextype.Cunnilingus && props.partner != null && target != null)
 | 
			
		||||
            {
 | 
			
		||||
				Pawn pawn2 = target as Pawn;
 | 
			
		||||
				// Case 1: Pawn is "drinking" and has CumEater Gene
 | 
			
		||||
				if (props.isRevese && GeneUtility.IsCumEater(pawn))
 | 
			
		||||
                {
 | 
			
		||||
					if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
						ModLog.Message($"{pawn.Name} is draining {pawn2.Name}'s cumflation for additional fertilin (CumEater-Gene ChangePsyFocus-Trigger).");
 | 
			
		||||
					DrinkCumflation(pawn2, pawn);
 | 
			
		||||
				}
 | 
			
		||||
				// Case 2: Pawn2 is "drinking" and has CumEater Gene
 | 
			
		||||
				else if (GeneUtility.IsCumEater(pawn2))
 | 
			
		||||
				{
 | 
			
		||||
					if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
						ModLog.Message($"{pawn.Name} is draining {pawn2.Name}'s cumflation for additional fertilin (CumEater-Gene ChangePsyFocus-Trigger).");
 | 
			
		||||
					DrinkCumflation(pawn, pawn2);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void DrinkCumflation(Pawn source, Pawn consumer)
 | 
			
		||||
        {
 | 
			
		||||
			if (GeneUtility.HasLifeForce(consumer) && GeneUtility.IsCumEater(consumer)
 | 
			
		||||
				&& source.health.hediffSet.HasHediff(HediffDef.Named("Cumflation")))
 | 
			
		||||
			{
 | 
			
		||||
				Hediff cumflation = source.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Cumflation"));
 | 
			
		||||
				Gene_LifeForce gene_LifeForce = consumer.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
				cumflation.Severity = Math.Max(0f,cumflation.Severity - CUMFLATION_SEVERITY_LOSS_PER_TICK);
 | 
			
		||||
				gene_LifeForce.Resource.Value += LIFEFORCE_GAIN_PER_TICK;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,79 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This Patch is applied to add a absorption gene for fertilin if it has none, but it does have the fertilin gene
 | 
			
		||||
    /// First tries to get one from the parents else chooses one of them at random
 | 
			
		||||
    /// the genes are determined and "simply added". 
 | 
			
		||||
    /// 
 | 
			
		||||
    /// This fixes the potential problem that Pawns could inherit Fertilin, but no gene to gain Fertilin.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [HarmonyPatch(typeof(PregnancyUtility), "GetInheritedGeneSet", new Type[]
 | 
			
		||||
    {
 | 
			
		||||
        typeof(Pawn),
 | 
			
		||||
        typeof(Pawn)
 | 
			
		||||
    }
 | 
			
		||||
    )]
 | 
			
		||||
    public static class Patch_Vanilla_Inheritance_Fertilin
 | 
			
		||||
    {
 | 
			
		||||
        [HarmonyPostfix]
 | 
			
		||||
        public static void InheritedGenes(Pawn father, Pawn mother, ref GeneSet __result)
 | 
			
		||||
        {
 | 
			
		||||
            //Also make a setting for this
 | 
			
		||||
            if (__result.GenesListForReading.Contains(GeneDefOf.rjw_genes_lifeforce))
 | 
			
		||||
            {
 | 
			
		||||
                List<GeneDef> babies_genes = __result.GenesListForReading;
 | 
			
		||||
 | 
			
		||||
                //If there is no absorption gene get one from the parents, else a random one
 | 
			
		||||
                if(!Has_Fertilin_Source_Gene(babies_genes))
 | 
			
		||||
                {
 | 
			
		||||
                    if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
                        ModLog.Message($"Child of ({father.Name};{mother.Name}) has Genes with LifeForce-Resource but no Source-Gene, adding one of parents random if possible or any random otherwise.");
 | 
			
		||||
                    // Gather Parents Source-Genes
 | 
			
		||||
                    List<GeneDef> absorption_genes_parents = new List<GeneDef>();
 | 
			
		||||
                    foreach (GeneDef geneDef in FertilinSourceGenes)
 | 
			
		||||
                    {
 | 
			
		||||
                        if(mother.genes != null && mother.genes.HasGene(geneDef))
 | 
			
		||||
                            absorption_genes_parents.Add(geneDef);
 | 
			
		||||
 | 
			
		||||
                        if (father.genes != null && father.genes.HasGene(geneDef))
 | 
			
		||||
                            absorption_genes_parents.Add(geneDef);
 | 
			
		||||
                    }
 | 
			
		||||
                    // Parents had Genes - Pick a random one of them 
 | 
			
		||||
                    if (!absorption_genes_parents.NullOrEmpty())
 | 
			
		||||
                        __result.AddGene(absorption_genes_parents.RandomElement());
 | 
			
		||||
                    // Create a fully random one for your little Cumfueled missbreed
 | 
			
		||||
                    else
 | 
			
		||||
                        __result.AddGene(FertilinSourceGenes.RandomElement());
 | 
			
		||||
                }
 | 
			
		||||
            }       
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static List<GeneDef> FertilinSourceGenes = new List<GeneDef>() {
 | 
			
		||||
            GeneDefOf.rjw_genes_drainer, 
 | 
			
		||||
            GeneDefOf.rjw_genes_cum_eater, 
 | 
			
		||||
            GeneDefOf.rjw_genes_fertilin_absorber,
 | 
			
		||||
            GeneDefOf.rjw_genes_cockeater 
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static bool Has_Fertilin_Source_Gene(List<GeneDef> genes)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (GeneDef gene in genes)
 | 
			
		||||
            {
 | 
			
		||||
                if (FertilinSourceGenes.Contains(gene))
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class ThinkNode_ConditionalCannotInteract : ThinkNode_Conditional
 | 
			
		||||
    {
 | 
			
		||||
        protected override bool Satisfied(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            Pawn target = pawn.mindState.duty.focus.Pawn;
 | 
			
		||||
            if (target == null)
 | 
			
		||||
            {
 | 
			
		||||
                return true;    
 | 
			
		||||
            }
 | 
			
		||||
            return (target.jobs != null && target.jobs.curDriver.asleep) || !pawn.CanReach(target, PathEndMode.InteractionCell, Danger.Deadly);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class ThinkNode_ConditionalCritcalLifeForce : ThinkNode_Conditional
 | 
			
		||||
	{
 | 
			
		||||
		protected override bool Satisfied(Pawn p)
 | 
			
		||||
		{
 | 
			
		||||
			return GeneUtility.HasCriticalLifeForce(p);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	public class ThinkNode_ConditionalLowLifeForce : ThinkNode_Conditional
 | 
			
		||||
	{
 | 
			
		||||
		protected override bool Satisfied(Pawn p)
 | 
			
		||||
		{
 | 
			
		||||
			return GeneUtility.HasLowLifeForce(p);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,37 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class ThinkNode_NewFlirtTarget : ThinkNode
 | 
			
		||||
    {
 | 
			
		||||
        public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams)
 | 
			
		||||
        {
 | 
			
		||||
            List<Pawn> validTargets = ValidTargets(pawn, pawn.Map).ToList();
 | 
			
		||||
            Pawn new_target = validTargets.NullOrEmpty() ? null : validTargets.RandomElement();
 | 
			
		||||
            if (new_target != null)
 | 
			
		||||
            {
 | 
			
		||||
                pawn.mindState.duty.focus = new_target;
 | 
			
		||||
            }
 | 
			
		||||
            return ThinkResult.NoJob;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IEnumerable<Pawn> ValidTargets(Pawn pawn, Map map)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (Pawn pawn2 in map.mapPawns.FreeAdultColonistsSpawned)
 | 
			
		||||
            {
 | 
			
		||||
                if (pawn != null && pawn2 != null && pawn != pawn2 && !pawn2.jobs.curDriver.asleep && SexAppraiser.would_fuck(pawn, pawn2) > 0.1f)
 | 
			
		||||
                {
 | 
			
		||||
                    yield return pawn2;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            //IEnumerator<Pawn> enumerator = null;
 | 
			
		||||
            yield break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,68 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld.Planet;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class Alert_CriticalFertilin : Alert
 | 
			
		||||
    {
 | 
			
		||||
		private List<GlobalTargetInfo> Targets
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				this.CalculateTargets();
 | 
			
		||||
				return this.targets;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override string GetLabel()
 | 
			
		||||
		{
 | 
			
		||||
			if (this.Targets.Count == 1)
 | 
			
		||||
			{
 | 
			
		||||
				return "AlertLowFertilin".Translate() + ": " + this.targetLabels[0];
 | 
			
		||||
			}
 | 
			
		||||
			return "AlertLowFertilin".Translate();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void CalculateTargets()
 | 
			
		||||
		{
 | 
			
		||||
			this.targets.Clear();
 | 
			
		||||
			this.targetLabels.Clear();
 | 
			
		||||
			if (!ModsConfig.BiotechActive)
 | 
			
		||||
			{
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (Pawn pawn in PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive)
 | 
			
		||||
			{
 | 
			
		||||
				if (pawn.RaceProps.Humanlike && pawn.Faction == Faction.OfPlayer)
 | 
			
		||||
				{
 | 
			
		||||
					Pawn_GeneTracker genes = pawn.genes;
 | 
			
		||||
					Gene_LifeForce gene_Lifeforce = (genes != null) ? genes.GetFirstGeneOfType<Gene_LifeForce>() : null;
 | 
			
		||||
					if (gene_Lifeforce != null && gene_Lifeforce.Active && gene_Lifeforce.Value < gene_Lifeforce.MinLevelForAlert)
 | 
			
		||||
					{
 | 
			
		||||
						this.targets.Add(pawn);
 | 
			
		||||
						this.targetLabels.Add(pawn.NameShortColored.Resolve());
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override TaggedString GetExplanation()
 | 
			
		||||
		{
 | 
			
		||||
			return "AlertLowFertilinDesc".Translate() + ":\n" + this.targetLabels.ToLineList("  - ");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override AlertReport GetReport()
 | 
			
		||||
		{
 | 
			
		||||
			return AlertReport.CulpritsAre(this.Targets);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private List<GlobalTargetInfo> targets = new List<GlobalTargetInfo>();
 | 
			
		||||
 | 
			
		||||
		private List<string> targetLabels = new List<string>();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,83 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	//Copied from GeneGizmo_ResourceHemogen, with small modifications 
 | 
			
		||||
	public class GeneGizmo_ResourceLifeForce : GeneGizmo_Resource
 | 
			
		||||
    {
 | 
			
		||||
        public GeneGizmo_ResourceLifeForce(Gene_Resource gene, List<IGeneResourceDrain> drainGenes, Color barColor, Color barhighlightColor) : base(gene, drainGenes, barColor, barhighlightColor)
 | 
			
		||||
        {
 | 
			
		||||
            this.draggableBar = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
 | 
			
		||||
        {
 | 
			
		||||
            return base.GizmoOnGUI(topLeft, maxWidth, parms);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override string GetTooltip()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
			this.tmpDrainGenes.Clear();
 | 
			
		||||
			string text = string.Format("{0}: {1} / {2}\n", this.gene.ResourceLabel.CapitalizeFirst().Colorize(ColoredText.TipSectionTitleColor), this.gene.ValueForDisplay, this.gene.MaxForDisplay);
 | 
			
		||||
			if (this.gene.pawn.IsColonistPlayerControlled || this.gene.pawn.IsPrisonerOfColony)
 | 
			
		||||
			{
 | 
			
		||||
				if (this.gene.targetValue <= 0f)
 | 
			
		||||
				{
 | 
			
		||||
					text += "NeverSeekFertilin";
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					text = text + ("SeekFertilinBelow" + ": ") + this.gene.PostProcessValue(this.gene.targetValue);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (!this.drainGenes.NullOrEmpty<IGeneResourceDrain>())
 | 
			
		||||
			{
 | 
			
		||||
				float num = 0f;
 | 
			
		||||
				foreach (IGeneResourceDrain geneResourceDrain in this.drainGenes)
 | 
			
		||||
				{
 | 
			
		||||
					if (geneResourceDrain.CanOffset)
 | 
			
		||||
					{
 | 
			
		||||
						this.tmpDrainGenes.Add(new Pair<IGeneResourceDrain, float>(geneResourceDrain, geneResourceDrain.ResourceLossPerDay));
 | 
			
		||||
						num += geneResourceDrain.ResourceLossPerDay;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if (num != 0f)
 | 
			
		||||
				{
 | 
			
		||||
					string text2 = (num < 0f) ? "RegenerationRate".Translate() : "DrainRate".Translate();
 | 
			
		||||
					text = string.Concat(new string[]
 | 
			
		||||
					{
 | 
			
		||||
				text,
 | 
			
		||||
				"\n\n",
 | 
			
		||||
				text2,
 | 
			
		||||
				": ",
 | 
			
		||||
				"PerDay".Translate(Mathf.Abs(this.gene.PostProcessValue(num))).Resolve()
 | 
			
		||||
					});
 | 
			
		||||
					foreach (Pair<IGeneResourceDrain, float> pair in this.tmpDrainGenes)
 | 
			
		||||
					{
 | 
			
		||||
						text = string.Concat(new string[]
 | 
			
		||||
						{
 | 
			
		||||
					text,
 | 
			
		||||
					"\n  - ",
 | 
			
		||||
					pair.First.DisplayLabel.CapitalizeFirst(),
 | 
			
		||||
					": ",
 | 
			
		||||
					"PerDay".Translate(this.gene.PostProcessValue(-pair.Second).ToStringWithSign()).Resolve()
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (!this.gene.def.resourceDescription.NullOrEmpty())
 | 
			
		||||
			{
 | 
			
		||||
				text = text + "\n\n" + this.gene.def.resourceDescription.Formatted(this.gene.pawn.Named("PAWN")).Resolve();
 | 
			
		||||
			}
 | 
			
		||||
			return text;
 | 
			
		||||
		}
 | 
			
		||||
		private List<Pair<IGeneResourceDrain, float>> tmpDrainGenes = new List<Pair<IGeneResourceDrain, float>>();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +143,7 @@ namespace RJW_Genes
 | 
			
		|||
            copy.style = CopyStyleTracker(copy, toMultiply.style);
 | 
			
		||||
            copy.story = CopyStoryTracker(copy, toMultiply.story);
 | 
			
		||||
 | 
			
		||||
            copy.Draw();
 | 
			
		||||
 | 
			
		||||
            return copy;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,8 +36,7 @@ namespace RJW_Genes
 | 
			
		|||
            if (!RelationsUtility.PawnsKnowEachOther(pawn, other))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
            // If the pawn is not on Map (e.g. caravan), no mali 
 | 
			
		||||
            if (!HiveUtility.PawnIsOnHomeMap(pawn))
 | 
			
		||||
                return (ThoughtState)false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // Do nothing for pawns that also have pheromones
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,27 +15,7 @@ namespace RJW_Genes
 | 
			
		|||
            // Patch Licentia, if Licentia exists
 | 
			
		||||
            // Logic & Explanation taken from https://rimworldwiki.com/wiki/Modding_Tutorials/Compatibility_with_DLLs
 | 
			
		||||
            // Adjusted to use ModsConfig (which makes it work, the example above does not run out of the box)
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                ((Action)(() =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (ModsConfig.IsActive("LustLicentia.RJWLabs"))
 | 
			
		||||
                    {
 | 
			
		||||
                        // Gene: Cumflation Immunity [Prefix Patch]
 | 
			
		||||
                        harmony.Patch(AccessTools.Method(typeof(LicentiaLabs.CumflationHelper), nameof(LicentiaLabs.CumflationHelper.Cumflation)),
 | 
			
		||||
                            prefix: new HarmonyMethod(typeof(Patch_Cumflation), nameof(Patch_Cumflation.Prefix)));
 | 
			
		||||
                        // Gene: Generous Donor [Postfix Patch]
 | 
			
		||||
                        harmony.Patch(AccessTools.Method(typeof(LicentiaLabs.CumflationHelper), nameof(LicentiaLabs.CumflationHelper.TransferNutrition)),
 | 
			
		||||
                            postfix: new HarmonyMethod(typeof(Patch_TransferNutrition), nameof(Patch_TransferNutrition.Postfix)));
 | 
			
		||||
                        // Gene: CumEater [Postfix Patch]
 | 
			
		||||
                        harmony.Patch(AccessTools.Method(typeof(rjw.JobDriver_Sex), nameof(rjw.JobDriver_Sex.ChangePsyfocus)),
 | 
			
		||||
                            postfix: new HarmonyMethod(typeof(Patch_SexTicks_ChangePsyfocus), nameof(Patch_SexTicks_ChangePsyfocus.Postfix)));
 | 
			
		||||
                    }
 | 
			
		||||
                }))();
 | 
			
		||||
            }
 | 
			
		||||
            catch (TypeLoadException ex) {
 | 
			
		||||
                // To be expected for people without Licentia Labs
 | 
			
		||||
            }
 | 
			
		||||
           
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -12,10 +12,9 @@ namespace RJW_Genes
 | 
			
		|||
    public static class HediffDefOf
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly HediffDef rjw_genes_aphrodisiac_pheromone;
 | 
			
		||||
        public static readonly HediffDef rjw_genes_fertilin_lost;
 | 
			
		||||
        public static readonly HediffDef rjw_genes_succubus_drained;
 | 
			
		||||
        
 | 
			
		||||
        public static readonly HediffDef rjw_genes_orgasm_rush_hediff;
 | 
			
		||||
        public static readonly HediffDef rjw_genes_fertilin_craving;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static readonly HediffDef rjw_genes_evergrowth_sideeffect;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,52 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using rjw.Modules.Interactions;
 | 
			
		||||
using rjw.Modules.Interactions.Internals.Implementation;
 | 
			
		||||
using rjw.Modules.Interactions.Objects;
 | 
			
		||||
using rjw;
 | 
			
		||||
using rjw.Modules.Interactions.Enums;
 | 
			
		||||
 | 
			
		||||
//Modefied code based of RJW-AI code at https://gitgud.io/Ed86/rjw-ia/-/tree/master/
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	[StaticConstructorOnStartup]
 | 
			
		||||
	public class DomSuccubusTailCustomRequirementHandler : ICustomRequirementHandler
 | 
			
		||||
	{
 | 
			
		||||
		public string HandlerKey
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return "DomSuccubusTailCustomRequirementHandler";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
		static DomSuccubusTailCustomRequirementHandler()
 | 
			
		||||
		{
 | 
			
		||||
			Register();
 | 
			
		||||
		}
 | 
			
		||||
		public static void Register()
 | 
			
		||||
		{
 | 
			
		||||
			InteractionRequirementService.CustomRequirementHandlers.Add(new DomSuccubusTailCustomRequirementHandler());
 | 
			
		||||
			if (Prefs.DevMode)
 | 
			
		||||
			{
 | 
			
		||||
				Log.Message("DomSuccubusTailCustomRequirementHandler registered: ");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool FufillRequirements(InteractionWithExtension interaction, InteractionPawn dominant, InteractionPawn submissive)
 | 
			
		||||
		{
 | 
			
		||||
			if (GeneUtility.HasGeneNullCheck(dominant.Pawn, GeneDefOf.rjw_genes_succubus_tail))
 | 
			
		||||
            {
 | 
			
		||||
				return true;
 | 
			
		||||
            }
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		//public static readonly StringListDef filter = DefDatabase<StringListDef>.GetNamed("DomSuccubusTailFilter");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,74 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using rjw;
 | 
			
		||||
using rjw.Modules.Interactions.Contexts;
 | 
			
		||||
using rjw.Modules.Interactions.Enums;
 | 
			
		||||
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
 | 
			
		||||
using rjw.Modules.Shared;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes.Interactions
 | 
			
		||||
{
 | 
			
		||||
	//Summary//
 | 
			
		||||
	//Set custom preferences for pawn. Gets integrated into rjw by AddtoIPartPreferenceRule in First
 | 
			
		||||
	//Depending on the level of lifeforce increase the chance for using the mouth.
 | 
			
		||||
	public class GenesPartKindUsageRule : IPartPreferenceRule
 | 
			
		||||
    {
 | 
			
		||||
		public IEnumerable<Weighted<LewdablePartKind>> ModifiersForDominant(InteractionContext context)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn pawn = context.Internals.Dominant.Pawn;
 | 
			
		||||
			Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
			if (gene != null)
 | 
			
		||||
			{
 | 
			
		||||
				float weight = 2f;
 | 
			
		||||
				if (gene.Value < gene.MinLevelForAlert)
 | 
			
		||||
				{
 | 
			
		||||
					weight *= 10;
 | 
			
		||||
				}
 | 
			
		||||
				else if (gene.Value < gene.targetValue)
 | 
			
		||||
				{
 | 
			
		||||
					weight *= 2.5f;
 | 
			
		||||
				}
 | 
			
		||||
				if (pawn.genes.HasGene(GeneDefOf.rjw_genes_cum_eater))
 | 
			
		||||
				{
 | 
			
		||||
					yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Mouth);
 | 
			
		||||
					yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Beak);
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if (pawn.genes.HasGene(GeneDefOf.rjw_genes_fertilin_absorber))
 | 
			
		||||
				{
 | 
			
		||||
					yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Vagina);
 | 
			
		||||
					yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Anus);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IEnumerable<Weighted<LewdablePartKind>> ModifiersForSubmissive(InteractionContext context)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn pawn = context.Internals.Dominant.Pawn;
 | 
			
		||||
			Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
 | 
			
		||||
			if (gene != null)
 | 
			
		||||
			{
 | 
			
		||||
				float weight = 2f;
 | 
			
		||||
				if (gene.Value < gene.MinLevelForAlert)
 | 
			
		||||
				{
 | 
			
		||||
					weight *= 10;
 | 
			
		||||
				}
 | 
			
		||||
				else if (gene.Value < gene.targetValue)
 | 
			
		||||
				{
 | 
			
		||||
					weight *= 2.5f;
 | 
			
		||||
				}
 | 
			
		||||
				yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Mouth);
 | 
			
		||||
				yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Beak);
 | 
			
		||||
 | 
			
		||||
				if (pawn.genes.HasGene(GeneDefOf.rjw_genes_fertilin_absorber))
 | 
			
		||||
				{
 | 
			
		||||
					yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Vagina);
 | 
			
		||||
					yield return new Weighted<LewdablePartKind>(weight, LewdablePartKind.Anus);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			yield break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,44 +0,0 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
using rjw.Modules.Interactions;
 | 
			
		||||
using rjw.Modules.Interactions.Internals.Implementation;
 | 
			
		||||
using rjw.Modules.Interactions.Objects;
 | 
			
		||||
 | 
			
		||||
//Modified code based of RJW-AI code at https://gitgud.io/Ed86/rjw-ia/-/tree/master/
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
	[StaticConstructorOnStartup]
 | 
			
		||||
	public class SubSuccubusTailCustomRequirementHandler : ICustomRequirementHandler
 | 
			
		||||
	{
 | 
			
		||||
		public string HandlerKey
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return "SubSuccubusTailCustomRequirementHandler";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		static SubSuccubusTailCustomRequirementHandler()
 | 
			
		||||
		{
 | 
			
		||||
			Register();
 | 
			
		||||
		}
 | 
			
		||||
		public static void Register()
 | 
			
		||||
		{
 | 
			
		||||
			InteractionRequirementService.CustomRequirementHandlers.Add(new SubSuccubusTailCustomRequirementHandler());
 | 
			
		||||
			if (Prefs.DevMode)
 | 
			
		||||
			{
 | 
			
		||||
				Log.Message("SubSuccubusTailCustomRequirementHandler registered: ");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool FufillRequirements(InteractionWithExtension interaction, InteractionPawn dominant, InteractionPawn submissive)
 | 
			
		||||
		{
 | 
			
		||||
			if (GeneUtility.HasGeneNullCheck(submissive.Pawn, GeneDefOf.rjw_genes_succubus_tail))
 | 
			
		||||
            {
 | 
			
		||||
				return true;
 | 
			
		||||
            }
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		//public static readonly StringListDef filter = DefDatabase<StringListDef>.GetNamed("SubSuccubusTailFilter");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    [DefOf]
 | 
			
		||||
    public static class JobDefOf
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly JobDef rjw_genes_lifeforce_randomrape;
 | 
			
		||||
        public static readonly JobDef rjw_genes_lifeforce_seduced;
 | 
			
		||||
        public static readonly JobDef sex_on_spot;
 | 
			
		||||
        public static readonly JobDef sex_on_spot_reciever;
 | 
			
		||||
        public static readonly JobDef rjw_genes_flirt;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,16 +11,7 @@ namespace RJW_Genes
 | 
			
		|||
        static RJW_Genes()
 | 
			
		||||
        {
 | 
			
		||||
            ModLog.Message("RJW-Genes loaded");
 | 
			
		||||
            if (RJW_Genes_Settings.rjw_genes_detailed_debug)
 | 
			
		||||
            {
 | 
			
		||||
                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))} + Default) ");
 | 
			
		||||
                IEnumerable<HiveOffspringChanceDef> offspringChanceDefs = DefDatabase<HiveOffspringChanceDef>.AllDefs;
 | 
			
		||||
                IEnumerable<HiveOffspringChanceDef> 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))})");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,9 @@
 | 
			
		|||
    <None Include="..\Common\Defs\Genes\GeneCategories.xml" />
 | 
			
		||||
    <None Include="..\Common\Defs\Genes\GeneDefs_ExtraGenitaliaEndogenes.xml" />
 | 
			
		||||
    <None Include="..\Common\Defs\Genes\GeneDefs_GenitaliaTypeEndogenes.xml" />
 | 
			
		||||
    <None Include="..\Common\Languages\**" />
 | 
			
		||||
    <None Include="..\Common\Languages\English\Keyed\Dialog_StatsReport.xml" />
 | 
			
		||||
    <None Include="..\Common\Languages\English\Keyed\Hive.xml" />
 | 
			
		||||
    <None Include="..\Common\Languages\English\Keyed\Lifeforce.xml" />
 | 
			
		||||
    <None Include="..\Common\Patches\**" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
| 
						 | 
				
			
			@ -47,24 +49,17 @@
 | 
			
		|||
    <Compile Include="GeneDefOf.cs" />
 | 
			
		||||
    <Compile Include="Genes\Breeding\Gene_MechBreeder.cs" />
 | 
			
		||||
    <Compile Include="Genes\Breeding\PatchMechBirth.cs" />
 | 
			
		||||
    <Compile Include="Genes\ExtraGenitalia\Gene_Femboy.cs" />
 | 
			
		||||
    <Compile Include="Genes\ExtraGenitalia\Gene_UdderBreasts.cs" />
 | 
			
		||||
    <Compile Include="Genes\Gender\Defs\GenderFluidExtension.cs" />
 | 
			
		||||
    <Compile Include="Genes\Gender\Gene_GenderFluid.cs" />
 | 
			
		||||
    <Compile Include="Genes\GenitaliaSize\Gene_EvergrowingGenitalia.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Defs\HiveOffspringChanceDef.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Genes\Gene_FerventOvipositor.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Genes\Gene_InsectIncubator.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Helpers\HiveBirthLogic.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Patches\Patch_InsectEggs_BirthBaby_SetHiveGenes.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Patches\Patch_InsectBreeder_EggFertilization.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Patches\Patch_InsectIncubator_PregnancyHelper.cs" />
 | 
			
		||||
    <Compile Include="Genes\Cum\CumUtility.cs" />
 | 
			
		||||
    <Compile Include="Genes\Cum\Gene_VeryMuchCum.cs" />
 | 
			
		||||
    <Compile Include="Genes\Cum\Gene_MuchCum.cs" />
 | 
			
		||||
    <Compile Include="Genes\Cum\Gene_NoCum.cs" />
 | 
			
		||||
    <Compile Include="Genes\Cum\Patch_TransferNutrition.cs" />
 | 
			
		||||
    <Compile Include="Genes\Damage\Gene_Unbreakable.cs" />
 | 
			
		||||
    <Compile Include="Genes\Damage\Gene_Elasticity.cs" />
 | 
			
		||||
    <Compile Include="Genes\Cum\Patch_Cumflation.cs" />
 | 
			
		||||
    <Compile Include="Genes\ExtraGenitalia\Gene_ExtraBreasts.cs" />
 | 
			
		||||
    <Compile Include="Genes\ExtraGenitalia\Gene_ExtraAnus.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -99,54 +94,6 @@
 | 
			
		|||
    <Compile Include="Genes\Genitalia\Gene_DemonicGenitalia.cs" />
 | 
			
		||||
    <Compile Include="Genes\Genitalia\Gene_EquineGenitalia.cs" />
 | 
			
		||||
    <Compile Include="Genes\Genitalia\GenitaliaChanger.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Abilities\CompAbilityEffect_SpawnSpelopede.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Abilities\CompAbilityEffect_CocoonWeaver.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Abilities\CompProperties_AbilitySpawnSpelopede.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Abilities\CompProperties_AbilityCocoonWeaver.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Genes\ConditionalStatAffecters\ConditionalStatAffecter_MultipleQueens.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Genes\ConditionalStatAffecters\ConditionalStatAffecter_QueenCloseBy.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Genes\ConditionalStatAffecters\ConditionalStatAffecter_QueenAbsent.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Helpers\HiveUtility.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Defs\QueenWorkerMappingDef.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Patches\Patch_BirthOutcome_SetHiveGenes.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\Thoughtworker_QueenAbsent_Mood.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\Thoughtworker_MultipleQueens_Mood.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\Thoughtworker_QueenPresent_Mood.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\ThoughtWorker_WorkerDespised_Social.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\Thoughtworker_RivalQueen_Mood.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\ThoughtWorker_QueenPresent_Social.cs" />
 | 
			
		||||
    <Compile Include="Genes\Hive\Thoughts\ThoughtWorker_RivalQueen_Social.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\AbilityUtility.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Defs\LifeForceEmpathExtension.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Genes\Gene_LifeForce_Empath.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\UI\Alert_LowFertilin.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompAbilityEffect_CasterIsNaked.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompProperties_CasterIsNaked.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompAbilityEffect_Seduce.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompAbilityEffect_LifeForceCost.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompAbilityEffect_CockEater.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompProperties_Seduce.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompProperties_AbilityCockEater.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Genes\Gene_LifeForceDrain.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\HediffCompProperties_SeverityFromFertilin.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\HediffComp_SeverityFromFertilin.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Events\SuccubusVisit\IncidentWorker_SuccubusDreamVisit.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\IngestionOutcomeDoer_LifeForceOffset.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobGivers\JobGiver_TryQuickieWith.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobDrivers\JobDriver_Flirt.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobDrivers\JobDriver_SexOnSpotReceiver.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobDrivers\JobDriver_SexOnSpot.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobDrivers\JobDriver_Seduced.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobGivers\JobGiver_Flirt.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Events\SuccubusVisit\LordJob_SuccubusVisit.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\LordToil_Flirt.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Patches\Patch_SexTicks_ChangePsyfocus.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Patches\Patch_Vanilla_Inheritance_Fertilin.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\ThinkNodes\ThinkNode_ConditionalCannotInteract.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\ThinkNodes\ThinkNode_ConditionalLowLifeForce.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\ThinkNodes\ThinkNode_ConditionalCritcalLifeForce.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobGivers\JobGiver_GetLifeForce.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\ThinkNodes\ThinkNode_NewFlirtTarget.cs" />
 | 
			
		||||
    <Compile Include="Genes\Patch_AddNotifyOnGeneration.cs" />
 | 
			
		||||
    <Compile Include="Genes\Special\Defs\AgeTransferExtension.cs" />
 | 
			
		||||
    <Compile Include="Genes\Special\Defs\HormonalSalivaExtension.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -155,30 +102,15 @@
 | 
			
		|||
    <Compile Include="Genes\Special\Patches\Patch_OrgasmMytosis.cs" />
 | 
			
		||||
    <Compile Include="Genes\Special\Thoughts\ThoughtWorker_Aphrodisiac_Pheromones_Social.cs" />
 | 
			
		||||
    <Compile Include="Interactions\SuccubusTailjob\CompAbility_SexInteractionRequirements.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompAbilityEffect_PussyHeal.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompProperties_AbilityLifeForceCost.cs" />
 | 
			
		||||
    <Compile Include="Interactions\SuccubusTailjob\CompProperties_SexInteractionRequirements.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Abilities\CompProperties_AbilityPussyHeal.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\UI\GeneGizmo_ResourceLifeForce.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobDrivers\JobDriver_CastAbilityAfterSex.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\MentalStates\LifeForceMentalState.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\MentalStates\LifeForceMentalStateWorker.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\JobGivers\JobGiver_LifeForce_RandomRape.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\MentalStates\LifeForceMentalBreakWorker.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Genes\Gene_LifeForce.cs" />
 | 
			
		||||
    <Compile Include="Genes\RJW_Gene.cs" />
 | 
			
		||||
    <Compile Include="Genes\Genitalia\GenitaliaUtility.cs" />
 | 
			
		||||
    <Compile Include="Genes\Special\Genes\Gene_Aphrodisiac_Pheromones.cs" />
 | 
			
		||||
    <Compile Include="Genes\Life_Force\Patches\Patch_SatisfyPersonal_LifeForceGain.cs" />
 | 
			
		||||
    <Compile Include="Genes\Special\Patches\Patch_OrgasmRush.cs" />
 | 
			
		||||
    <Compile Include="Genes\Special\Patches\Patch_Youth_Fountain.cs" />
 | 
			
		||||
    <Compile Include="HarmonyInit.cs" />
 | 
			
		||||
    <Compile Include="HediffDefOf.cs" />
 | 
			
		||||
    <Compile Include="Interactions\SuccubusTailjob\CustomSexInteraction_Helper.cs" />
 | 
			
		||||
    <Compile Include="Interactions\SuccubusTailjob\GenesPartKindUsageRule.cs" />
 | 
			
		||||
    <Compile Include="Interactions\SuccubusTailjob\SubSuccubusTailCustomRequirementHandler.cs" />
 | 
			
		||||
    <Compile Include="Interactions\SuccubusTailjob\DomSuccubusTailCustomRequirementHandler.cs" />
 | 
			
		||||
    <Compile Include="JobDefOf.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
    <Compile Include="RJW_Genes.cs" />
 | 
			
		||||
    <Compile Include="Settings\RJW_Genes_Settings.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -199,18 +131,13 @@
 | 
			
		|||
      <HintPath>..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
 | 
			
		||||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="LicentiaLabs, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
 | 
			
		||||
      <SpecificVersion>False</SpecificVersion>
 | 
			
		||||
      <HintPath>..\..\licentia-labs\Assemblies\LicentiaLabs.dll</HintPath>
 | 
			
		||||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="RJW, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
 | 
			
		||||
      <SpecificVersion>False</SpecificVersion>
 | 
			
		||||
      <HintPath>..\..\rjw\1.4\Assemblies\RJW.dll</HintPath>
 | 
			
		||||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="RJWSexperience">
 | 
			
		||||
      <HintPath>..\..\RJW-Sexperience-1.1.4.0\1.4\Assemblies\RJWSexperience.dll</HintPath>
 | 
			
		||||
      <HintPath>..\..\rjw-sexperience\1.5\Assemblies\RJWSexperience.dll</HintPath>
 | 
			
		||||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,12 +10,11 @@ namespace RJW_Genes
 | 
			
		|||
	[DefOf]
 | 
			
		||||
	public static class ThoughtDefOf
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly ThoughtDef rjw_genes_cock_eaten;
 | 
			
		||||
        public static readonly ThoughtDef rjw_genes_seduced;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static readonly ThoughtDef rjw_genes_pheromone_carrier_nearby;
 | 
			
		||||
 | 
			
		||||
        //Others with same names but other defs than in genedefof
 | 
			
		||||
        public static readonly InteractionDef rjw_genes_flirt;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue