protected override Job TryGiveJob(Pawn pawn) { //--Log.Message("[RJW] JobGiver_DoFappin::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called"); if (pawn.Drafted) { return(null); } if (!xxx.can_be_fucked(pawn) && !xxx.can_fuck(pawn)) { return(null); } // W****s only fap if frustrated, unless imprisoned. if ((SexUtility.ReadyForLovin(pawn) && (!xxx.is_whore(pawn) || pawn.IsPrisoner)) || xxx.is_frustrated(pawn)) { if (pawn.jobs.curDriver is JobDriver_LayDown && RJWPreferenceSettings.FapInBed) { Building_Bed bed = ((JobDriver_LayDown)pawn.jobs.curDriver).Bed; if (bed != null) { return(new Job(xxx.fappin, bed)); } } else if ((xxx.is_frustrated(pawn) || xxx.has_quirk(pawn, "Exhibitionist")) && RJWPreferenceSettings.FapEverywhere) { return(new Job(xxx.quickfap, FindFapLocation(pawn))); } } return(null); }
protected override Job TryGiveJob(Pawn pawn) { //Log.Message("[RJW] JobGiver_AIRapePrisoner::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called "); if (!xxx.can_rape(pawn)) { return(null); } if (SexUtility.ReadyForLovin(pawn) || xxx.is_hornyorfrustrated(pawn)) { // don't allow pawns marked as comfort prisoners to rape others if (xxx.is_healthy(pawn)) { Pawn prisoner = find_victim(pawn, pawn.Map); if (prisoner != null) { //--Log.Message("[RJW] JobGiver_RandomRape::TryGiveJob( " + xxx.get_pawnname(p) + " ) - found victim " + xxx.get_pawnname(prisoner)); return(JobMaker.MakeJob(xxx.RapeRandom, prisoner)); } } } return(null); }
protected override Job TryGiveJob(Pawn pawn) { // Most checks are done in ThinkNode_ConditionalNecro. // filter out necro for nymphs if (!RJWSettings.necrophilia_enabled) { return(null); } if (pawn.Drafted) { return(null); } //--Log.Message("[RJW] JobGiver_ViolateCorpse::TryGiveJob for ( " + xxx.get_pawnname(pawn) + " )"); if (SexUtility.ReadyForLovin(pawn) || xxx.is_hornyorfrustrated(pawn)) { //--Log.Message("[RJW] JobGiver_ViolateCorpse::TryGiveJob, can love "); if (!xxx.can_rape(pawn)) { return(null); } var target = find_corpse(pawn, pawn.Map); //--Log.Message("[RJW] JobGiver_ViolateCorpse::TryGiveJob - target is " + (target == null ? "NULL" : "Found")); if (target != null) { return(JobMaker.MakeJob(xxx.RapeCorpse, target)); } // Ticks should only be increased after successful sex. } return(null); }
public void Start() { if (Partner == null) //TODO: solo sex descriptions { isRape = false; isWhoring = false; //sexType = SexUtility.DetermineSextype(pawn, Partner, isRape, isWhoring, Partner); } else if (Partner.Dead) { isRape = true; isWhoring = false; sexType = SexUtility.DetermineSextype(pawn, Partner, isRape, isWhoring, Partner); } else if (Partner.jobs?.curDriver is JobDriver_SexBaseReciever) { (Partner.jobs.curDriver as JobDriver_SexBaseReciever).parteners.AddDistinct(pawn); (Partner.jobs.curDriver as JobDriver_SexBaseReciever).increase_time(duration); //prevent Receiver standing up and interrupting rape if (Partner.health.hediffSet.HasHediff(HediffDef.Named("Hediff_Submitting"))) { Partner.health.AddHediff(HediffDef.Named("Hediff_Submitting")); } //(Target.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Count; //TODO: add multipartner support so sex doesnt repeat, maybe, someday isRape = Partner?.CurJob.def == xxx.gettin_raped; isWhoring = pawn?.CurJob.def == xxx.whore_is_serving_visitors; sexType = SexUtility.DetermineSextype(pawn, Partner, isRape, isWhoring, Partner); } //Log.Message("sexType: " + sexType.ToString()); //props = new SexProps(pawn, Partener, sexType, isRape);//maybe merge everything into this ? }
public override void NeedInterval() //150 ticks between each calls from Pawn_NeedsTracker() { if (isInvisible) { return; // no caravans } if (needsex_tick <= 0) // every 10 ticks - real tick { std_updater.update(pawn); if (xxx.is_asexual(pawn)) { CurLevel = 0.5f; return; } //--Log.Message("[RJW]Need_Sex::NeedInterval is called0 - pawn is "+xxx.get_pawnname(pawn)); needsex_tick = needsex_tick_timer; if (!def.freezeWhileSleeping || pawn.Awake()) { var fall_per_call = 150 * needsex_tick_timer * fall_per_tick(pawn); CurLevel -= fall_per_call * xxx.get_sex_drive(pawn) * RJWSettings.sexneed_decay_rate; // Each day has 60000 ticks, each hour has 2500 ticks, so each hour has 50/3 calls, in other words, each call takes .06 hour. //Log.Message("[RJW] " + xxx.get_pawnname(pawn) + "'s sex need stats:: Decay/call: " + fall_per_call * decay_rate_modifier * xxx.get_sex_drive(pawn) + ", Cur.lvl: " + CurLevel + ", Dec. rate: " + decay_rate_modifier + ", Sex drive: " + xxx.get_sex_drive(pawn)); if (CurLevel < thresh_horny()) { SexUtility.OffsetPsyfocus(pawn, -0.01f); } if (CurLevel < thresh_frustrated() || CurLevel > thresh_ahegao()) { SexUtility.OffsetPsyfocus(pawn, -0.05f); } } //--Log.Message("[RJW]Need_Sex::NeedInterval is called1"); //If they need it, they should seek it if (CurLevel < thresh_horny() && (pawn.mindState.canLovinTick - Find.TickManager.TicksGame > 300)) { pawn.mindState.canLovinTick = Find.TickManager.TicksGame + 300; } // the bootstrap of the mapInjector will only be triggered once per visible pawn. if (!BootStrapTriggered) { //--Log.Message("[RJW]Need_Sex::NeedInterval::calling boostrap - pawn is " + xxx.get_pawnname(pawn)); xxx.bootstrap(pawn.Map); BootStrapTriggered = true; } } else { needsex_tick--; } //--Log.Message("[RJW]Need_Sex::NeedInterval is called2 - needsex_tick is "+needsex_tick); }
protected override IEnumerable <Toil> MakeNewToils() { //this.FailOn(() => PawnUtility.PlayerForcedJobNowOrSoon(pawn)); this.FailOn(() => pawn.health.Downed); this.FailOn(() => pawn.IsBurning()); this.FailOn(() => pawn.IsFighting()); this.FailOn(() => pawn.Drafted); //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); // Faster fapping when frustrated. ticks_left = (int)(xxx.need_some_sex(pawn) > 2f ? 2500.0f * Rand.Range(0.2f, 0.7f) : 2500.0f * Rand.Range(0.2f, 0.4f)); Toil findfapspot = new Toil { initAction = delegate { pawn.pather.StartPath(cell, PathEndMode.OnCell); }, defaultCompleteMode = ToilCompleteMode.PatherArrival }; yield return(findfapspot); //Log.Message("[RJW] Making new toil for QuickFap."); Toil fap = Toils_General.Wait(ticks_left); fap.tickAction = delegate { --ticks_left; xxx.reduce_rest(pawn, 1); if (ticks_left <= 0) { ReadyForNextToil(); } else if (pawn.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } }; fap.AddFinishAction(delegate { SexUtility.Aftersex(pawn, xxx.rjwSextype.Masturbation); if (!SexUtility.ConsiderCleaning(pawn)) { return; } LocalTargetInfo own_cum = pawn.PositionHeld.GetFirstThing <Filth>(pawn.Map); Job clean = new Job(JobDefOf.Clean); clean.AddQueuedTarget(TargetIndex.A, own_cum); pawn.jobs.jobQueue.EnqueueFirst(clean); }); yield return(fap); }
protected override IEnumerable <Toil> MakeNewToils() { //--Log.Message("JobDriver_JoinInBed::MakeNewToils() called"); this.FailOnDespawnedOrNull(ipartner); this.FailOnDespawnedOrNull(ibed); this.FailOn(() => !Partner.health.capacities.CanBeAwake); this.FailOn(() => !(Partner.InBed() || xxx.in_same_bed(Partner, Top))); this.FailOn(() => pawn.Drafted); yield return(Toils_Reserve.Reserve(ipartner, xxx.max_rapists_per_prisoner, 0)); yield return(Toils_Goto.GotoThing(ipartner, PathEndMode.OnCell)); yield return(new Toil { initAction = delegate { //--Log.Message("JobDriver_JoinInBed::MakeNewToils() - setting initAction"); //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticks_left = (int)(2500.0f * Rand.Range(0.30f, 1.30f)); Job gettin_loved = new Job(xxx.gettin_loved, Top, Bed); Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); }, defaultCompleteMode = ToilCompleteMode.Instant }); Toil do_lovin = new Toil { defaultCompleteMode = ToilCompleteMode.Never }; do_lovin.FailOn(() => (Partner.CurJob == null) || (Partner.CurJob.def != xxx.gettin_loved)); do_lovin.AddPreTickAction(delegate { --ticks_left; xxx.reduce_rest(Partner, 1); xxx.reduce_rest(Top, 2); if (ticks_left <= 0) { ReadyForNextToil(); } else if (Top.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(Top.Position, Top.Map, ThingDefOf.Mote_Heart); } }); do_lovin.socialMode = RandomSocialMode.Off; yield return(do_lovin); yield return(new Toil { initAction = delegate { // Trying to add some interactions and social logs SexUtility.ProcessSex(Top, Partner, false /*rape*/, false /*isCoreLovin*/, false /*whoring*/); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override Job TryGiveJob(Pawn pawn) { //Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called0"); if (!RJWSettings.WildMode) { // don't allow pawns marked as comfort prisoners to rape others if (!xxx.is_healthy(pawn) || pawn.IsDesignatedComfort() || (!SexUtility.ReadyForLovin(pawn) && !xxx.is_frustrated(pawn))) { return(null); } } if (pawn.Drafted) { return(null); } //Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called1"); if (!xxx.can_rape(pawn)) { return(null); } // It's unnecessary to include other job checks. Pawns seem to only look for new jobs when between jobs or layind down idle. if (!(pawn.jobs.curJob == null || pawn.jobs.curJob.def == JobDefOf.LayDown)) { return(null); } //--Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called2"); // Faction check. if (!(pawn.Faction?.IsPlayer ?? false) && !pawn.IsPrisonerOfColony) { return(null); } Pawn target = find_prisoner_to_rape(pawn, pawn.Map); //--Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called3 - (" + ((target == null) ? "no target found" : xxx.get_pawnname(target))+") is the prisoner"); if (target == null) { return(null); } //Log.Message("giving job to " + pawner + " with target " + target); if (xxx.is_animal(target)) { return(new Job(xxx.bestiality, target)); } else { return(new Job(xxx.comfort_prisoner_rapin, target)); } }
public static void sexualize_pawn(Pawn pawn) { //Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) called"); if (pawn == null) { return; } if (RaceGroupDef_Helper.TryGetRaceGroupDef(pawn, out var raceGroupDef) && raceGroupDef.hasSingleGender) { Log.Message($"[RJW] sexualize_pawn() - sexualizing single gender pawn {xxx.get_pawnname(pawn)} race: {raceGroupDef.defName}"); SexualizeSingleGenderPawn(pawn); } else if (pawn.RaceProps.hasGenders) { SexualizeGenderedPawn(pawn); } else { if (Current.ProgramState == ProgramState.Playing) // DO NOT run at world generation, throws error in generating relationship stuff { SexulaizeGenderlessPawn(pawn); return; } } if (!pawn.Dead) { //Add ticks at generation, so pawns don't instantly start lovin' when generated (esp. on scenario start). //if (xxx.RoMIsActive && pawn.health.hediffSet.HasHediff(HediffDef.Named("TM_ShapeshiftHD"))) // Rimworld of Magic's polymorph/shapeshift // pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.01f, 0.05f)); if (!xxx.is_insect(pawn)) { pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.1f, 1.0f)); } else { pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.01f, 0.2f)); } //Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) add sexneed"); if (pawn.RaceProps.Humanlike) { var sex_need = pawn.needs.TryGetNeed <Need_Sex>(); if (pawn.Faction != null && !(pawn.Faction?.IsPlayer ?? false) && sex_need != null) { sex_need.CurLevel = Rand.Range(0.01f, 0.75f); } } } }
/// <summary> /// handle Psyfocus /// </summary> public void ChangePsyfocus(Pawn pawn, Thing target) { if (pawn.jobs?.curDriver is JobDriver_ViolateCorpse) { if (xxx.is_necrophiliac(pawn) && MeditationFocusTypeAvailabilityCache.PawnCanUse(pawn, DefDatabase <MeditationFocusDef> .GetNamedSilentFail("Morbid"))) { SexUtility.OffsetPsyfocus(pawn, 0.01f); } } if (target != null) { var partner = target as Pawn; if (partner != null) { if (xxx.is_nympho(pawn)) { SexUtility.OffsetPsyfocus(pawn, 0.01f); } else if (xxx.is_zoophile(pawn) && xxx.is_animal(partner) && MeditationFocusTypeAvailabilityCache.PawnCanUse(pawn, MeditationFocusDefOf.Natural)) { SexUtility.OffsetPsyfocus(pawn, 0.01f); } if (xxx.is_nympho(partner)) { SexUtility.OffsetPsyfocus(partner, 0.01f); } else if (xxx.is_zoophile(partner) && xxx.is_animal(pawn) && MeditationFocusTypeAvailabilityCache.PawnCanUse(partner, MeditationFocusDefOf.Natural)) { SexUtility.OffsetPsyfocus(partner, 0.01f); } if (xxx.RoMIsActive) { if (pawn.story.traits.HasTrait(TraitDef.Named("Succubus"))) { SexUtility.OffsetPsyfocus(pawn, 0.01f); } if (partner.story.traits.HasTrait(TraitDef.Named("Succubus"))) { SexUtility.OffsetPsyfocus(partner, 0.01f); } } } } }
protected override IEnumerable <Toil> MakeNewToils() { // Faster fapping when frustrated. //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticks_left = (int)(xxx.need_some_sex(pawn) > 2f ? 2500.0f * Rand.Range(0.2f, 0.7f) : 2500.0f * Rand.Range(0.2f, 0.4f)); this.FailOnDespawnedOrNull(ibed); this.FailOn(() => pawn.Drafted); this.KeepLyingDown(ibed); yield return(Toils_Bed.ClaimBedIfNonMedical(ibed)); yield return(Toils_Bed.GotoBed(ibed)); Toil do_fappin = Toils_LayDown.LayDown(ibed, true, false, false, false); do_fappin.AddPreTickAction(delegate { --ticks_left; xxx.reduce_rest(pawn, 1); if (ticks_left <= 0) { ReadyForNextToil(); } else if (pawn.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } }); do_fappin.AddFinishAction(delegate { //Moved satisfy and tick increase to aftersex, since it works with solo acts now. SexUtility.Aftersex(pawn, xxx.rjwSextype.Masturbation); if (SexUtility.ConsiderCleaning(pawn)) { LocalTargetInfo own_cum = pawn.PositionHeld.GetFirstThing <Filth>(pawn.Map); Job clean = new Job(JobDefOf.Clean); clean.AddQueuedTarget(TargetIndex.A, own_cum); pawn.jobs.jobQueue.EnqueueFirst(clean); } }); do_fappin.socialMode = RandomSocialMode.Off; yield return(do_fappin); }
protected override Job TryGiveJob(Pawn pawn) { // Most things are now checked in the ThinkNode_ConditionalWhore. if (pawn.Drafted) { return(null); } if (MP.IsInMultiplayer) { return(null); //fix error someday, maybe } //Log.Message("[RJW] JobGiver_WhoreInvitingVisitors::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called"); if (!SexUtility.ReadyForLovin(pawn)) { //W****s need rest too, but this'll reduxe the wait a bit every it triggers. pawn.mindState.canLovinTick -= 40; return(null); } Building_Bed whorebed = xxx.FindBed(pawn); if (whorebed == null || !xxx.CanUse(pawn, whorebed)) { return(null); } int price; Pawn client = FindAttractivePawn(pawn, out price); if (client == null) { return(null); } if (!client.CanReach(whorebed, PathEndMode.OnCell, Danger.Some)) { return(null); } //Log.Message("[RJW] JobGiver_WhoreInvitingVisitors::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) is w***e, " + xxx.get_pawnname(client) + " is client."); //whorebed.priceOfWhore = price; return(new Job(xxx.whore_inviting_visitors, client, whorebed)); }
protected override Job TryGiveJob(Pawn pawn) { if (pawn.Drafted) { return(null); } // Most checks are now done in ThinkNode_ConditionalBestiality DebugText("[RJW] JobGiver_Bestiality::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called"); if (!SexUtility.ReadyForLovin(pawn) && !xxx.is_frustrated(pawn)) { return(null); } Pawn target = BreederHelper.find_breeder_animal(pawn, pawn.Map); DebugText("[RJW] JobGiver_Bestiality::TryGiveJob - target is " + (target == null ? "no target found" : xxx.get_pawnname(target))); if (target == null) { return(null); } if (xxx.can_rape(pawn)) { return(new Job(xxx.bestiality, target)); } Building_Bed bed = pawn.ownership.OwnedBed; if (!xxx.can_be_fucked(pawn) || bed == null || !target.CanReach(bed, PathEndMode.OnCell, Danger.Some) || target.Downed) { return(null); } // TODO: Should rename this to BestialityInBed or somesuch, since it's not limited to females. return(new Job(xxx.bestialityForFemale, target, bed, bed.SleepPosOfAssignedPawn(pawn))); }
protected override Job TryGiveJob(Pawn animal) { //Log.Message("[RJW] JobGiver_Breed::TryGiveJob( " + xxx.get_pawnname(animal) + " ) called0" + (SexUtility.ReadyForLovin(animal))); if (!SexUtility.ReadyForLovin(animal)) { return(null); } if (xxx.is_healthy(animal) && xxx.can_rape(animal)) { //search for desiganted target to sex if (animal.IsDesignatedBreedingAnimal()) { Pawn designated_target = BreederHelper.find_designated_breeder(animal, animal.Map); if (designated_target != null) { return(JobMaker.MakeJob(xxx.animalBreed, designated_target)); } } } return(null); }
//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 void SexTick(Pawn pawn, Thing target, bool pawnnude = true, bool partnernude = true) { var partner = target as Pawn; if (pawn.IsHashIntervalTick(ticks_between_thrusts)) { ChangePsyfocus(pawn, partner); Animate(pawn, partner); PlaySexSound(); if (!isRape) { pawn.GainComfortFromCellIfPossible(); if (partner != null) { partner.GainComfortFromCellIfPossible(); } } } //refresh DrawNude after beating and Notify_MeleeAttackOn // Endytophiles prefer clothed sex, everyone else gets nude. if (!xxx.has_quirk(pawn, "Endytophile")) { if (pawnnude) { SexUtility.DrawNude(pawn); } if (partner != null) { if (partnernude) { SexUtility.DrawNude(partner); } } } }
protected override Job TryGiveJob(Pawn pawn) { if (pawn.Drafted) { return(null); } // Most checks are now done in ThinkNode_ConditionalBestiality if (!SexUtility.ReadyForLovin(pawn) && !xxx.is_frustrated(pawn)) { return(null); } Pawn target = BreederHelper.find_breeder_animal(pawn, pawn.Map); if (target == null) { return(null); } if (xxx.can_rape(pawn)) { return(JobMaker.MakeJob(xxx.bestiality, target)); } Building_Bed bed = pawn.ownership.OwnedBed; if (!xxx.can_be_fucked(pawn) || bed == null || !target.CanReach(bed, PathEndMode.OnCell, Danger.Some) || target.Downed) { return(null); } // TODO: Should rename this to BestialityInBed or somesuch, since it's not limited to females. return(JobMaker.MakeJob(xxx.bestialityForFemale, target, bed)); }
protected override Job TryGiveJob(Pawn pawn) { // Most things are now checked in the ThinkNode_ConditionalWhore. if (pawn.Drafted) { return(null); } if (MP.IsInMultiplayer) { return(null); //fix error someday, maybe } if (!SexUtility.ReadyForLovin(pawn)) { //W****s need rest too, but this'll reduxe the wait a bit every it triggers. pawn.mindState.canLovinTick -= 40; return(null); } if (RJWSettings.DebugWhoring) { Log.Message($"[RJW] JobGiver_WhoreInvitingVisitors.TryGiveJob:({xxx.get_pawnname(pawn)})"); } Building_Bed whorebed = xxx.FindBed(pawn); if (whorebed == null || !xxx.CanUse(pawn, whorebed)) { if (RJWSettings.DebugWhoring) { Log.Message($" {xxx.get_pawnname(pawn)} has no bed or can use it"); } return(null); } int price; Pawn client = FindAttractivePawn(pawn, out price); if (client == null) { if (RJWSettings.DebugWhoring) { Log.Message($" no clients found"); } return(null); } if (RJWSettings.DebugWhoring) { Log.Message($" {xxx.get_pawnname(client)} is client"); } if (!client.CanReach(whorebed, PathEndMode.OnCell, Danger.Some)) { if (RJWSettings.DebugWhoring) { Log.Message($" {xxx.get_pawnname(client)} cant reach bed"); } return(null); } //whorebed.priceOfWhore = price; return(JobMaker.MakeJob(xxx.whore_inviting_visitors, client, whorebed)); }
public static void Doimpregnate(Pawn pawn, Pawn partner) { if (RJWSettings.DevMode) { Log.Message("[RJW] Doimpregnate " + xxx.get_pawnname(pawn) + " is a father, " + xxx.get_pawnname(partner) + " is a mother"); } if (AndroidsCompatibility.IsAndroid(pawn) && !AndroidsCompatibility.AndroidPenisFertility(pawn)) { if (RJWSettings.DevMode) { Log.Message(" Father is android with no arcotech penis, abort"); } return; } if (AndroidsCompatibility.IsAndroid(partner) && !AndroidsCompatibility.AndroidVaginaFertility(partner)) { if (RJWSettings.DevMode) { Log.Message(" Mother is android with no arcotech v****a, abort"); } return; } // fertility check float fertility = RJWPregnancySettings.humanlike_impregnation_chance / 100f; if (xxx.is_animal(partner)) { fertility = RJWPregnancySettings.animal_impregnation_chance / 100f; } // Interspecies modifier if (pawn.def.defName != partner.def.defName) { if (RJWPregnancySettings.complex_interspecies) { fertility *= SexUtility.BodySimilarity(pawn, partner); } else { fertility *= RJWPregnancySettings.interspecies_impregnation_modifier; } } //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float ReproductionFactor = Math.Min(pawn.health.capacities.GetLevel(xxx.reproduction), partner.health.capacities.GetLevel(xxx.reproduction)); float pregnancy_threshold = fertility * ReproductionFactor; float non_pregnancy_chance = Rand.Value; BodyPartRecord torso = partner.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Torso); if (non_pregnancy_chance > pregnancy_threshold || pregnancy_threshold == 0) { if (RJWSettings.DevMode) { Log.Message(" Impregnation failed. Chance: " + pregnancy_threshold.ToStringPercent() + " roll: " + non_pregnancy_chance.ToStringPercent()); } return; } if (RJWSettings.DevMode) { Log.Message(" Impregnation succeeded. Chance: " + pregnancy_threshold.ToStringPercent() + " roll: " + non_pregnancy_chance.ToStringPercent()); } PregnancyDecider(partner, pawn); }
protected override IEnumerable <Toil> MakeNewToils() { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - making toils"); this.FailOnDespawnedOrNull(PartnerInd); this.FailOnDespawnedNullOrForbidden(BedInd); //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() fail conditions check " + (Actor is null) + " " + !xxx.CanUse(Actor, Bed) + " " + !Actor.CanReserve(Partner)); this.FailOn(() => Actor is null || !xxx.CanUse(Actor, Bed) || !Actor.CanReserve(Partner)); this.FailOn(() => pawn.Drafted); int price = WhoringHelper.PriceOfWhore(Actor); yield return(Toils_Reserve.Reserve(PartnerInd, 1, 0)); //yield return Toils_Reserve.Reserve(BedInd, Bed.SleepingSlotsCount, 0); bool partnerHasPenis = Genital_Helper.has_penis(Partner) || Genital_Helper.has_penis_infertile(Partner); Toil gotoWhoreBed = new Toil { initAction = delegate { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - gotoWhoreBed initAction is called"); Actor.pather.StartPath(WhoreSleepSpot, PathEndMode.OnCell); Partner.jobs.StopAll(); Partner.pather.StartPath(WhoreSleepSpot, PathEndMode.Touch); }, tickAction = delegate { if (Partner.IsHashIntervalTick(150)) { Partner.pather.StartPath(Actor, PathEndMode.Touch); //Log.Message(xxx.get_pawnname(Partner) + ": I'm following the w***e"); } }, defaultCompleteMode = ToilCompleteMode.PatherArrival }; gotoWhoreBed.FailOnWhorebedNoLongerUsable(BedInd, Bed); yield return(gotoWhoreBed); Toil waitInBed = new Toil { initAction = delegate { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - waitInBed, initAction is called"); ticksLeftThisToil = 5000; ticks_left = (int)(2000.0f * Rand.Range(0.30f, 1.30f)); //Actor.pather.StopDead(); //Let's just make w****s standing at the bed //JobDriver curDriver = Actor.jobs.curDriver; //curDriver.layingDown = LayingDownState.LayingInBed; //curDriver.asleep = false; var gettin_loved = new Job(xxx.gettin_loved, Actor, Bed); Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); }, tickAction = delegate { Actor.GainComfortFromCellIfPossible(); if (IsInOrByBed(Bed, Partner)) { //Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - waitInBed, tickAction pass"); ticksLeftThisToil = 0; } }, defaultCompleteMode = ToilCompleteMode.Delay, }; waitInBed.FailOn(() => pawn.GetRoom() == null); yield return(waitInBed); bool canAfford = WhoringHelper.CanAfford(Partner, Actor, price); if (canAfford) { Toil loveToil = new Toil { initAction = delegate { //Actor.jobs.curDriver.ticksLeftThisToil = 1200; //Using ticks_left to control the time of sex //--Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - loveToil, setting initAction"); /* * //Hoge: W***e is just work. no feel cheatedOnMe. * if (xxx.HasNonPolyPartner(Actor)) * { * Pawn pawn = LovePartnerRelationUtility.ExistingLovePartner(Actor); * if (((Partner != pawn) && !pawn.Dead) && ((pawn.Map == Actor.Map) || (Rand.Value < 0.15))) * { * pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, Actor); * } * } */ if (xxx.HasNonPolyPartnerOnCurrentMap(Partner)) { Pawn lover = LovePartnerRelationUtility.ExistingLovePartner(Partner); //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); // We have to do a few other checks because the pawn might have multiple lovers and ExistingLovePartner() might return the wrong one if (lover != null && Actor != lover && !lover.Dead && (lover.Map == Partner.Map || Rand.Value < 0.25)) { lover.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, Partner); } } if (!partnerHasPenis) { Actor.rotationTracker.Face(Partner.DrawPos); } }, defaultCompleteMode = ToilCompleteMode.Never, //Changed from Delay }; loveToil.AddPreTickAction(delegate { //Actor.Reserve(Partner, 1, 0); --ticks_left; xxx.reduce_rest(Partner); xxx.reduce_rest(Actor, 2); if (ticks_left <= 0) { ReadyForNextToil(); } else if (pawn.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(Actor.Position, Actor.Map, ThingDefOf.Mote_Heart); } Actor.GainComfortFromCellIfPossible(); Partner.GainComfortFromCellIfPossible(); }); loveToil.AddFinishAction(delegate { //Log.Message("[RJW] JobDriver_WhoreIsServingVisitors::MakeNewToils() - finished loveToil"); //// Trying to add some interactions and social logs //xxx.processAnalSex(Partner, Actor, ref isAnalSex, partnerHasPenis); }); loveToil.AddFailCondition(() => Partner.Dead || !IsInOrByBed(Bed, Partner)); loveToil.socialMode = RandomSocialMode.Off; yield return(loveToil); Toil afterSex = new Toil { initAction = delegate { // Adding interactions, social logs, etc SexUtility.ProcessSex(Actor, Partner, false, false, true); //--Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Partner should pay the price now in afterSex.initAction"); int remainPrice = WhoringHelper.PayPriceToWhore(Partner, price, Actor); /*if (remainPrice <= 0) * { * --Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Paying price is success"); * } * else * { * --Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Paying price failed"); * }*/ xxx.UpdateRecords(Actor, price - remainPrice); var thought = (Actor.IsPrisoner) ? thought_captive : thought_free; pawn.needs.mood.thoughts.memories.TryGainMemory(thought); if (SexUtility.ConsiderCleaning(pawn)) { LocalTargetInfo cum = pawn.PositionHeld.GetFirstThing <Filth>(pawn.Map); Job clean = new Job(JobDefOf.Clean); clean.AddQueuedTarget(TargetIndex.A, cum); pawn.jobs.jobQueue.EnqueueFirst(clean); } }, defaultCompleteMode = ToilCompleteMode.Instant }; yield return(afterSex); } }
protected override IEnumerable <Toil> MakeNewToils() { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); int duration = (int)(2000.0f * Rand.Range(0.50f, 0.90f)); int ticks_between_hearts = Rand.RangeInclusive(70, 130); int ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); int ticks_between_thrusts = 100; //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - setting fail conditions"); this.FailOnDespawnedNullOrForbidden(PartnerIndex); this.FailOn(() => !pawn.CanReserve(Target, BreederHelper.max_animals_at_once, 0)); // Fail if someone else reserves the target before the animal arrives. this.FailOn(() => !pawn.CanReach(Target, PathEndMode.Touch, Danger.Some)); // Fail if animal cannot reach target. this.FailOn(() => !(Target.IsDesignatedBreeding() || (RJWSettings.animal_on_animal_enabled && xxx.is_animal(Target)))); // Fail if not designated and not animal-on-animal this.FailOn(() => Target.CurJob == null); this.FailOn(() => pawn.Drafted); // Path to target yield return(Toils_Goto.GotoThing(PartnerIndex, PathEndMode.OnCell)); SexUtility.RapeAttemptAlert(pawn, Target); // Breed target var breed = new Toil(); breed.initAction = delegate { //Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Setting victim job driver"); Job currentJob = Target.jobs.curJob; if (currentJob.def != xxx.gettin_raped) { Job gettin_raped = new Job(xxx.gettin_raped, pawn, Target); Building_Bed Bed = null; //Log.Message(xxx.get_pawnname(pawn) + " LayingInBed:" + pawn.GetPosture()); //Log.Message(xxx.get_pawnname(Target) + " LayingInBed:" + Target.GetPosture()); if (Target.GetPosture() == PawnPosture.LayingInBed) { Bed = Target.CurrentBed(); //Log.Message(xxx.get_pawnname(Target) + ": bed:" + Bed); } Target.jobs.StartJob(gettin_raped, JobCondition.InterruptForced); //var dri = Target.jobs.curDriver as JobDriver_GettinRaped; //if (xxx.is_animal(pawn) && xxx.is_animal(Target)) // No alert spam for animal-on-animal //dri.disable_alert = true; (Target.jobs.curDriver as JobDriver_GettinRaped).increase_time(duration); if (Bed != null) { (Target.jobs.curDriver as JobDriver_GettinRaped)?.set_bed(Bed); } } else { if (Target.jobs.curDriver is JobDriver_GettinRaped dri) { dri.rapist_count += 1; dri.increase_time(duration); } } }; breed.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } if (pawn.IsHashIntervalTick(ticks_between_thrusts)) { xxx.sexTick(pawn, Target); } if (!xxx.is_zoophile(Target) && pawn.IsHashIntervalTick(ticks_between_hits)) { roll_to_hit(pawn, Target); } if (!Target.Dead) { xxx.reduce_rest(Target, 1); } xxx.reduce_rest(pawn, 2); if (Genital_Helper.has_penis(pawn) || Genital_Helper.has_penis_infertile(pawn)) { // Face same direction, most of animal sex is likely doggystyle. Target.Rotation = pawn.Rotation; } }; breed.AddFinishAction(delegate { if ((Target.jobs != null) && (Target.jobs.curDriver != null) && (Target.jobs.curDriver as JobDriver_GettinRaped != null)) { (Target.jobs.curDriver as JobDriver_GettinRaped).rapist_count -= 1; } pawn.stances.StaggerFor(Rand.Range(0, 50)); Target.stances.StaggerFor(Rand.Range(10, 300)); }); breed.defaultCompleteMode = ToilCompleteMode.Delay; breed.defaultDuration = duration; yield return(breed); yield return(new Toil { initAction = delegate { //Log.Message("JobDriver_Breeding::MakeNewToils() - Calling aftersex"); //// Trying to add some interactions and social logs bool violent = !(pawn.relations.DirectRelationExists(PawnRelationDefOf.Bond, Target) || (xxx.is_animal(pawn) && (pawn.RaceProps.wildness - pawn.RaceProps.petness + 0.18f) > Rand.Range(0.36f, 1.8f))); SexUtility.ProcessSex(pawn, Target, violent); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
private static bool on_cleanup_driver(JobDriver __instance, JobCondition condition) { if (__instance == null) { return(true); } if (condition == JobCondition.Succeeded) { Pawn pawn = __instance.pawn; Pawn partner = null; //Log.Message("[RJW]patches_lovin::on_cleanup_driver" + xxx.get_pawnname(pawn)); //[RF] Rational Romance [1.0] loving if (xxx.RomanceDiversifiedIsActive && __instance.GetType() == JobDriverDoLovinCasual) { // not sure RR can even cause pregnancies but w/e var any_ins = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; partner = (Pawn)(__instance.GetType().GetProperty("Partner", any_ins).GetValue(__instance, null)); Log.Message("[RJW]patches_lovin::on_cleanup_driver RomanceDiversified/RationalRomance:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner)); } //Vanilla loving else if (__instance.GetType() == JobDriverLovin) { var any_ins = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; partner = (Pawn)(__instance.GetType().GetProperty("Partner", any_ins).GetValue(__instance, null)); //CnP loving if (xxx.RimWorldChildrenIsActive && RJWPregnancySettings.humanlike_pregnancy_enabled && xxx.is_human(pawn) && xxx.is_human(partner)) { Log.Message("[RJW]patches_lovin:: RimWorldChildren/ChildrenAndPregnancy pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner)); PregnancyHelper.cleanup_CnP(pawn); PregnancyHelper.cleanup_CnP(partner); } else { Log.Message("[RJW]patches_lovin:: JobDriverLovin pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner)); } } //Vanilla mating else if (__instance.GetType() == JobDriverMate) { var any_ins = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; partner = (Pawn)(__instance.GetType().GetProperty("Female", any_ins).GetValue(__instance, null)); Log.Message("[RJW]patches_lovin:: JobDriverMate pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner)); } else { return(true); } // TODO: Doing TryUseCondom here is a bit weird... it should happen before. var usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(partner); //vanilla will probably be f****d up for non humanlikes... but only humanlikes do loving, right? //if rjw pregnancy enabled, remove vanilla for: //human-human //animal-animal //bestiality //always remove when someone is insect or mech if (RJWPregnancySettings.humanlike_pregnancy_enabled && xxx.is_human(pawn) && xxx.is_human(partner) || RJWPregnancySettings.animal_pregnancy_enabled && xxx.is_animal(pawn) && xxx.is_animal(partner) || (RJWPregnancySettings.bestial_pregnancy_enabled && xxx.is_human(pawn) && xxx.is_animal(partner) || RJWPregnancySettings.bestial_pregnancy_enabled && xxx.is_animal(pawn) && xxx.is_human(partner)) || xxx.is_insect(pawn) || xxx.is_insect(partner) || xxx.is_mechanoid(pawn) || xxx.is_mechanoid(partner) ) { Log.Message("[RJW]patches_lovin::on_cleanup_driver vanilla pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner)); PregnancyHelper.cleanup_vanilla(pawn); PregnancyHelper.cleanup_vanilla(partner); } SexUtility.ProcessSex(pawn, partner, usedCondom, false, true); } return(true); }
protected override IEnumerable <Toil> MakeNewToils() { //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called"); setup_ticks(); this.FailOnDespawnedNullOrForbidden(iTarget); this.FailOn(() => !pawn.CanReserve(Partner, xxx.max_rapists_per_prisoner, 0)); // Fail if someone else reserves the prisoner before the pawn arrives this.FailOn(() => pawn.IsFighting()); this.FailOn(() => Partner.IsFighting()); this.FailOn(() => pawn.Drafted); yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); SexUtility.RapeTargetAlert(pawn, Partner); Toil StartPartnerJob = new Toil(); StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; StartPartnerJob.socialMode = RandomSocialMode.Off; StartPartnerJob.initAction = delegate { var dri = Partner.jobs.curDriver as JobDriver_SexBaseRecieverRaped; if (dri == null) { Job gettin_raped = JobMaker.MakeJob(xxx.gettin_raped, pawn); Building_Bed Bed = null; if (Partner.GetPosture() == PawnPosture.LayingInBed) { Bed = Partner.CurrentBed(); } Partner.jobs.StartJob(gettin_raped, JobCondition.InterruptForced, null, false, true, null); if (Bed != null) { (Partner.jobs.curDriver as JobDriver_SexBaseRecieverRaped)?.Set_bed(Bed); } } }; yield return(StartPartnerJob); var rape = new Toil(); rape.FailOn(() => Partner.CurJob == null || Partner.CurJob.def != xxx.gettin_raped || Partner.IsFighting() || pawn.IsFighting()); rape.defaultCompleteMode = ToilCompleteMode.Delay; rape.defaultDuration = duration; rape.handlingFacing = true; rape.initAction = delegate { Start(); }; rape.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) { ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } if (pawn.IsHashIntervalTick(ticks_between_hits)) { Roll_to_hit(pawn, Partner); } SexTick(pawn, Partner); SexUtility.reduce_rest(Partner, 1); SexUtility.reduce_rest(pawn, 2); }; rape.AddFinishAction(delegate { End(); }); yield return(rape); yield return(new Toil { initAction = delegate { //// Trying to add some interactions and social logs SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, sextype: sexType); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override Job TryGiveJob(Pawn pawn) { //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called0"); //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 0 " + SexUtility.ReadyForLovin(pawn)); //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 1 " + (xxx.need_some_sex(pawn) <= 1f)); //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 2 " + !(SexUtility.ReadyForLovin(pawn) || xxx.need_some_sex(pawn) <= 1f)); //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 1 " + Find.TickManager.TicksGame); //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 2 " + pawn.mindState.canLovinTick); if (pawn.Drafted) { return(null); } if (pawn.health.hediffSet.HasHediff(HediffDef.Named("Hediff_RapeEnemyCD")) || !pawn.health.capacities.CanBeAwake || !(SexUtility.ReadyForLovin(pawn) || xxx.need_some_sex(pawn) <= 1f)) { //if (pawn.health.hediffSet.HasHediff(HediffDef.Named("Hediff_RapeEnemyCD")) || !pawn.health.capacities.CanBeAwake || (SexUtility.ReadyForLovin(pawn) || xxx.is_human(pawn) ? xxx.need_some_sex(pawn) <= 1f : false)) return(null); } if (!xxx.can_rape(pawn)) { return(null); } //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) can rape"); JobDef_RapeEnemy rapeEnemyJobDef = null; int?highestPriority = null; foreach (JobDef_RapeEnemy job in DefDatabase <JobDef_RapeEnemy> .AllDefs) { if (job.CanUseThisJobForPawn(pawn)) { if (highestPriority == null) { rapeEnemyJobDef = job; highestPriority = job.priority; } else if (job.priority > highestPriority) { rapeEnemyJobDef = job; highestPriority = job.priority; } } } //Log.Message("[RJW] JobGiver_RapeEnemy::ChoosedJobDef( " + xxx.get_pawnname(pawn) + " ) - " + rapeEnemyJobDef.ToString() + " choosed"); Pawn victim = rapeEnemyJobDef?.FindVictim(pawn, pawn.Map); //Log.Message("[RJW] JobGiver_RapeEnemy::FoundVictim( " + xxx.get_pawnname(victim) + " )"); //prevents 10 job stacks error, no idea whats the prob with JobDriver_Rape //if (victim != null) pawn.health.AddHediff(HediffDef.Named("Hediff_RapeEnemyCD"), null, null, null); return(victim != null ? new Job(rapeEnemyJobDef, victim) : null); /* * else * { * //--Log.Message("[RJW]" + this.GetType().ToString() + "::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) - unable to find victim"); * pawn.mindState.canLovinTick = Find.TickManager.TicksGame + Rand.Range(75, 150); * } */ //else { //--Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) - too fast to play next"); } }
protected override IEnumerable <Toil> MakeNewToils() { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); duration = (int)(2000.0f * Rand.Range(0.50f, 0.90f)); ticks_between_hearts = Rand.RangeInclusive(70, 130); ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); ticks_between_thrusts = 100; bool pawnHasPenis = Genital_Helper.has_penis(pawn) || Genital_Helper.has_penis_infertile(pawn); if (xxx.is_bloodlust(pawn)) { ticks_between_hits = (int)(ticks_between_hits * 0.75); } if (xxx.is_brawler(pawn)) { ticks_between_hits = (int)(ticks_between_hits * 0.90); } //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - setting fail conditions"); this.FailOnDespawnedNullOrForbidden(iprisoner); //this.FailOn(() => (!Target.health.capacities.CanBeAwake) || (!comfort_prisoners.is_designated(Target)));//this is wrong this.FailOn(() => (!Target.IsDesignatedComfort())); this.FailOn(() => !pawn.CanReserve(Target, xxx.max_rapists_per_prisoner, 0)); // Fail if someone else reserves the prisoner before the pawn arrives this.FailOn(() => pawn.Drafted); yield return(Toils_Goto.GotoThing(iprisoner, PathEndMode.OnCell)); SexUtility.RapeAttemptAlert(pawn, Target); Toil rape = new Toil(); rape.initAction = delegate { //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - reserving prisoner"); //pawn.Reserve(Target, comfort_prisoners.max_rapists_per_prisoner, 0); if (!pawnHasPenis) { Target.rotationTracker.Face(pawn.DrawPos); } //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Setting victim job driver"); JobDriver_GettinRaped dri = Target.jobs.curDriver as JobDriver_GettinRaped; if (dri == null) { Job gettin_raped = new Job(xxx.gettin_raped, pawn, Target); Building_Bed Bed = null; //Log.Message(xxx.get_pawnname(pawn) + " LayingInBed:" + pawn.GetPosture()); //Log.Message(xxx.get_pawnname(Target) + " LayingInBed:" + Target.GetPosture()); if (Target.GetPosture() == PawnPosture.LayingInBed) { Bed = Target.CurrentBed(); //Log.Message(xxx.get_pawnname(Target) + ": bed:" + Bed); } Target.jobs.StartJob(gettin_raped, JobCondition.InterruptForced, null, false, true, null); (Target.jobs.curDriver as JobDriver_GettinRaped)?.increase_time(duration); if (Bed != null) { (Target.jobs.curDriver as JobDriver_GettinRaped)?.set_bed(Bed); } } else { dri.rapist_count += 1; dri.increase_time(duration); } }; rape.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } if (pawn.IsHashIntervalTick(ticks_between_thrusts)) { xxx.sexTick(pawn, Target); } if (pawn.IsHashIntervalTick(ticks_between_hits)) { roll_to_hit(pawn, Target); } xxx.reduce_rest(Target, 1); xxx.reduce_rest(pawn, 2); }; rape.AddFinishAction(delegate { //Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Clearing victim job"); if (Target.jobs?.curDriver is JobDriver_GettinRaped) { //Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Victim present"); (Target.jobs.curDriver as JobDriver_GettinRaped).rapist_count -= 1; } }); rape.defaultCompleteMode = ToilCompleteMode.Delay; rape.defaultDuration = duration; yield return(rape); yield return(new Toil { initAction = delegate { // Trying to add some interactions and social logs SexUtility.ProcessSex(pawn, Target, true); Target.records.Increment(xxx.GetRapedAsComfortPrisoner); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override IEnumerable <Toil> MakeNewToils() { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() called"); setup_ticks(); this.FailOnDespawnedNullOrForbidden(iTarget); this.FailOn(() => !pawn.CanReserve(Target, 1, 0)); // Fail if someone else reserves the prisoner before the pawn arrives this.FailOn(() => pawn.IsFighting()); this.FailOn(() => pawn.Drafted); this.FailOn(Target.IsBurning); //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - moving towards Target"); yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); var alert = RJWPreferenceSettings.rape_attempt_alert == RJWPreferenceSettings.RapeAlert.Disabled ? MessageTypeDefOf.SilentInput : MessageTypeDefOf.NeutralEvent; Messages.Message(xxx.get_pawnname(pawn) + " is trying to rape a corpse of " + xxx.get_pawnname(Partner), pawn, alert); setup_ticks(); // re-setup ticks on arrival var rape = new Toil(); rape.defaultCompleteMode = ToilCompleteMode.Delay; rape.defaultDuration = duration; rape.handlingFacing = true; rape.initAction = delegate { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - stripping Target"); (Target as Corpse).Strip(); Start(); }; rape.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) { if (xxx.is_necrophiliac(pawn)) { ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } else { ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart); } } //if (pawn.IsHashIntervalTick (ticks_between_hits)) // roll_to_hit (pawn, Target); SexTick(pawn, Target); SexUtility.reduce_rest(pawn, 2); }; rape.AddFinishAction(delegate { End(); }); yield return(rape); yield return(new Toil { initAction = delegate { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - creating aftersex toil"); SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, sextype: sexType); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override IEnumerable <Toil> MakeNewToils() { setup_ticks(); this.FailOnDespawnedOrNull(iTarget); this.FailOnDespawnedNullOrForbidden(iBed); this.FailOn(() => !pawn.CanReserveAndReach(Partner, PathEndMode.Touch, Danger.Deadly)); this.FailOn(() => pawn.Drafted); this.FailOn(() => Partner.IsFighting()); this.FailOn(() => !Partner.CanReach(pawn, PathEndMode.Touch, Danger.Deadly)); yield return(Toils_Reserve.Reserve(iTarget, 1, 0)); Toil gotoAnimal = Toils_Goto.GotoThing(iTarget, PathEndMode.Touch); yield return(gotoAnimal); Toil gotoBed = new Toil(); gotoBed.defaultCompleteMode = ToilCompleteMode.PatherArrival; gotoBed.FailOnBedNoLongerUsable(iBed); gotoBed.AddFailCondition(() => Partner.Downed); gotoBed.initAction = delegate { pawn.pather.StartPath(SleepSpot, PathEndMode.OnCell); Partner.jobs.StopAll(); Job job = JobMaker.MakeJob(JobDefOf.GotoMindControlled, SleepSpot); Partner.jobs.StartJob(job, JobCondition.InterruptForced); }; yield return(gotoBed); Toil waitInBed = new Toil(); waitInBed.FailOn(() => pawn.GetRoom(RegionType.Set_Passable) == null); waitInBed.defaultCompleteMode = ToilCompleteMode.Delay; waitInBed.initAction = delegate { ticksLeftThisToil = 5000; }; waitInBed.tickAction = delegate { pawn.GainComfortFromCellIfPossible(); if (IsInOrByBed(Bed, Partner) && pawn.PositionHeld == Partner.PositionHeld) { ReadyForNextToil(); } }; yield return(waitInBed); Toil StartPartnerJob = new Toil(); StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; StartPartnerJob.socialMode = RandomSocialMode.Off; StartPartnerJob.initAction = delegate { var gettin_loved = JobMaker.MakeJob(xxx.gettin_loved, pawn, Bed); Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); }; yield return(StartPartnerJob); Toil loveToil = new Toil(); loveToil.AddFailCondition(() => Partner.Dead || !IsInOrByBed(Bed, Partner)); loveToil.socialMode = RandomSocialMode.Off; loveToil.defaultCompleteMode = ToilCompleteMode.Never; loveToil.handlingFacing = true; loveToil.initAction = delegate { usedCondom = CondomUtility.TryUseCondom(pawn); Start(); }; loveToil.AddPreTickAction(delegate { --ticks_left; if (pawn.IsHashIntervalTick(ticks_between_hearts)) { if (xxx.is_zoophile(pawn)) { ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } else { ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart); } } SexTick(pawn, Partner); SexUtility.reduce_rest(pawn, 1); SexUtility.reduce_rest(Partner, 2); if (ticks_left <= 0) { ReadyForNextToil(); } }); loveToil.AddFinishAction(delegate { End(); }); yield return(loveToil); Toil afterSex = new Toil { initAction = delegate { //Log.Message("JobDriver_BestialityForFemale::MakeNewToils() - Calling aftersex"); SexUtility.ProcessSex(Partner, pawn, usedCondom: usedCondom, sextype: sexType); }, defaultCompleteMode = ToilCompleteMode.Instant }; yield return(afterSex); }
protected override IEnumerable <Toil> MakeNewToils() { //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called"); setup_ticks(); this.FailOnDespawnedOrNull(iTarget); this.FailOnDespawnedOrNull(iBed); this.FailOn(() => !Partner.health.capacities.CanBeAwake); this.FailOn(() => !(Partner.InBed() || xxx.in_same_bed(Partner, pawn))); this.FailOn(() => pawn.Drafted); yield return(Toils_Reserve.Reserve(iTarget, xxx.max_rapists_per_prisoner, 0)); yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); Toil StartPartnerJob = new Toil(); StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; StartPartnerJob.socialMode = RandomSocialMode.Off; StartPartnerJob.initAction = delegate { Job gettin_loved = JobMaker.MakeJob(xxx.gettin_loved, pawn, Bed); Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); }; yield return(StartPartnerJob); Toil do_lovin = new Toil(); do_lovin.FailOn(() => Partner.CurJob.def != xxx.gettin_loved); do_lovin.defaultCompleteMode = ToilCompleteMode.Never; do_lovin.socialMode = RandomSocialMode.Off; do_lovin.handlingFacing = true; do_lovin.initAction = delegate { usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner); Start(); }; do_lovin.AddPreTickAction(delegate { --ticks_left; if (pawn.IsHashIntervalTick(ticks_between_hearts)) { ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } SexTick(pawn, Partner); SexUtility.reduce_rest(Partner, 1); SexUtility.reduce_rest(pawn, 2); if (ticks_left <= 0) { ReadyForNextToil(); } }); do_lovin.AddFinishAction(delegate { End(); }); yield return(do_lovin); yield return(new Toil { initAction = delegate { // Trying to add some interactions and social logs SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, whoring: isWhoring, sextype: sexType); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override IEnumerable <Toil> MakeNewToils() { //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() called"); //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); duration = (int)(2500.0f * Rand.Range(0.50f, 0.90f)); ticks_between_hearts = Rand.RangeInclusive(70, 130); ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); ticks_between_thrusts = 100; if (xxx.is_bloodlust(pawn)) { ticks_between_hits = (int)(ticks_between_hits * 0.75); } if (xxx.is_brawler(pawn)) { ticks_between_hits = (int)(ticks_between_hits * 0.90); } //this.FailOn (() => (!animal.health.capacities.CanBeAwake) || (!comfort_prisoners.is_designated (animal))); // Fail if someone else reserves the prisoner before the pawn arrives or colonist can't reach animal this.FailOn(() => !pawn.CanReserveAndReach(animal, PathEndMode.Touch, Danger.Deadly)); this.FailOn(() => animal.HostileTo(pawn)); this.FailOnDespawnedNullOrForbidden(target_animal); this.FailOn(() => pawn.Drafted); yield return(Toils_Reserve.Reserve(target_animal, 1, 0)); //Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() - moving towards animal"); yield return(Toils_Goto.GotoThing(target_animal, PathEndMode.Touch)); yield return(Toils_Interpersonal.WaitToBeAbleToInteract(pawn)); yield return(Toils_Interpersonal.GotoInteractablePosition(target_animal)); if (xxx.is_kind(pawn) || (xxx.CTIsActive && xxx.has_traits(pawn) && pawn.story.traits.HasTrait(TraitDef.Named("RCT_AnimalLover")))) { yield return(TalkToAnimal(pawn, animal)); yield return(TalkToAnimal(pawn, animal)); } if (Rand.Chance(0.6f)) { yield return(TalkToAnimal(pawn, animal)); } yield return(Toils_Goto.GotoThing(target_animal, PathEndMode.OnCell)); SexUtility.RapeAttemptAlert(pawn, animal); Toil rape = new Toil(); rape.initAction = delegate { //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() - reserving animal"); //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() - Setting animal job driver"); if (!(animal.jobs.curDriver is JobDriver_GettinRaped dri)) { //wild animals may flee or attack if (pawn.Faction != animal.Faction && animal.RaceProps.wildness > Rand.Range(0.22f, 1.0f) && !(pawn.TicksPerMoveCardinal < (animal.TicksPerMoveCardinal / 2) && !animal.Downed && xxx.is_not_dying(animal))) { animal.jobs.StopAll(); // Wake up if sleeping. float aggro = animal.kindDef.RaceProps.manhunterOnTameFailChance; if (animal.kindDef.RaceProps.predator) { aggro += 0.2f; } else { aggro -= 0.1f; } if (Rand.Chance(aggro) && animal.CanSee(pawn)) { animal.rotationTracker.FaceTarget(pawn); LifeStageUtility.PlayNearestLifestageSound(animal, (ls) => ls.soundAngry, 1.4f); MoteMaker.ThrowMetaIcon(animal.Position, animal.Map, ThingDefOf.Mote_IncapIcon); MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_ColonistFleeing); //red '!' animal.mindState.mentalStateHandler.TryStartMentalState(MentalStateDefOf.Manhunter); if (animal.kindDef.RaceProps.herdAnimal && Rand.Chance(0.2f)) { // 20% chance of turning the whole herd hostile... List <Pawn> packmates = animal.Map.mapPawns.AllPawnsSpawned.Where(x => x != animal && x.def == animal.def && x.Faction == animal.Faction && x.Position.InHorDistOf(animal.Position, 24f) && x.CanSee(animal)).ToList(); foreach (Pawn packmate in packmates) { packmate.mindState.mentalStateHandler.TryStartMentalState(MentalStateDefOf.Manhunter); } } Messages.Message(pawn.Name.ToStringShort + " is being attacked by " + xxx.get_pawnname(animal) + ".", pawn, MessageTypeDefOf.ThreatSmall); } else { MoteMaker.ThrowMetaIcon(animal.Position, animal.Map, ThingDefOf.Mote_ColonistFleeing); LifeStageUtility.PlayNearestLifestageSound(animal, (ls) => ls.soundCall); animal.mindState.StartFleeingBecauseOfPawnAction(pawn); animal.mindState.mentalStateHandler.TryStartMentalState(DefDatabase <MentalStateDef> .GetNamed("PanicFlee")); } pawn.jobs.EndCurrentJob(JobCondition.Incompletable); } else { Job gettin_bred = new Job(xxx.gettin_bred, pawn, animal); animal.jobs.StartJob(gettin_bred, JobCondition.InterruptForced, null, true); (animal.jobs.curDriver as JobDriver_GettinRaped)?.increase_time(duration); } }
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 } } } } } }