//roll how much gender fluid the pawn is. //In ideal world this would actually take into account from where to where transition is moving and so on. //Same applies to the thought hediffs themselves, but we get what we can get now static float RollSexChangeSeverity(Pawn pawn) { float res = 1; if (xxx.is_bisexual(pawn)) { res *= 0.5f; } if (pawn.story != null && (pawn.story.bodyType == BodyTypeDefOf.Thin || pawn.story.bodyType == BodyTypeDefOf.Fat)) { res *= 0.8f; } if (!pawn.ageTracker.CurLifeStage.reproductive) { res *= 0.2f; } else { res *= rigidity_from_age.Evaluate(SexUtility.ScaleToHumanAge(pawn)); } return(res); }
public static void calculateAndApplySemen(Pawn pawn, Pawn partner, xxx.rjwSextype sextype) { if (!RJWSettings.cum_on_body) { return; } Pawn giver, receiver; //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //dispenser of the seed if (Genital_Helper.has_penis(pawn) || xxx.is_mechanoid(pawn) || xxx.is_insect(pawn)) { giver = pawn; receiver = partner; } else if (partner != null && (Genital_Helper.has_penis(partner) || xxx.is_mechanoid(partner) || xxx.is_insect(partner))) { giver = partner; receiver = pawn; } else //female on female or genderless - no s***n dispensed; maybe add futa support? { return; } //slimes do not waste fluids? //if (xxx.is_slime(giver)) return; //determine entity: int entityType = SemenHelper.CUM_NORMAL; if (xxx.is_mechanoid(giver)) { entityType = SemenHelper.CUM_MECHA; } else if (xxx.is_insect(giver)) { entityType = SemenHelper.CUM_INSECT; } //get pawn genitalia: BodyPartRecord genitals; if (xxx.is_mechanoid(giver)) { genitals = giver.RaceProps.body.AllParts.Find(x => string.Equals(x.def.defName, "MechGenitals")); } else //insects, animals, humans { genitals = giver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef); } //no cum without genitals if (genitals == null) { return; } //calculate s***n amount: Need sexNeed = giver.needs.AllNeeds.Find(x => string.Equals(x.def.defName, "Sex")); float horniness = 1f; if (sexNeed != null) //non-humans don't have it - therefore just use the default value { horniness = 1f - sexNeed.CurLevel; } float ageScale = Math.Min(80 / SexUtility.ScaleToHumanAge(giver), 1.0f); //calculation lifted from rjw float cumAmount = horniness * giver.BodySize * ageScale * RJWSettings.cum_on_body_amount_adjust; ; if (xxx.has_quirk(giver, "Messy")) { cumAmount *= 1.5f; } //if no partner -> masturbation, apply some cum on self: //if (partner == null && sextype == xxx.rjwSextype.Autofellatio) //{ // if (!xxx.is_slime(giver)) // SemenHelper.cumOn(giver, BodyPartDefOf.Jaw, cumAmount, giver); // return; //} if (partner == null && sextype == xxx.rjwSextype.Masturbation) { if (!xxx.is_slime(giver)) { SemenHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver); //pawns are usually not super-messy -> only apply 30% } return; } else if (partner != null) { List <BodyPartRecord> targetParts = new List <BodyPartRecord>(); //which to apply s***n on IEnumerable <BodyPartRecord> availableParts = SemenHelper.getAvailableBodyParts(receiver); BodyPartRecord randomPart; //not always needed switch (sextype) { case rjw.xxx.rjwSextype.Anal: targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.anusDef)); break; case rjw.xxx.rjwSextype.Boobjob: targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.chestDef)); break; case rjw.xxx.rjwSextype.DoublePenetration: targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.anusDef)); targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef)); break; case rjw.xxx.rjwSextype.Fingering: cumAmount = 0; break; case rjw.xxx.rjwSextype.Fisting: cumAmount = 0; break; case rjw.xxx.rjwSextype.Footjob: //random part: availableParts.TryRandomElement <BodyPartRecord>(out randomPart); targetParts.Add(randomPart); break; case rjw.xxx.rjwSextype.Handjob: //random part: availableParts.TryRandomElement <BodyPartRecord>(out randomPart); targetParts.Add(randomPart); break; case rjw.xxx.rjwSextype.Masturbation: cumAmount *= 2f; break; case rjw.xxx.rjwSextype.MechImplant: //one of the openings: int random = Rand.Range(0, 3); if (random == 0) { targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef)); } else if (random == 1) { targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.anusDef)); } else if (random == 2) { targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Jaw)); } break; case rjw.xxx.rjwSextype.MutualMasturbation: //random availableParts.TryRandomElement <BodyPartRecord>(out randomPart); targetParts.Add(randomPart); break; case rjw.xxx.rjwSextype.None: cumAmount = 0; break; case rjw.xxx.rjwSextype.Oral: targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Jaw)); break; case rjw.xxx.rjwSextype.Scissoring: //I guess if it came to here, a male must be involved? targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef)); break; case rjw.xxx.rjwSextype.Vaginal: targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef)); break; } if (cumAmount > 0) { if (xxx.is_slime(receiver)) { //slime absorb cum //this needs balancing, since cumamount ranges 0-10(?) which is fine for cum/hentai but not very realistic for feeding //using TransferNutrition for now //Log.Message("cumAmount " + cumAmount); //float nutrition_amount = cumAmount/10; Need_Food need = need = giver.needs.TryGetNeed <Need_Food>(); if (need == null) { //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(pawn) + " doesn't track nutrition in itself, probably shouldn't feed the others"); return; } if (receiver?.needs?.TryGetNeed <Need_Food>() != null) { //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(partner) + " can receive"); float nutrition_amount = Math.Min(need.MaxLevel / 15f, need.CurLevel); //body size is taken into account implicitly by need.MaxLevel receiver.needs.food.CurLevel += nutrition_amount; } } else { SemenHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver, entityType); //cum on self - smaller amount foreach (BodyPartRecord bpr in targetParts) { if (bpr != null) { SemenHelper.cumOn(receiver, bpr, cumAmount, giver, entityType); //cum on partner } } } } } }
public static int WhoreMinPrice(Pawn w***e) { float min_price = 20f; min_price *= whoring_age_curve.Evaluate(SexUtility.ScaleToHumanAge(w***e)); if (xxx.has_traits(w***e)) { if (xxx.IndividualityIsActive && w***e.story.traits.HasTrait(xxx.SYR_Haggler)) { min_price *= 1.5f; } if (w***e.story.traits.DegreeOfTrait(TraitDefOf.Industriousness) == 2) // Industrious { min_price *= 1.5f; } if (w***e.story.traits.DegreeOfTrait(TraitDefOf.NaturalMood) == -2) // Depressive { min_price *= 0.5f; } if (w***e.story.traits.HasTrait(TraitDefOf.CreepyBreathing)) { min_price *= 0.75f; } //StatDef PawnBeauty if (w***e.story.traits.HasTrait(TraitDefOf.Beauty)) { switch (w***e.story.traits.DegreeOfTrait(TraitDefOf.Beauty)) { case 2: min_price *= 3f; break; case 1: min_price *= 1.5f; break; case -1: min_price *= 0.5f; break; case -2: min_price *= 0.2f; break; } } if (xxx.is_masochist(w***e)) // Won't haggle, may settle for low price { min_price *= 0.7f; } if (xxx.is_nympho(w***e)) // Same as above { min_price *= 0.4f; } } min_price *= WhoreInjuryAdjustment(w***e); if (w***e.ownership.OwnedRoom != null) { min_price *= WhoreRoomAdjustment(w***e); } return((int)min_price); }
public static int WhoreMaxPrice(Pawn w***e) { float max_price = 40f; max_price *= whoring_age_curve.Evaluate(SexUtility.ScaleToHumanAge(w***e)); if (w***e.gender == Gender.Female) { max_price *= 1.2f; } if (xxx.has_traits(w***e)) { if (w***e.story.traits.HasTrait(TraitDefOf.Greedy)) { max_price *= 2f; } if (xxx.IndividualityIsActive && w***e.story.traits.HasTrait(xxx.SYR_Haggler)) { max_price *= 1.5f; } if (w***e.story.traits.DegreeOfTrait(TraitDefOf.Industriousness) == 2) // Industrious { max_price *= 1.5f; } if (w***e.story.traits.DegreeOfTrait(TraitDefOf.Industriousness) == 1) // Hard Worker { max_price *= 1.2f; } if (w***e.story.traits.HasTrait(TraitDefOf.CreepyBreathing)) { max_price *= 0.75f; } if (w***e.story.traits.HasTrait(TraitDefOf.Beauty)) { switch (w***e.story.traits.DegreeOfTrait(TraitDefOf.Beauty)) { case 2: max_price *= 3.5f; break; case 1: max_price *= 2f; break; case -1: max_price *= 0.8f; break; case -2: max_price *= 0.6f; break; } } } max_price *= WhoreInjuryAdjustment(w***e); if (w***e.ownership.OwnedRoom != null) { max_price *= WhoreRoomAdjustment(w***e); } return((int)max_price); }
private static float GetAgeFactor(Pawn f****r, Pawn f****d, int p_age) { float age_factor; //The human age curve needs work. Currently pawns refuse to have sex with anyone over age of ~50 no matter what the other factors are, which is just silly... age_factor = f****d.gender == Gender.Male ? attractiveness_from_age_male.Evaluate(SexUtility.ScaleToHumanAge(f****d)) : attractiveness_from_age_female.Evaluate(SexUtility.ScaleToHumanAge(f****d)); //--Log.Message("would_fuck() - age_factor = " + age_factor.ToString()); if (xxx.is_animal(f****r)) { age_factor = 1.0f; //using flat factors, since human age is not comparable to animal ages } else if (xxx.is_animal(f****d)) { if (p_age <= 1 && f****d.RaceProps.lifeExpectancy > 8) { age_factor = 0.5f; } else { age_factor = 1.0f; } //--Log.Message("would_fuck() - animal age_factor = " + age_factor.ToString()); } if (Quirk.Gerontophile.IsSatisfiedBy(f****r, f****d)) { age_factor = 1.0f; } return(age_factor); }