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,6 +32,7 @@ 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;
|
||||
|
@ -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…
Reference in a new issue