mirror of
				https://github.com/vegapnk/RJW-Genes.git
				synced 2024-08-15 00:23:31 +00:00 
			
		
		
		
	Added a Gene for Gender Fluid Pawns
This commit is contained in:
		
							parent
							
								
									ae3c4471cf
								
							
						
					
					
						commit
						97c153f468
					
				
					 7 changed files with 302 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -1,8 +1,9 @@
 | 
			
		|||
# 1.2.2
 | 
			
		||||
# 1.3.0
 | 
			
		||||
 | 
			
		||||
**Changes:**
 | 
			
		||||
 | 
			
		||||
- New Gene for Evergrowing Cocks. Be careful. 
 | 
			
		||||
- New Gene for Genderfluid Pawns - daily chance to change sex. Futas just change "display" and keep genitalia, other pawns switch genitalia.
 | 
			
		||||
 | 
			
		||||
**Fixes:**
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +11,11 @@
 | 
			
		|||
- Copy of Infis patch for eating cum from sexperience, #41 and #48
 | 
			
		||||
- Updated some Icons to have better backgrounds (thanks @WasmachenDennSachenSo #53)
 | 
			
		||||
 | 
			
		||||
*Notes*: 
 | 
			
		||||
The pawns that are gender fluid can get pregnant. 
 | 
			
		||||
However, with RJW 5.3.7 these pregnancies disappear. 
 | 
			
		||||
This is a change needed upstream, but I will have a look. 
 | 
			
		||||
 | 
			
		||||
# 1.2.1 
 | 
			
		||||
 | 
			
		||||
**Fixes**: 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,4 +46,33 @@
 | 
			
		|||
        </modExtensions>
 | 
			
		||||
    </GeneDef>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    <GeneDef>
 | 
			
		||||
        <defName>rjw_genes_gender_fluid</defName>
 | 
			
		||||
        <displayCategory>rjw_genes_gender</displayCategory>
 | 
			
		||||
        <label>Gender Fluid</label>
 | 
			
		||||
        <description>Everyday carriers of this gene might change their biological sex.</description>
 | 
			
		||||
        <biostatCpx>0</biostatCpx>
 | 
			
		||||
        <iconPath>Genes/Icons/Futa</iconPath>
 | 
			
		||||
        <geneClass>RJW_Genes.Gene_GenderFluid</geneClass>
 | 
			
		||||
        <displayOrderInCategory>2</displayOrderInCategory>
 | 
			
		||||
        
 | 
			
		||||
        <exclusionTags>
 | 
			
		||||
          <li>AG_Gender</li>
 | 
			
		||||
          <li>Gender</li>          
 | 
			
		||||
        </exclusionTags>
 | 
			
		||||
 | 
			
		||||
        <modExtensions>
 | 
			
		||||
          <li MayRequire="OskarPotocki.VanillaFactionsExpanded.Core" Class="VanillaGenesExpanded.GeneExtension">
 | 
			
		||||
            <backgroundPathEndogenes>Genes/Icons/RJW_Genes_Endogene_Background</backgroundPathEndogenes>
 | 
			
		||||
            <backgroundPathXenogenes>Genes/Icons/RJW_Genes_Xenogene_Background</backgroundPathXenogenes>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li Class="RJW_Genes.GenderFluidExtension">
 | 
			
		||||
                <!-- 120k = 2 days -->
 | 
			
		||||
                <changeInterval>1000</changeInterval>
 | 
			
		||||
                <changeChance>1</changeChance>
 | 
			
		||||
          </li>
 | 
			
		||||
        </modExtensions>
 | 
			
		||||
    </GeneDef>
 | 
			
		||||
 | 
			
		||||
</Defs>
 | 
			
		||||
| 
						 | 
				
			
			@ -32,9 +32,10 @@ namespace RJW_Genes
 | 
			
		|||
		public static readonly GeneDef rjw_genes_extra_anus;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_no_anus;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_futa;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_featureless_chest;
 | 
			
		||||
 | 
			
		||||
		// Genitalia Sizes
 | 
			
		||||
		public static readonly GeneDef rjw_genes_big_male_genitalia;
 | 
			
		||||
        // Genitalia Sizes
 | 
			
		||||
        public static readonly GeneDef rjw_genes_big_male_genitalia;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_small_male_genitalia;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_loose_female_genitalia;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_tight_female_genitalia;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +47,7 @@ namespace RJW_Genes
 | 
			
		|||
		// Gender 
 | 
			
		||||
		public static readonly GeneDef rjw_genes_female_only;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_male_only;
 | 
			
		||||
		public static readonly GeneDef rjw_genes_gender_fluid;
 | 
			
		||||
 | 
			
		||||
		// Breeding
 | 
			
		||||
		public static readonly GeneDef rjw_genes_mechbreeder;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								Source/Genes/Gender/Defs/GenderFluidExtension.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Source/Genes/Gender/Defs/GenderFluidExtension.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
    public class GenderFluidExtension : DefModExtension
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Number of ticks until the change can be triggered.
 | 
			
		||||
        /// Just being "triggered" does not mean changing, see the changeChance below. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int changeInterval;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// How high is the chance to change gender?
 | 
			
		||||
        /// Set to 1 for "always", set to 0 for "never". 
 | 
			
		||||
        /// Everything else is a bit statistics, but e.g. when set to .5 the chances grow per day from [50%, 75%, 82.25%, ...]
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public float changeChance;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +31,8 @@ namespace RJW_Genes
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Adjusts the Body Type to match the given target gender 
 | 
			
		||||
        /// Adjusts the Body Type to match the given target gender.
 | 
			
		||||
        /// This is only for "drawing" attributes of the pawn, the genitalia are untouched at this point. 
 | 
			
		||||
        /// (for male and female only, baby,child and hulks don't change)
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn"></param>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										235
									
								
								Source/Genes/Gender/Gene_GenderFluid.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								Source/Genes/Gender/Gene_GenderFluid.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,235 @@
 | 
			
		|||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace RJW_Genes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Once per day (or slightly different per configuration) checks if the pawn changes gender. 
 | 
			
		||||
     * At the triggered tick, there is a random chance to change gender. 
 | 
			
		||||
     * This will swap genitalia, appearance and breasts. 
 | 
			
		||||
     * 
 | 
			
		||||
     * For some situations, the pawn better not change genitalia, e.g. while having vaginal sex. This would throw errors.
 | 
			
		||||
     * For these cases a check is implemented, and if there was a block the change happens a bit later when "unblocked". 
 | 
			
		||||
     * 
 | 
			
		||||
     * TODO: Keep pregnancies. 
 | 
			
		||||
     * The pregnancies remove their things on Tick at the end, which kills it for male pawns.
 | 
			
		||||
     * This seems to be an upstream RJW thing, but needs a bit of investigation.
 | 
			
		||||
     */
 | 
			
		||||
    public class Gene_GenderFluid : RJW_Gene
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        //public const int CHANGE_INTERVAL_FALLBACK = 1000; // Test value for Quick Trials
 | 
			
		||||
        const int CHANGE_INTERVAL_FALLBACK = 60000; // 60k == 1 day
 | 
			
		||||
        const float SWITCH_CHANCE_FALLBACK = 0.25f;
 | 
			
		||||
 | 
			
		||||
        int change_interval;
 | 
			
		||||
        float switch_chance;
 | 
			
		||||
 | 
			
		||||
        List<Hediff> storedBreasts = new List<Hediff>();
 | 
			
		||||
 | 
			
		||||
        private bool sexChangeWasBlocked = false;
 | 
			
		||||
 | 
			
		||||
        public Gene_GenderFluid() : base() {
 | 
			
		||||
            GenderFluidExtension genderFluidExt = GeneDefOf.rjw_genes_gender_fluid.GetModExtension<GenderFluidExtension>();
 | 
			
		||||
            change_interval = genderFluidExt?.changeInterval ?? CHANGE_INTERVAL_FALLBACK;
 | 
			
		||||
            switch_chance = genderFluidExt?.changeChance ?? SWITCH_CHANCE_FALLBACK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Tick()
 | 
			
		||||
        {
 | 
			
		||||
            base.Tick();
 | 
			
		||||
 | 
			
		||||
            // Case 1: We had a blocked SexChange, now Pawn is free, apply sexchange a bit delayed.
 | 
			
		||||
            if (pawn.IsHashIntervalTick(1500) && sexChangeWasBlocked && !SexChangeBlocked(pawn)){
 | 
			
		||||
                ChangeSex();
 | 
			
		||||
                sexChangeWasBlocked = false;
 | 
			
		||||
            }
 | 
			
		||||
            // Case 2: Check every interval if the Chance triggers
 | 
			
		||||
            else if (pawn.IsHashIntervalTick(change_interval) && (new Random()).NextDouble() < switch_chance)
 | 
			
		||||
            {
 | 
			
		||||
                
 | 
			
		||||
                // Case 2.A) SexChange was blocked, postpone it
 | 
			
		||||
                if (SexChangeBlocked(pawn))
 | 
			
		||||
                {
 | 
			
		||||
                    sexChangeWasBlocked |= true;
 | 
			
		||||
                    return;
 | 
			
		||||
                } 
 | 
			
		||||
                // Case 2.B) Nothing blocking, change the sex.
 | 
			
		||||
                else { ChangeSex();}
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ChangeSex()
 | 
			
		||||
        {
 | 
			
		||||
            if (rjw.Genital_Helper.is_futa(pawn))
 | 
			
		||||
            {
 | 
			
		||||
                // Handle Futa Pawns - Keep Genitalia as is, just change RW Gender
 | 
			
		||||
                pawn.gender = pawn.gender == Gender.Male? Gender.Female: Gender.Male;
 | 
			
		||||
            }
 | 
			
		||||
            // Handle Non-Futas - Change Genitalia and Store breasts. 
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (pawn.gender == Gender.Female)
 | 
			
		||||
                {
 | 
			
		||||
                    if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"genderfluid pawn {pawn} is changing from female to male");
 | 
			
		||||
                    SwitchToMale();
 | 
			
		||||
                }
 | 
			
		||||
                else if (pawn.gender == Gender.Male)
 | 
			
		||||
                {
 | 
			
		||||
                    if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"genderfluid pawn {pawn} is changing from male to female");
 | 
			
		||||
                    SwitchToFemale();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            GenderUtility.RemoveAllSexChangeThoughts(pawn);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SwitchToFemale()
 | 
			
		||||
        {
 | 
			
		||||
            // Change Drawing 
 | 
			
		||||
            GenderUtility.AdjustBodyToTargetGender(pawn, Verse.Gender.Female);
 | 
			
		||||
            // Change Gender 
 | 
			
		||||
            pawn.gender = Verse.Gender.Female;
 | 
			
		||||
 | 
			
		||||
            // Switch Penisses to Vaginas
 | 
			
		||||
            var genitalsToRemove = pawn.GetGenitalsList().FindAll(g => Genital_Helper.is_penis(g) || Genital_Helper.is_vagina(g));
 | 
			
		||||
            foreach (var genital  in genitalsToRemove)
 | 
			
		||||
            {
 | 
			
		||||
                var genitaliaHediffDef = GenitaliaUtility.GetVaginaForGene(GenitaliaUtility.GetGenitaliaTypeGeneForPawn(pawn));
 | 
			
		||||
                float size = genital.Severity;
 | 
			
		||||
                pawn.health.RemoveHediff(genital);
 | 
			
		||||
 | 
			
		||||
                var newVagina = HediffMaker.MakeHediff(genitaliaHediffDef, pawn, Genital_Helper.get_genitalsBPR(pawn));
 | 
			
		||||
                pawn.health.AddHediff(newVagina);
 | 
			
		||||
                newVagina.Severity = size;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SwitchBreasts();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SwitchToMale()
 | 
			
		||||
        {
 | 
			
		||||
            // Change Drawing 
 | 
			
		||||
            GenderUtility.AdjustBodyToTargetGender(pawn, Verse.Gender.Male);
 | 
			
		||||
            // Change Gender 
 | 
			
		||||
            pawn.gender = Verse.Gender.Male;
 | 
			
		||||
 | 
			
		||||
            // Switch Vaginas to Penisses
 | 
			
		||||
            var genitalsToRemove = pawn.GetGenitalsList().FindAll(g => Genital_Helper.is_penis(g) || Genital_Helper.is_vagina(g));
 | 
			
		||||
            foreach (var genital in genitalsToRemove)
 | 
			
		||||
            {
 | 
			
		||||
                var genitaliaHediffDef = GenitaliaUtility.GetPenisForGene(GenitaliaUtility.GetGenitaliaTypeGeneForPawn(pawn));
 | 
			
		||||
                float size = genital.Severity;
 | 
			
		||||
                pawn.health.RemoveHediff(genital);
 | 
			
		||||
 | 
			
		||||
                var newPenis = HediffMaker.MakeHediff(genitaliaHediffDef, pawn, Genital_Helper.get_genitalsBPR(pawn));
 | 
			
		||||
                pawn.health.AddHediff(newPenis);
 | 
			
		||||
                newPenis.Severity = size;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SwitchBreasts();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private void SwitchBreasts()
 | 
			
		||||
        {
 | 
			
		||||
            List<Hediff> current_breasts  = pawn.GetBreastList();
 | 
			
		||||
 | 
			
		||||
            // Stored_Breasts can be empty when the pawn first ever switches gender!
 | 
			
		||||
            if (storedBreasts.NullOrEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var breasts in current_breasts)
 | 
			
		||||
                {
 | 
			
		||||
                    // Is Male, and does not have the "no breast gene"
 | 
			
		||||
                    if (pawn.gender == Gender.Male && !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_no_breasts))
 | 
			
		||||
                    {
 | 
			
		||||
                        storedBreasts.Add(CreateNewBreasts());
 | 
			
		||||
                    } 
 | 
			
		||||
                    else if (pawn.gender == Gender.Female && !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_featureless_chest) )
 | 
			
		||||
                    {
 | 
			
		||||
                        storedBreasts.Add(CreateNewBreasts());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            foreach (var breast in current_breasts)
 | 
			
		||||
            {
 | 
			
		||||
                pawn.health.RemoveHediff(breast);
 | 
			
		||||
            }
 | 
			
		||||
            foreach (var breast in storedBreasts)
 | 
			
		||||
            {
 | 
			
		||||
                pawn.health.AddHediff(breast);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            storedBreasts.Clear();
 | 
			
		||||
            storedBreasts.AddRange(current_breasts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        internal Hediff CreateNewBreasts()
 | 
			
		||||
        {
 | 
			
		||||
            var correctGene = GenitaliaUtility.GetGenitaliaTypeGeneForPawn(pawn);
 | 
			
		||||
            var breastDef = GenitaliaUtility.GetBreastsForGene(correctGene);
 | 
			
		||||
            var partBPR = Genital_Helper.get_breastsBPR(pawn);
 | 
			
		||||
            var additional_breasts = HediffMaker.MakeHediff(breastDef, pawn,partBPR);
 | 
			
		||||
 | 
			
		||||
            var CompHediff = additional_breasts.TryGetComp<rjw.CompHediffBodyPart>();
 | 
			
		||||
            if (CompHediff != null)
 | 
			
		||||
            {
 | 
			
		||||
                CompHediff.initComp(pawn);
 | 
			
		||||
                CompHediff.updatesize();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return additional_breasts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// There are some actions that block sex change, 
 | 
			
		||||
        /// being drafted or having sex. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="pawn">The pawn that want to sexchange.</param>
 | 
			
		||||
        /// <returns>False if the SexChange is applicable, True if there needs to be a wait timer.</returns>
 | 
			
		||||
        internal bool SexChangeBlocked(Pawn pawn)
 | 
			
		||||
        {
 | 
			
		||||
            // DEVNOTE: This list might extend on new cases, thus the explicit method.
 | 
			
		||||
            return pawn == null
 | 
			
		||||
                || pawn.health.Dead
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Masturbate)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Sex)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexBaseReciever)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexBaseInitiator)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_JoinInBed)
 | 
			
		||||
                
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexQuick)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexBaseRecieverQuickie)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexOnSpot)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexOnSpotReciever)
 | 
			
		||||
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Knotted)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Mate)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Mating)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Breeding)
 | 
			
		||||
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Rape)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_SexBaseRecieverRaped)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_RandomRape)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_RapeComfortPawn)
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_RapeEnemy)
 | 
			
		||||
                || pawn.jobs.curDriver is JobDriver_Lovin
 | 
			
		||||
 | 
			
		||||
                // This is a heavy check, but this is necessary because sometimes the pawns go somewhere to have sex and then they start despite missing genitalia!
 | 
			
		||||
                || (pawn.jobs.curDriver is JobDriver_Goto)
 | 
			
		||||
 | 
			
		||||
                || pawn.Drafted;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +44,8 @@
 | 
			
		|||
    <Compile Include="Genes\Breeding\Gene_MechBreeder.cs" />
 | 
			
		||||
    <Compile Include="Genes\Breeding\PatchMechBirth.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" />
 | 
			
		||||
| 
						 | 
				
			
			@ -217,6 +219,8 @@
 | 
			
		|||
      <Private>False</Private>
 | 
			
		||||
    </Reference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup />
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Folder Include="Genes\Gender\Patches\" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
			
		||||
</Project>
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue