diff --git a/Common/Assemblies/Rjw-Genes.dll b/Common/Assemblies/Rjw-Genes.dll index df5976d..706a831 100644 Binary files a/Common/Assemblies/Rjw-Genes.dll and b/Common/Assemblies/Rjw-Genes.dll differ diff --git a/Common/Defs/AbilityDefs/Ability_PussyHeal.xml b/Common/Defs/AbilityDefs/Ability_PussyHeal.xml new file mode 100644 index 0000000..6837a39 --- /dev/null +++ b/Common/Defs/AbilityDefs/Ability_PussyHeal.xml @@ -0,0 +1,47 @@ + + + + rjw_genes_pussyheal + + Rape another pawn, so you can heal them with your vagina's special healing power. + Things/Mote/Heart + false + true + false + 60000 + Mote_CoagulateStencil + Coagulate + Coagulate_Cast + rjw_genes_lifeforce_healpussy + 401 + + Verb_CastAbilityTouch + false + -1 + 0 + + true + false + false + false + true + + + +
  • + 0.4~0.8 +
  • +
  • + + +
  • Rape
  • + + + +
  • Vagina
  • +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/Common/Defs/Genes/GeneDefs_Cosmetic.xml b/Common/Defs/Genes/GeneDefs_Cosmetic.xml index acff4a5..5a65039 100644 --- a/Common/Defs/Genes/GeneDefs_Cosmetic.xml +++ b/Common/Defs/Genes/GeneDefs_Cosmetic.xml @@ -18,7 +18,7 @@ rjw_genes_Succubus_Wings Carriers of this gene grow succubus wings. - UI/Icons/Genes/Gene_TailFurry + Genes/Icons/Succubus_Wings (0.75, 0.75, 0.75) 1000 1 diff --git a/Common/Defs/Genes/GeneDefs_LifeForce.xml b/Common/Defs/Genes/GeneDefs_LifeForce.xml index 1428ec2..69db900 100644 --- a/Common/Defs/Genes/GeneDefs_LifeForce.xml +++ b/Common/Defs/Genes/GeneDefs_LifeForce.xml @@ -33,4 +33,28 @@ 1 1 + + + rjw_genes_pussyhealer + + pussyhealer + Carriers of this gene are able use vaginal sex to tend to other's wounds. + Things/Mote/Heart + Ability + +
  • rjw_genes_pussyheal
  • +
    + + rjw_genes_pussyheal + + 1 + 13 + + +
  • life
  • +
  • clotter
  • +
  • tender
  • +
    +
    +
    \ No newline at end of file diff --git a/Common/Defs/JobDefs/Jobs_LifeForce.xml b/Common/Defs/JobDefs/Jobs_LifeForce.xml index 274ade7..babb547 100644 --- a/Common/Defs/JobDefs/Jobs_LifeForce.xml +++ b/Common/Defs/JobDefs/Jobs_LifeForce.xml @@ -7,4 +7,11 @@ Raping false + + + rjw_genes_lifeforce_healpussy + RJW_Genes.JobDriver_CastAbilityAfterSex + Healing someone with sex. + false + \ No newline at end of file diff --git a/Common/Textures/Genes/Icons/Succubus_Wings.png b/Common/Textures/Genes/Icons/Succubus_Wings.png new file mode 100644 index 0000000..5ca976f Binary files /dev/null and b/Common/Textures/Genes/Icons/Succubus_Wings.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png index 19ecc3e..71e3f53 100644 Binary files a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_east.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png index 92c4a01..331add5 100644 Binary files a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_north.png differ diff --git a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png index 92c4a01..331add5 100644 Binary files a/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png and b/Common/Textures/Things/Pawn/Humanlike/BodyAttachments/rjw_genes_Succubus_Wings/Succubus_Wings_south.png differ diff --git a/Source/GeneDefOf.cs b/Source/GeneDefOf.cs index 726bb53..5ac85dd 100644 --- a/Source/GeneDefOf.cs +++ b/Source/GeneDefOf.cs @@ -74,5 +74,6 @@ namespace RJW_Genes // LifeForce public static readonly GeneDef rjw_genes_lifeforce; + public static readonly GeneDef rjw_genes_pussyhealer; } } diff --git a/Source/Genes/GeneUtility.cs b/Source/Genes/GeneUtility.cs index 3bea9a6..0a8d571 100644 --- a/Source/Genes/GeneUtility.cs +++ b/Source/Genes/GeneUtility.cs @@ -102,5 +102,14 @@ 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); + } } } \ No newline at end of file diff --git a/Source/Genes/Life_Force/AbilityUtility.cs b/Source/Genes/Life_Force/AbilityUtility.cs new file mode 100644 index 0000000..896694e --- /dev/null +++ b/Source/Genes/Life_Force/AbilityUtility.cs @@ -0,0 +1,52 @@ +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 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; + } + } +} \ No newline at end of file diff --git a/Source/Genes/Life_Force/CompAbilityEffect_PussyHeal.cs b/Source/Genes/Life_Force/CompAbilityEffect_PussyHeal.cs new file mode 100644 index 0000000..5ddb6af --- /dev/null +++ b/Source/Genes/Life_Force/CompAbilityEffect_PussyHeal.cs @@ -0,0 +1,103 @@ +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); + } + + public void AfterSex(Pawn pawn, Pawn target) + { + List 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; + } + + + } +} diff --git a/Source/Genes/Life_Force/CompAbility_SexInteractionRequirements.cs b/Source/Genes/Life_Force/CompAbility_SexInteractionRequirements.cs new file mode 100644 index 0000000..5e926c5 --- /dev/null +++ b/Source/Genes/Life_Force/CompAbility_SexInteractionRequirements.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using rjw; +using rjw.Modules.Interactions.Objects; +using rjw.Modules.Interactions.Helpers; +using rjw.Modules.Interactions.Enums; +using rjw.Modules.Interactions.Implementation; +using rjw.Modules.Interactions.Defs.DefFragment; +namespace RJW_Genes +{ + public class CompAbility_SexInteractionRequirements : AbilityComp + { + public CompProperties_SexInteractionRequirements Props + { + get + { + return (CompProperties_SexInteractionRequirements)this.props; + } + } + + public static List GenerateInteractionDefList(Pawn pawn, Pawn pawn2, CompProperties_SexInteractionRequirements sexpropsreq) + { + List tags = new List(); + if (pawn2.IsAnimal()) + { + tags.Add(InteractionTag.Animal); + + } + else + { + tags = sexpropsreq.tags; + } + + InteractionRequirement dominantRequirement = sexpropsreq.dominantRequirement; + InteractionRequirement submissiveRequirement = sexpropsreq.submissiveRequirement; + List sexinteractions = SexUtility.SexInterractions; + List list = new List(); + //List a = from interaction in sexinteractions + //where InteractionHelper.GetWithExtension(interaction).DominantHasFamily(dominantRequirement.families.) + // select interaction; + + //should use where select but dont fully understand that, so I am using this. + foreach (InteractionDef interactionDef in SexUtility.SexInterractions) + { + //Use rjw function to check if the interaction would be valid + if (!LewdInteractionValidatorService.Instance.IsValid(interactionDef, pawn, pawn2)) + { + continue; + } + InteractionWithExtension withExtension = InteractionHelper.GetWithExtension(interactionDef); + bool add_interaction = false; + //only add interactions which have a correct tag + foreach (InteractionTag tag in tags) + { + if (withExtension.HasInteractionTag(tag)) + { + add_interaction = true; + break; + } + } + //In case of failure go to next interaction + if (!add_interaction) + { + continue; + } + //goes to next interaction if it doesn't have the required genitals + if (dominantRequirement != null) + { + foreach (GenitalFamily genitalFamily in dominantRequirement.families) + { + if (!withExtension.DominantHasFamily(genitalFamily)) + { + add_interaction = false; + break; + + } + } + if (!add_interaction) + { + continue; + } + foreach (GenitalTag tag in dominantRequirement.tags) + { + if (!withExtension.DominantHasTag(tag)) + { + add_interaction = false; + break; + + } + } + } + //goes to next interaction if it doesn't have the required genitals + if (submissiveRequirement != null) + { + foreach (GenitalFamily genitalFamily in submissiveRequirement.families) + { + if (!withExtension.SubmissiveHasFamily(genitalFamily)) + { + add_interaction = false; + break; + + } + } + if (!add_interaction) + { + continue; + } + foreach (GenitalTag tag in submissiveRequirement.tags) + { + if (!withExtension.SubmissiveHasTag(tag)) + { + add_interaction = false; + break; + + } + + } + } + if (add_interaction) + { + list.Add(interactionDef); + } + + } + return list; + } + + //Generates a valid interaction for the requirements and assigns sexprops based on that + public static SexProps GenerateSexProps(Pawn pawn, Pawn pawn2, CompProperties_SexInteractionRequirements sexpropsreq) + { + List interactionlist = GenerateInteractionDefList(pawn, pawn2, sexpropsreq); + if (!interactionlist.Any()) + { + return null; + } + InteractionDef dictionaryKey = interactionlist.RandomElement(); + bool rape = InteractionHelper.GetWithExtension(dictionaryKey).HasInteractionTag(InteractionTag.Rape); + SexProps sexProps = new SexProps(); + sexProps.pawn = pawn; + sexProps.partner = pawn2; + sexProps.sexType = SexUtility.rjwSextypeGet(dictionaryKey); + sexProps.isRape = rape; + sexProps.isRapist = rape; + sexProps.canBeGuilty = false; + sexProps.dictionaryKey = dictionaryKey; + sexProps.rulePack = SexUtility.SexRulePackGet(dictionaryKey); + return sexProps; + } + } +} diff --git a/Source/Genes/Life_Force/CompProperties_AbilityPussyHeal.cs b/Source/Genes/Life_Force/CompProperties_AbilityPussyHeal.cs new file mode 100644 index 0000000..16ba74d --- /dev/null +++ b/Source/Genes/Life_Force/CompProperties_AbilityPussyHeal.cs @@ -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; + } +} diff --git a/Source/Genes/Life_Force/CompProperties_SexInteractionRequirements.cs b/Source/Genes/Life_Force/CompProperties_SexInteractionRequirements.cs new file mode 100644 index 0000000..3756d7b --- /dev/null +++ b/Source/Genes/Life_Force/CompProperties_SexInteractionRequirements.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using rjw; +using rjw.Modules.Interactions.Defs.DefFragment; +using rjw.Modules.Interactions.Enums; + +namespace RJW_Genes +{ + public class CompProperties_SexInteractionRequirements : AbilityCompProperties + { + public CompProperties_SexInteractionRequirements() + { + this.compClass = typeof(CompAbility_SexInteractionRequirements); + } + + public List tags = new List(); + public InteractionRequirement dominantRequirement; + public InteractionRequirement submissiveRequirement; + } +} diff --git a/Source/Genes/Life_Force/Interactionchances.cs b/Source/Genes/Life_Force/Interactionchances.cs new file mode 100644 index 0000000..fd7a43d --- /dev/null +++ b/Source/Genes/Life_Force/Interactionchances.cs @@ -0,0 +1,16 @@ +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 Interaction_weights + { + public InteractionDef interaction; + public int weight = 1; + + } +} diff --git a/Source/Genes/Life_Force/JobDriver_CastAbilityAfterSex.cs b/Source/Genes/Life_Force/JobDriver_CastAbilityAfterSex.cs new file mode 100644 index 0000000..7198890 --- /dev/null +++ b/Source/Genes/Life_Force/JobDriver_CastAbilityAfterSex.cs @@ -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 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 = CompAbility_SexInteractionRequirements.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; + } + } +} diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index 3f24101..26c21bf 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -114,7 +114,14 @@ + + + + + + +