static void Addsemen(Pawn pawn) { //Log.Message("add s***n button is pressed for " + pawn); if (!pawn.Dead && pawn.records != null) { //get all acceptable body parts: IEnumerable <BodyPartRecord> filteredParts = SemenHelper.getAvailableBodyParts(pawn); //select random part: BodyPartRecord randomPart; //filteredParts.TryRandomElement<BodyPartRecord>(out randomPart); //for testing - choose either genitals or anus: //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.Value > 0.5f) { randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.anusDef); } else { randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.genitalsDef); } if (randomPart != null) { SemenHelper.cumOn(pawn, randomPart, 0.2f, null, SemenHelper.CUM_NORMAL); } } ; }
public override bool TryMergeWith(Hediff other) { //if a new S***n hediff is added to the same body part, they are combined. if severity reaches more than 1, spillover to other body parts occurs Hediff_Semen hediff_Semen = other as Hediff_Semen; if (hediff_Semen != null && hediff_Semen.def == this.def && hediff_Semen.Part == base.Part && this.def.injuryProps.canMerge) { semenType = hediff_Semen.semenType; //take over new creature color float totalAmount = hediff_Semen.Severity + this.Severity; if (totalAmount > 1.0f) { BodyPartDef spillOverTo = SemenHelper.spillover(this.Part.def); //SemenHelper saves valid other body parts for spillover if (spillOverTo != null) { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); IEnumerable <BodyPartRecord> availableParts = SemenHelper.getAvailableBodyParts(pawn); //gets all non missing, valid body parts IEnumerable <BodyPartRecord> filteredParts = availableParts.Where(x => x.def == spillOverTo); //filters again for valid spill target BodyPartRecord spillPart = filteredParts.RandomElement <BodyPartRecord>(); //then pick one if (spillPart != null) { SemenHelper.cumOn(pawn, spillPart, totalAmount - this.Severity, null, semenType); } } } return(base.TryMergeWith(other)); } return(false); }
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 } } } } } }