mirror of
https://github.com/vegapnk/RJW-Genes.git
synced 2024-08-15 00:23:31 +00:00
Resolved Merge Conflicts
This commit is contained in:
commit
0e20e00150
88 changed files with 3886 additions and 31 deletions
|
@ -33,5 +33,35 @@ namespace RJW_Genes
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
//Get total fluidamount a person has.
|
||||
public static float GetTotalFluidAmount(Pawn pawn, float multiplier = 1f)
|
||||
{
|
||||
var partBPR = Genital_Helper.get_genitalsBPR(pawn);
|
||||
var parts = Genital_Helper.get_PartsHediffList(pawn, partBPR);
|
||||
float total_cum = 0;
|
||||
if (!parts.NullOrEmpty())
|
||||
{
|
||||
CompHediffBodyPart CompHediff;
|
||||
|
||||
foreach (Hediff part in parts)
|
||||
{
|
||||
if (GenitaliaChanger.IsArtificial(part))
|
||||
continue;
|
||||
|
||||
if (rjw.Genital_Helper.is_penis(part))
|
||||
{
|
||||
CompHediff = part.TryGetComp<rjw.CompHediffBodyPart>();
|
||||
if (CompHediff != null)
|
||||
{
|
||||
total_cum += CompHediff.FluidAmmount * CompHediff.FluidModifier * multiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return total_cum;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
using RimWorld;
|
||||
namespace RJW_Genes
|
||||
{
|
||||
public class GeneUtility
|
||||
{
|
||||
//Instead of seperate functions this should be simpeler
|
||||
public static bool HasGeneNullCheck(Pawn pawn, GeneDef genedef)
|
||||
{
|
||||
if (pawn.genes == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return pawn.genes.HasGene(genedef);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
float old_value = drain.Resource.Value;
|
||||
drain.Resource.Value += offset;
|
||||
//PostOffSetLifeForce(drain, old_value);
|
||||
}
|
||||
|
||||
public static void PostOffSetLifeForce(IGeneResourceDrain drain, float old_value)
|
||||
{
|
||||
if (old_value > 0.2f && drain.Resource.Value <= 0.2f)
|
||||
{
|
||||
Pawn pawn = drain.Pawn;
|
||||
|
||||
//Do things
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsMechbreeder(Pawn pawn)
|
||||
{
|
||||
if (pawn.genes == null)
|
||||
|
@ -15,6 +50,41 @@ namespace RJW_Genes
|
|||
return pawn.genes.HasGene(GeneDefOf.rjw_genes_mechbreeder);
|
||||
}
|
||||
|
||||
public static bool HasLifeForce(Pawn pawn)
|
||||
{
|
||||
if (pawn.genes == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return pawn.genes.HasGene(GeneDefOf.rjw_genes_lifeforce);
|
||||
}
|
||||
|
||||
public static bool HasLowLifeForce(Pawn pawn)
|
||||
{
|
||||
if (HasLifeForce(pawn))
|
||||
{
|
||||
Gene_LifeForce gene = pawn.genes.GetFirstGeneOfType<Gene_LifeForce>();
|
||||
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.Resource.Value < gene.MinLevelForAlert)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsInsectIncubator(Pawn pawn)
|
||||
{
|
||||
if (pawn.genes == null)
|
||||
|
@ -87,6 +157,15 @@ namespace RJW_Genes
|
|||
return pawn.genes.HasGene(GeneDefOf.rjw_genes_generous_donor);
|
||||
}
|
||||
|
||||
public static bool isPussyHealer(Pawn pawn)
|
||||
{
|
||||
if (pawn.genes == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return pawn.genes.HasGene(GeneDefOf.rjw_genes_pussyhealer);
|
||||
}
|
||||
|
||||
public static bool IsUnbreakable(Pawn pawn)
|
||||
{
|
||||
if (pawn.genes == null)
|
||||
|
@ -95,6 +174,7 @@ namespace RJW_Genes
|
|||
}
|
||||
return pawn.genes.HasGene(GeneDefOf.rjw_genes_unbreakable);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
|
||||
public static bool HasGenitaliaResizingGenes(Pawn pawn)
|
||||
|
@ -116,5 +196,7 @@ namespace RJW_Genes
|
|||
|
||||
return ResizingGenes;
|
||||
}
|
||||
=======
|
||||
>>>>>>> 09157e923d5c4c4cf71d79cb0af665ffd6a7c536
|
||||
}
|
||||
}
|
71
Source/Genes/Life_Force/Abilities/AbilityUtility.cs
Normal file
71
Source/Genes/Life_Force/Abilities/AbilityUtility.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
using UnityEngine;
|
||||
using RimWorld;
|
||||
using rjw;
|
||||
using rjw.Modules.Interactions.Helpers;
|
||||
|
||||
namespace RJW_Genes
|
||||
{
|
||||
public class CompAbilityEffect_CockEater : CompAbilityEffect
|
||||
{
|
||||
private new CompProperties_AbilityCockEater Props
|
||||
{
|
||||
get
|
||||
{
|
||||
return (CompProperties_AbilityCockEater)this.props;
|
||||
}
|
||||
}
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
Pawn pawn = target.Pawn;
|
||||
if (pawn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var partBPR = Genital_Helper.get_genitalsBPR(pawn);
|
||||
var parts = Genital_Helper.get_PartsHediffList(pawn, partBPR);
|
||||
if (!parts.NullOrEmpty())
|
||||
{
|
||||
foreach (Hediff part in parts)
|
||||
{
|
||||
if (GenitaliaChanger.IsArtificial(part))
|
||||
continue;
|
||||
|
||||
if (Genital_Helper.is_penis(part))
|
||||
{
|
||||
GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(this.parent.pawn), part.Severity); ;
|
||||
pawn.health.RemoveHediff(part);
|
||||
pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.rjw_genes_cock_eaten, pawn, null);
|
||||
break; //Only one penis at the time
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
|
||||
{
|
||||
Pawn pawn = target.Pawn;
|
||||
if (pawn != null)
|
||||
{
|
||||
bool flag = pawn.Faction == this.parent.pawn.Faction || pawn.IsPrisonerOfColony;
|
||||
bool flag2 = pawn.HostileTo(this.parent.pawn);
|
||||
bool flag3 = pawn.Downed;
|
||||
if (!flag && !(flag2 && flag3))
|
||||
{
|
||||
if (throwMessages)
|
||||
{
|
||||
if(flag2 && !flag3)
|
||||
{
|
||||
Messages.Message(pawn.Name + " is hostile, but not downed.", pawn, MessageTypeDefOf.RejectInput, false);
|
||||
}
|
||||
else if (!flag)
|
||||
{
|
||||
Messages.Message(pawn.Name + " is not a part of the colony or hostile.", pawn, MessageTypeDefOf.RejectInput, false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!Genital_Helper.has_penis_fertile(pawn))
|
||||
{
|
||||
if (throwMessages)
|
||||
{
|
||||
Messages.Message(pawn.Name + " has no penis", pawn, 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
104
Source/Genes/Life_Force/Abilities/CompAbilityEffect_PussyHeal.cs
Normal file
104
Source/Genes/Life_Force/Abilities/CompAbilityEffect_PussyHeal.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
using UnityEngine;
|
||||
using RimWorld;
|
||||
using rjw;
|
||||
using rjw.Modules.Interactions.Helpers;
|
||||
|
||||
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 healed wounds", 3.65f);
|
||||
//pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.Pussy_Healed, pawn, null);
|
||||
}
|
||||
//this.AfterSex(any_wound_tended);
|
||||
//FleckMaker.AttachedOverlay(pawn, FleckDefOf.FlashHollow, Vector3.zero, 1.5f, -1f);
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
//AbilityUtility.ValidateHasTendableWound(pawn, throwMessages, this.parent);
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
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 (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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
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;
|
||||
}
|
||||
}
|
21
Source/Genes/Life_Force/Abilities/CompProperties_Seduce.cs
Normal file
21
Source/Genes/Life_Force/Abilities/CompProperties_Seduce.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
70
Source/Genes/Life_Force/Alert_LowFertilin.cs
Normal file
70
Source/Genes/Life_Force/Alert_LowFertilin.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
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.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);
|
||||
}
|
||||
|
||||
// Token: 0x04004B5C RID: 19292
|
||||
private List<GlobalTargetInfo> targets = new List<GlobalTargetInfo>();
|
||||
|
||||
// Token: 0x04004B5D RID: 19293
|
||||
private List<string> targetLabels = new List<string>();
|
||||
}
|
||||
}
|
83
Source/Genes/Life_Force/GeneGizmo_ResourceLifeForce.cs
Normal file
83
Source/Genes/Life_Force/GeneGizmo_ResourceLifeForce.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
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>>();
|
||||
}
|
||||
}
|
153
Source/Genes/Life_Force/Gene_LifeForce.cs
Normal file
153
Source/Genes/Life_Force/Gene_LifeForce.cs
Normal file
|
@ -0,0 +1,153 @@
|
|||
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 && this.pawn.ageTracker.AgeBiologicalYears >= (RJWSettings.AllowYouthSex ? 13f : 18f));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
foreach (Gizmo gizmo2 in GeneResourceDrainUtility.GetResourceDrainGizmos(this))
|
||||
{
|
||||
yield return gizmo2;
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
|
||||
//Depending on how low the value is it will increase sexdrive and if it reaches zero it will create a mental break which will make the pawn rape others.
|
||||
//Not using base.Tick() as it is used to start mental breaks, but we have another way to do it.
|
||||
public override void Tick()
|
||||
{
|
||||
//base.Tick();
|
||||
if (this.CanOffset && this.Resource != null)
|
||||
{
|
||||
GeneUtility.OffsetLifeForce(this, -this.ResourceLossPerDay / 60000f);
|
||||
//this.Resource.Value -= this.ResourceLossPerDay / 60000;
|
||||
if (this.Resource.Value <= 0 && this.pawn.IsHashIntervalTick(300))
|
||||
{
|
||||
if (ModsConfig.BiotechActive && this.def.mentalBreakDef != null &&
|
||||
this.pawn.Spawned && !this.pawn.InMentalState && !this.pawn.Downed &&
|
||||
this.def.mentalBreakDef.Worker.BreakCanOccur(this.pawn))
|
||||
{
|
||||
this.def.mentalBreakDef.Worker.TryStart(this.pawn, "MentalStateReason_Gene".Translate() + ": " + this.LabelCap, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
Source/Genes/Life_Force/Gene_LifeForceDrain.cs
Normal file
79
Source/Genes/Life_Force/Gene_LifeForceDrain.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> GetGizmos()
|
||||
{
|
||||
foreach (Gizmo gizmo in GeneResourceDrainUtility.GetResourceDrainGizmos(this))
|
||||
{
|
||||
yield return gizmo;
|
||||
}
|
||||
IEnumerator<Gizmo> enumerator = null;
|
||||
yield break;
|
||||
yield break;
|
||||
}
|
||||
|
||||
[Unsaved(false)]
|
||||
private Gene_LifeForce cachedLifeForceGene;
|
||||
|
||||
private const float MinAgeForDrain = 3f;
|
||||
}
|
||||
}
|
23
Source/Genes/Life_Force/HediffWithComps_tank.cs
Normal file
23
Source/Genes/Life_Force/HediffWithComps_tank.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
namespace RJW_Genes
|
||||
{
|
||||
internal class HediffWithComps_tank : HediffWithComps
|
||||
{
|
||||
public override string LabelInBrackets
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(base.LabelInBrackets);
|
||||
stringBuilder.Append(this.Severity.ToStringPercent());
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace RJW_Genes
|
||||
{
|
||||
public class IngestionOutcomeDoer_LifeForceOffset : IngestionOutcomeDoer
|
||||
{
|
||||
protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
|
||||
{
|
||||
if (GeneUtility.HasLifeForce(pawn))
|
||||
{
|
||||
float num = ingested.stackCount * this.FertilinPerUnit / 100;
|
||||
GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(pawn), num);
|
||||
}
|
||||
}
|
||||
public float FertilinPerUnit = 1f;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
55
Source/Genes/Life_Force/JobDrivers/JobDriver_Seduced.cs
Normal file
55
Source/Genes/Life_Force/JobDrivers/JobDriver_Seduced.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
108
Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpot.cs
Normal file
108
Source/Genes/Life_Force/JobDrivers/JobDriver_SexOnSpot.cs
Normal file
|
@ -0,0 +1,108 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
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;
|
||||
}
|
||||
|
||||
// Token: 0x06000420 RID: 1056 RVA: 0x00024190 File Offset: 0x00022390
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
87
Source/Genes/Life_Force/JobGiver_GetLifeForce.cs
Normal file
87
Source/Genes/Life_Force/JobGiver_GetLifeForce.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
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("LustLicentia.RJWLabs") && gene_lifeforce.StoredCumAllowed)
|
||||
{
|
||||
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.FertilinPerUnit);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
38
Source/Genes/Life_Force/JobGiver_LifeForce_RandomRape.cs
Normal file
38
Source/Genes/Life_Force/JobGiver_LifeForce_RandomRape.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
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)))));
|
||||
}
|
||||
}
|
||||
}
|
32
Source/Genes/Life_Force/LifeForceMentalBreakWorker.cs
Normal file
32
Source/Genes/Life_Force/LifeForceMentalBreakWorker.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
23
Source/Genes/Life_Force/LifeForceMentalState.cs
Normal file
23
Source/Genes/Life_Force/LifeForceMentalState.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
14
Source/Genes/Life_Force/LifeForceMentalStateWorker.cs
Normal file
14
Source/Genes/Life_Force/LifeForceMentalStateWorker.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
180
Source/Genes/Life_Force/Patch_LifeForce.cs
Normal file
180
Source/Genes/Life_Force/Patch_LifeForce.cs
Normal file
|
@ -0,0 +1,180 @@
|
|||
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
|
||||
{
|
||||
|
||||
[HarmonyPatch(typeof(SexUtility), nameof(SexUtility.SatisfyPersonal))]
|
||||
public static class Patch_LifeForce
|
||||
{
|
||||
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 succubus = props.partner;
|
||||
|
||||
if (!props.isRevese)
|
||||
{
|
||||
if (props.isReceiver)
|
||||
{
|
||||
// Scenario Dom Succubus, normal
|
||||
absorb_factor = BaseDom(props, succubus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scenario Sub Succubus, normal
|
||||
absorb_factor = BaseSub(props, succubus);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (props.isReceiver)
|
||||
{
|
||||
// Scenario Dom Succubus, Reverse
|
||||
absorb_factor = BaseSub(props, succubus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scenario Sub Succubus, Reverse
|
||||
absorb_factor = BaseDom(props, succubus);
|
||||
}
|
||||
}
|
||||
|
||||
//If we remove this check fertelin is always lost, but the succubus doesn't always gain any
|
||||
if (absorb_factor != 0f)
|
||||
{
|
||||
AbsorbFertilin(props, absorb_factor);
|
||||
}
|
||||
|
||||
if (GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_drainer) && !props.pawn.health.hediffSet.HasHediff(HediffDefOf.Succubus_Drained))
|
||||
{
|
||||
props.pawn.health.AddHediff(HediffDefOf.Succubus_Drained);
|
||||
GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(succubus), 0.25f);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void AbsorbFertilin(SexProps props, float absorb_factor = 1f)
|
||||
{
|
||||
Pawn_GeneTracker genes = props.partner.genes;
|
||||
Gene_LifeForce gene = genes.GetFirstGeneOfType<Gene_LifeForce>();
|
||||
Hediff fertilin_lost = props.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Fertilin_Lost);
|
||||
//Around quarter get ejected everytime pawn cums
|
||||
float multiplier = Rand.Range(0.10f, 0.40f);
|
||||
|
||||
|
||||
//Create a new ferilin_lost hediff or reduce multiplier
|
||||
if (fertilin_lost == null)
|
||||
{
|
||||
Hediff new_fertilin_lost = HediffMaker.MakeHediff(HediffDefOf.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;
|
||||
}
|
||||
//More in the tank means more to give
|
||||
if (props.pawn.Has(Quirk.Messy))
|
||||
{
|
||||
multiplier *= 2;
|
||||
}
|
||||
//Currently taking the sum of all penises, maybe I should just consider one at random
|
||||
float valuechange = CumUtility.GetTotalFluidAmount(props.pawn) / 100 * absorb_factor * multiplier;
|
||||
GeneUtility.OffsetLifeForce(GeneUtility.GetLifeForceGene(props.partner), valuechange);
|
||||
//gene.Resource.Value += CumUtility.GetTotalFluidAmount(props.pawn) / 100 * absorb_factor * multiplier;
|
||||
}
|
||||
|
||||
|
||||
public static float BaseDom(SexProps props, Pawn succubus)
|
||||
{
|
||||
float absorb_factor = 0f;
|
||||
if (props.sexType == xxx.rjwSextype.Sixtynine)
|
||||
{
|
||||
absorb_factor += 1f;
|
||||
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.Vaginal)
|
||||
{
|
||||
//with insertion absorbtion or vaginal cum absorbtion
|
||||
//absorb_factor += 1f;
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.DoublePenetration)
|
||||
{
|
||||
if (GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_vaginal_absorber))
|
||||
{
|
||||
//with insertion absorbtion?
|
||||
//absorb_factor += 0.5f;
|
||||
}
|
||||
if (GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_anal_absorber))
|
||||
{
|
||||
//with insertion absorbtion?
|
||||
//absorb_factor += 0.5f;
|
||||
}
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.Scissoring)
|
||||
{
|
||||
//with vaginal cum absorption && vaginal absorbtion
|
||||
//absorb_factor += 1f;
|
||||
}
|
||||
return absorb_factor;
|
||||
}
|
||||
|
||||
public static float BaseSub(SexProps props, Pawn succubus)
|
||||
{
|
||||
float absorb_factor = 0f;
|
||||
if (props.sexType == xxx.rjwSextype.Oral || props.sexType == xxx.rjwSextype.Fellatio || props.sexType == xxx.rjwSextype.Sixtynine)
|
||||
{
|
||||
absorb_factor += 1f;
|
||||
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.Vaginal && GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_vaginal_absorber))
|
||||
{
|
||||
absorb_factor += 1f;
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.Anal && GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_anal_absorber))
|
||||
{
|
||||
absorb_factor += 1f;
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.DoublePenetration)
|
||||
{
|
||||
if (GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_vaginal_absorber))
|
||||
{
|
||||
absorb_factor += 0.5f;
|
||||
}
|
||||
if (GeneUtility.HasGeneNullCheck(succubus, GeneDefOf.rjw_genes_anal_absorber))
|
||||
{
|
||||
absorb_factor += 0.5f;
|
||||
}
|
||||
}
|
||||
else if (props.sexType == xxx.rjwSextype.Scissoring || props.sexType == xxx.rjwSextype.Cunnilingus)
|
||||
{
|
||||
//with vaginal cum absorbtion
|
||||
//absorb_factor += 1f;
|
||||
}
|
||||
return absorb_factor;
|
||||
}
|
||||
}
|
||||
}
|
57
Source/Genes/Life_Force/Patch_SexTicks_ChangePsyfocus.cs
Normal file
57
Source/Genes/Life_Force/Patch_SexTicks_ChangePsyfocus.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
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
|
||||
{
|
||||
|
||||
//[HarmonyPatch(typeof(JobDriver_Sex), nameof(JobDriver_Sex.ChangePsyfocus))]
|
||||
public static class Patch_SexTicks_ChangePsyfocus
|
||||
{
|
||||
//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)
|
||||
{
|
||||
if (__instance.Sexprops.sexType == xxx.rjwSextype.Cunnilingus)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
Pawn pawn2 = target as Pawn;
|
||||
if (pawn2 != null)
|
||||
{
|
||||
//We need who the pawn on top is and if reverse we need to make the sub the pawn on top
|
||||
if (__instance.Sexprops.isRevese)
|
||||
{
|
||||
|
||||
DrinkCumflation(pawn2, pawn);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
DrinkCumflation(pawn, pawn2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrinkCumflation(Pawn dom, Pawn sub)
|
||||
{
|
||||
if (GeneUtility.HasLifeForce(sub) && dom.health.hediffSet.HasHediff(HediffDef.Named("Cumflation")))
|
||||
{
|
||||
Hediff cumflation = dom.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Cumflation"));
|
||||
Gene_LifeForce gene_LifeForce = sub.genes.GetFirstGeneOfType<Gene_LifeForce>();
|
||||
cumflation.Severity -= 0.1f;
|
||||
gene_LifeForce.Resource.Value += 0.05f;
|
||||
}
|
||||
}
|
||||
//Maybe I can store gene and hediff so I dont need to look them up every time
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
14
Source/Genes/Life_Force/ThinkNode_ConditionalLowLifeForce.cs
Normal file
14
Source/Genes/Life_Force/ThinkNode_ConditionalLowLifeForce.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,23 +12,31 @@ namespace RJW_Genes
|
|||
{
|
||||
public class Gene_Aphrodisiac_Pheromones : Gene
|
||||
{
|
||||
|
||||
//Summary one every one check for all pawns nearby and in line of sight and add/renew a hediff which increases sexdrive for six hours.
|
||||
public override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
if (this.pawn.IsHashIntervalTick(2500))
|
||||
{
|
||||
foreach (Pawn pawn in this.AffectedPawns(this.pawn.Position, this.pawn.Map))
|
||||
{
|
||||
this.InduceAphrodisiac(pawn);
|
||||
}
|
||||
//Only spread pheromones if sexdrive above 1
|
||||
float sexfrequency = this.pawn.GetStatValue(StatDef.Named("SexFrequency"));
|
||||
if(sexfrequency > 1f)
|
||||
{
|
||||
foreach (Pawn pawn in this.AffectedPawns(this.pawn.Position, this.pawn.Map))
|
||||
{
|
||||
this.InduceAphrodisiac(pawn, sexfrequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Creatus an IEnumerable of all pawns which are closeby and in lineofsight, self and other pawns with aphrodisiac pheromones gene are skipped.
|
||||
private IEnumerable<Pawn> AffectedPawns(IntVec3 pos, Map map)
|
||||
{
|
||||
foreach (Pawn pawn in map.mapPawns.AllPawns)
|
||||
{
|
||||
if (pos.DistanceTo(pawn.Position) < 5)
|
||||
if (this.pawn != null && pawn != this.pawn && pos.DistanceTo(pawn.Position) < 5 && GenSight.LineOfSight(pos, pawn.Position, pawn.Map) && !GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_aphrodisiac_pheromones))
|
||||
{
|
||||
yield return pawn;
|
||||
}
|
||||
|
@ -37,17 +45,36 @@ namespace RJW_Genes
|
|||
yield break;
|
||||
}
|
||||
|
||||
private void InduceAphrodisiac(Pawn pawn)
|
||||
//Applies er renews a hediff which increases sexdrive for 6 hours
|
||||
private void InduceAphrodisiac(Pawn pawn, float sexfrequency)
|
||||
{
|
||||
Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Aphrodisiac_Pheromone);
|
||||
|
||||
if (hediff != null)
|
||||
{
|
||||
hediff.Severity = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
pawn.health.AddHediff(HediffDefOf.Aphrodisiac_Pheromone);
|
||||
Hediff aphrodisiac = HediffMaker.MakeHediff(HediffDefOf.Aphrodisiac_Pheromone, pawn);
|
||||
foreach (StatModifier stat in aphrodisiac.CurStage.statFactors)
|
||||
{
|
||||
//Log.Message(pawn.Name.ToString());
|
||||
//Log.Message(stat.stat.defName);
|
||||
//Log.Message(stat.value.ToString());
|
||||
if (stat.stat.defName == "SexFrequency")
|
||||
{
|
||||
stat.value = ModifySexfrequency(pawn, sexfrequency);
|
||||
pawn.health.AddHediff(aphrodisiac);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Function to modify aphrodisiac strength, currently has no effect, but it's an easy hook for other modders.
|
||||
public float ModifySexfrequency(Pawn pawn, float sexfrequency)
|
||||
{
|
||||
return sexfrequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue