public static double GetWetness(Hediff organ) { double amount = 0; // Getting wetness CompHediffBodyPart hediffComp = organ.TryGetComp <CompHediffBodyPart>(); if (hediffComp != null && hediffComp.FluidAmmount > 0) { Dyspareunia.Log("Fluid: " + hediffComp.FluidType + ". Amount: " + hediffComp.FluidAmmount + ". Modifier: " + hediffComp.FluidModifier); amount = hediffComp.FluidAmmount * hediffComp.FluidModifier / organ.pawn.BodySize; } // Adding s***n to the amount of fluids foreach (Hediff_Semen hediff in organ.pawn.health.hediffSet.GetHediffs <Hediff_Semen>()) { if (hediff.Part == organ.Part) { Dyspareunia.Log("Found " + hediff.Severity + " s***n in " + hediff.Part.Label); amount += hediff.Severity; } } return(amount / organ.pawn.BodySize * 0.1); }
/// <summary> /// Returns the size (calculated as coverage * body size * 10) of the pawn's hand /// </summary> /// <param name="pawn"></param> /// <returns></returns> public static double GetHandSize(Pawn pawn) { if (pawn?.RaceProps?.body is null) { Dyspareunia.Log("The pawn has no body!"); return(0); } if (pawn?.health?.hediffSet is null) { Dyspareunia.Log("The pawn has no hediffSet."); return(0); } List <BodyPartRecord> parts = (List <BodyPartRecord>)pawn.RaceProps.body.GetPartsWithDef(BodyPartDefOf.Hand); if (parts is null) { Dyspareunia.Log(pawn + " has no hands!"); return(0); } Dyspareunia.Log(pawn.Label + " has " + parts.Count + " hands."); double size = parts.NullOrEmpty <BodyPartRecord>() ? 0 : parts[0].coverage * pawn.BodySize * 10; Dyspareunia.Log("Hand size: " + size); return(size); }
/// <summary> /// Returns the size (calculated as coverage * body size * 10) of the pawn's biggest finger /// </summary> /// <param name="pawn"></param> /// <returns></returns> public static double GetFingerSize(Pawn pawn) { if (pawn?.RaceProps?.body is null) { Dyspareunia.Log("The pawn has no body!"); return(0); } double biggest = 0; foreach (BodyPartRecord bpr in pawn.RaceProps.body.AllParts) { if (bpr.def.defName == "Finger") { Dyspareunia.Log("Finger '" + bpr.Label + "' of coverage " + bpr.coverage + " found."); if (!pawn.health.hediffSet.PartIsMissing(bpr)) { biggest = Math.Max(bpr.coverage, biggest); } else { Dyspareunia.Log("But it is missing :("); } } } Dyspareunia.Log("Finger size: " + (biggest * pawn.BodySize * 10)); return(biggest * pawn.BodySize * 10); }
((organ.def.defName.ToLower().Contains("anus") ? 0.5 : 1) + organ.Severity) * organ.pawn.BodySize; // Assume max natural organ size is 2x bigger than the smallest public static void AddHediff(string damageDefName, double damage, Hediff orifice, Pawn instigator) { // If damage is too low (or negative), skipping it if (damage < 0.5) { return; } Dyspareunia.Log(damageDefName + " damage amount: " + damage); DamageDef damageDef = DefDatabase <DamageDef> .GetNamed(damageDefName); if (damageDef == null) { Dyspareunia.Log("No DamageDef '" + damageDefName + "' found."); return; } DamageInfo damageInfo = new DamageInfo(damageDef, (float)damage, instigator: instigator, hitPart: orifice.Part); damageInfo.SetIgnoreArmor(true); HediffDef hediffDef = damageDef.hediff; if (hediffDef == null) { Dyspareunia.Log("No HediffDef for '" + damageDef.label + "' found."); return; } Hediff hediff = HediffMaker.MakeHediff(hediffDef, orifice.pawn, orifice.Part); hediff.Severity = (float)damage; orifice.pawn.health.AddHediff(hediff, orifice.Part, damageInfo); }
public static void StretchOrgan(Hediff organ, double amount) { if (amount <= 0) { return; } float stretch = (float)amount / organ.Part.def.hitPoints * StretchFactor; Dyspareunia.Log("Stretching " + organ.def.defName + " (" + organ.Severity + " size) by " + stretch); organ.Severity += stretch; }
public static void ApplyDamage(Pawn penetrator, double penetratingOrganSize, Hediff orifice, bool isRape) { // Checking validity of penetrator and target if (penetrator is null) { Dyspareunia.Log("Penetrator not found!"); return; } Pawn target = orifice?.pawn; if (target is null) { Dyspareunia.Log("Orifice/target not found!"); return; } Dyspareunia.Log("Applying damage from " + penetrator.Label + " (effective size " + penetratingOrganSize + ") penetrating " + target.Label + "'s " + orifice.def.defName + " (effective size " + GetOrganSize(orifice) + ")."); // Calculating damage amounts double relativeSize = penetratingOrganSize / GetOrganSize(orifice); double rubbingDamage = 0.5; double stretchDamage = Math.Max(relativeSize - 1, 0); if (relativeSize > 1.25) { rubbingDamage *= 1.5; // If penetrating organ is much bigger than the orifice, rubbing damage is higher } if (isRape) // Rape is rough { rubbingDamage *= 1.5; stretchDamage *= 1.5; } if (penetrator.story?.traits != null) { if (penetrator.story.traits.HasTrait(TraitDefOf.Bloodlust)) { rubbingDamage *= 1.25; stretchDamage *= 1.125; } if (penetrator.story.traits.HasTrait(xxx.rapist)) { rubbingDamage *= 1.25; stretchDamage *= 1.125; } if (penetrator.story.traits.HasTrait(TraitDefOf.Psychopath)) { rubbingDamage *= 1.2; stretchDamage *= 1.1; } if ((penetrator.story.traits.HasTrait(TraitDefOf.DislikesMen) && target.gender == Gender.Male) || (penetrator.story.traits.HasTrait(TraitDefOf.DislikesWomen) && target.gender == Gender.Female)) { rubbingDamage *= 1.1; stretchDamage *= 1.05; } if (penetrator.story.traits.HasTrait(TraitDefOf.Kind)) { rubbingDamage *= 0.8; stretchDamage *= 0.9; } if (penetrator.story.traits.HasTrait(wimpTraitDef)) { rubbingDamage *= 0.8; stretchDamage *= 0.9; } } if (target.story?.traits != null) { if (target.story.traits.HasTrait(wimpTraitDef)) { rubbingDamage *= 1.1; stretchDamage *= 1.1; } if (target.story.traits.HasTrait(xxx.m*******t)) { rubbingDamage *= 1.1; stretchDamage *= 1.05; } if (target.story.traits.HasTrait(xxx.m*******t)) { rubbingDamage *= 1.1; stretchDamage *= 1.05; } if (target.story.traits.HasTrait(TraitDefOf.Tough)) { rubbingDamage *= 0.9; stretchDamage *= 0.9; } } Dyspareunia.Log("Rubbing damage before randomization: " + rubbingDamage); Dyspareunia.Log("Stretch damage before randomization: " + stretchDamage); // Applying randomness rubbingDamage *= Rand.Range(0.75f, 1.25f); stretchDamage *= Rand.Range(0.75f, 1.25f); Dyspareunia.Log("Rubbing damage before lubricant: " + rubbingDamage); Dyspareunia.Log("Stretch damage before lubricant: " + stretchDamage); // Stretching the orifice StretchOrgan(orifice, stretchDamage); // Applying lubrication double wetness = GetWetness(orifice); Dyspareunia.Log("Total wetness: " + wetness); rubbingDamage *= Math.Max(1 - wetness * 0.5, 0.25); stretchDamage *= Math.Max(1 - wetness * 0.5, 0.4); Dyspareunia.Log("Rubbing damage final: " + rubbingDamage); Dyspareunia.Log("Stretch damage final: " + stretchDamage); // Adding a single hediff based on which damage type is stronger (to reduce clutter in the Health view and save on the number of treatments) AddHediff(rubbingDamage > stretchDamage ? "SexRub" : "SexStretch", rubbingDamage + stretchDamage, orifice, penetrator); // Applying positive moodlets for a big dick if (relativeSize > 1.25) { if (penetrator.needs?.mood?.thoughts?.memories != null) { penetrator.needs.mood.thoughts.memories.TryGainMemory(ThoughtMaker.MakeThought(ThoughtDef.Named("TightLovin"), relativeSize < 2 ? 0 : 1)); } if (!isRape && target.needs?.mood?.thoughts?.memories != null) { target.needs.mood.thoughts.memories.TryGainMemory(ThoughtMaker.MakeThought(ThoughtDef.Named("BigDick"), relativeSize < 2 ? 0 : 1)); } } }
/// <summary> /// This method discovers all penetrations in the sex act and applies respective damage /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="rape"></param> /// <param name="sextype"></param> /// <returns>Empty list if no eligible penetrations found, or an element for each penetration (can be DP etc.)</returns> public static void ProcessPenetrations(Pawn p1, Pawn p2, bool rape, xxx.rjwSextype sextype) { Dyspareunia.Log("Checking " + sextype + (rape ? " rape" : " sex") + " between " + p1.Label + " and " + p2.Label + "."); switch (sextype) { case xxx.rjwSextype.Vaginal: if (Dyspareunia.HasPenetratingOrgan(p1) && Genital_Helper.has_vagina(p2)) { ApplyDamage(Genital_Helper.get_penis_all(p1), Dyspareunia.GetVagina(p2), rape); } else { ApplyDamage(Genital_Helper.get_penis_all(p2), Dyspareunia.GetVagina(p1), false); } break; case xxx.rjwSextype.Anal: if (Dyspareunia.HasPenetratingOrgan(p1) && Genital_Helper.has_anus(p2)) { ApplyDamage(Genital_Helper.get_penis_all(p1), Dyspareunia.GetAnus(p2), rape); } else { ApplyDamage(Genital_Helper.get_penis_all(p2), Dyspareunia.GetAnus(p1), false); } break; case xxx.rjwSextype.Oral: // Oral penetration not supported ATM break; case xxx.rjwSextype.DoublePenetration: if (Genital_Helper.has_multipenis(p1) && Genital_Helper.has_vagina(p2) && Genital_Helper.has_anus(p2)) { ApplyDamage(Genital_Helper.get_penis_all(p1), Dyspareunia.GetVagina(p2), rape); ApplyDamage(Genital_Helper.get_penis_all(p1), Dyspareunia.GetAnus(p2), rape); } else { ApplyDamage(Genital_Helper.get_penis_all(p2), Dyspareunia.GetVagina(p1), false); ApplyDamage(Genital_Helper.get_penis_all(p2), Dyspareunia.GetAnus(p1), false); } break; case xxx.rjwSextype.Fingering: if (Genital_Helper.has_vagina(p2) || Genital_Helper.has_anus(p2)) { ApplyDamage(p1, GetFingerSize(p1), Dyspareunia.GetVagina(p2) ?? Dyspareunia.GetAnus(p2), rape); } else { ApplyDamage(p2, GetFingerSize(p2), Dyspareunia.GetVagina(p1) ?? Dyspareunia.GetAnus(p1), false); } break; case xxx.rjwSextype.Fisting: if (Genital_Helper.has_vagina(p2) || Genital_Helper.has_anus(p2)) { ApplyDamage(p1, GetHandSize(p1), Dyspareunia.GetVagina(p2) ?? Dyspareunia.GetAnus(p2), rape); } else { ApplyDamage(p2, GetHandSize(p2), Dyspareunia.GetVagina(p1) ?? Dyspareunia.GetAnus(p1), false); } break; case xxx.rjwSextype.MechImplant: Dyspareunia.Log("Processing mech implant sex between " + p1.Label + " and " + p2.Label); if (p1.kindDef.race.defName.ContainsAny("Mech_Centipede", "Mech_Lancer", "Mech_Scyther", "Mech_Crawler", "Mech_Skullywag", "Mech_Flamebot", "Mech_Mammoth", "Mech_Assaulter")) { ApplyDamage(p1, p1.BodySize, Dyspareunia.GetVagina(p2) ?? Dyspareunia.GetAnus(p2), rape); } else { ApplyDamage(p2, p2.BodySize, Dyspareunia.GetVagina(p1) ?? Dyspareunia.GetAnus(p1), false); } break; } }