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 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() { //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 }); }
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() { 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] 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() { //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() { //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 }); }
protected override IEnumerable <Toil> MakeNewToils() { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called"); 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; 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.FailOnDespawnedNullOrForbidden(iTarget); 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.IsFighting()); this.FailOn(() => Target.IsFighting()); this.FailOn(() => pawn.Drafted); yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); SexUtility.RapeAttemptAlert(pawn, Target); //Log.Message("[RJW] JobDriver_Rape::make toils() called"); var rape = new Toil(); rape.initAction = delegate { //Log.Message("[RJW]" + this.GetType().ToString() + "::initAction() called"); //pawn.Reserve(Target, comfort_prisoners.max_rapists_per_prisoner, 0); //if (!pawnHasPenis) // Target.rotationTracker.Face(pawn.DrawPos); 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.FailOn(() => Target.CurJob == null || Target.CurJob.def != xxx.gettin_raped || Target.IsFighting() || pawn.IsFighting()); }; rape.tickAction = delegate { //Log.Message("[RJW] JobDriver_Rape::tickAction() called"); 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, false); } if (pawn.IsHashIntervalTick(ticks_between_hits)) { roll_to_hit(pawn, Target); } xxx.reduce_rest(Target, 1); xxx.reduce_rest(pawn, 2); }; rape.AddFinishAction(delegate { if (Target.jobs?.curDriver is JobDriver_GettinRaped) { (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 { //Log.Message("[RJW] JobDriver_Rape::aftersex() called"); //// Trying to add some interactions and social logs SexUtility.ProcessSex(pawn, Target, true); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
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]" + this.GetType().ToString() + "::MakeNewToils() called"); setup_ticks(); this.FailOnDespawnedNullOrForbidden(iTarget); this.FailOn(() => !Partner.health.capacities.CanBeAwake); this.FailOn(() => pawn.IsFighting()); this.FailOn(() => Partner.IsFighting()); this.FailOn(() => pawn.Drafted); yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); Toil findQuickieSpot = new Toil(); findQuickieSpot.defaultCompleteMode = ToilCompleteMode.PatherArrival; findQuickieSpot.initAction = delegate { //Needs this earlier to decide if current place is good enough all_pawns = pawn.Map.mapPawns.AllPawnsSpawned.Where(x => x.Position.DistanceTo(pawn.Position) < 100 && xxx.is_human(x) && x != pawn && x != Partner ).ToList(); temperature = pawn.ComfortableTemperatureRange(); float cellTemp = pawn.Position.GetTemperature(pawn.Map); if (Partner.IsPrisonerInPrisonCell() || (!MightBeSeen(all_pawns, pawn.Position, pawn, Partner) && (cellTemp > temperature.min && cellTemp < temperature.max))) { ReadyForNextToil(); } else { var spot = FindQuickieLocation(pawn, Partner); pawn.pather.StartPath(spot, PathEndMode.OnCell); Partner.jobs.StopAll(); Job job = JobMaker.MakeJob(JobDefOf.GotoMindControlled, spot); Partner.jobs.StartJob(job, JobCondition.InterruptForced); } }; yield return(findQuickieSpot); Toil WaitForPartner = new Toil(); WaitForPartner.defaultCompleteMode = ToilCompleteMode.Delay; WaitForPartner.initAction = delegate { ticksLeftThisToil = 5000; }; WaitForPartner.tickAction = delegate { pawn.GainComfortFromCellIfPossible(); if (pawn.Position.DistanceTo(Partner.Position) <= 1f) { ReadyForNextToil(); } }; yield return(WaitForPartner); Toil StartPartnerJob = new Toil(); StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; StartPartnerJob.socialMode = RandomSocialMode.Off; StartPartnerJob.initAction = delegate { Job gettingQuickie = JobMaker.MakeJob(xxx.getting_quickie, pawn, Partner); Partner.jobs.StartJob(gettingQuickie, JobCondition.InterruptForced); }; yield return(StartPartnerJob); Toil doQuickie = new Toil(); doQuickie.defaultCompleteMode = ToilCompleteMode.Never; doQuickie.socialMode = RandomSocialMode.Off; doQuickie.defaultDuration = duration; doQuickie.handlingFacing = true; doQuickie.initAction = delegate { usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner); Start(); }; doQuickie.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, 1); if (ticks_left <= 0) { ReadyForNextToil(); } }); doQuickie.AddFinishAction(delegate { End(); }); yield return(doQuickie); 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 IEnumerable <Toil> MakeNewToils() { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() called"); //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; 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.FailOnDespawnedNullOrForbidden(icorpse); 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(icorpse, PathEndMode.OnCell)); var alert = RJWPreferenceSettings.rape_alert_sound == RJWPreferenceSettings.RapeAlert.Disabled ? MessageTypeDefOf.SilentInput : MessageTypeDefOf.NeutralEvent; Messages.Message(pawn.Name + " is trying to rape a Target.", pawn, alert); var rape = new Toil(); rape.initAction = delegate { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - reserving Target"); //pawn.Reserve(Target, 1, 0); // Target rapin seems like a solitary activity //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - stripping Target"); Target.Strip(); }; rape.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) { MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } if (pawn.IsHashIntervalTick(ticks_between_thrusts)) { sexTick(pawn, Target); } /* * if (pawn.IsHashIntervalTick (ticks_between_hits)) * roll_to_hit (pawn, Corpse); */ xxx.reduce_rest(pawn, 2); }; rape.AddFinishAction(delegate { if (xxx.is_human(pawn)) { pawn.Drawer.renderer.graphics.ResolveApparelGraphics(); } }); rape.defaultCompleteMode = ToilCompleteMode.Delay; rape.defaultDuration = duration; yield return(rape); yield return(new Toil { initAction = delegate { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - creating aftersex toil"); //Addded by nizhuan-jjr: Try to apply an aftersex process for the pawn and the Target if (Target.InnerPawn != null) { SexUtility.ProcessSex(pawn, Target.InnerPawn, true); } }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDespawnedOrNull(PartnerInd); this.FailOnDespawnedNullOrForbidden(BedInd); this.FailOn(() => Actor is null || !Actor.CanReserveAndReach(Partner, PathEndMode.Touch, Danger.Deadly)); this.FailOn(() => pawn.Drafted); yield return(Toils_Reserve.Reserve(PartnerInd, 1, 0)); //yield return Toils_Reserve.Reserve(BedInd, Bed.SleepingSlotsCount, 0); Toil gotoAnimal = Toils_Goto.GotoThing(PartnerInd, PathEndMode.Touch); yield return(gotoAnimal); bool partnerHasPenis = Genital_Helper.has_penis(Partner) || Genital_Helper.has_penis_infertile(Partner); Toil gotoBed = new Toil { initAction = delegate { Actor.pather.StartPath(SleepSpot, PathEndMode.OnCell); Partner.pather.StartPath(SleepSpot, PathEndMode.OnCell); }, defaultCompleteMode = ToilCompleteMode.PatherArrival }; gotoBed.FailOnBedNoLongerUsable(BedInd); gotoBed.AddFailCondition(() => Partner.Downed); yield return(gotoBed); gotoBed.AddFinishAction(delegate { var gettin_loved = new Job(xxx.gettin_loved, Actor, Bed); Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced, null, false, true, null); }); Toil waitInBed = new Toil { initAction = delegate { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticksLeftThisToil = 5000; ticks_left = (int)(2000.0f * Rand.Range(0.30f, 1.30f)); }, tickAction = delegate { Actor.GainComfortFromCellIfPossible(); if (IsInOrByBed(Bed, Partner)) { ticksLeftThisToil = 0; } }, defaultCompleteMode = ToilCompleteMode.Delay, }; waitInBed.FailOn(() => pawn.GetRoom(RegionType.Set_Passable) == null); yield return(waitInBed); Toil loveToil = new Toil { initAction = delegate { 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(Actor, 1); xxx.reduce_rest(Partner, 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.AddFailCondition(() => Partner.Dead || !IsInOrByBed(Bed, Partner)); loveToil.socialMode = RandomSocialMode.Off; yield return(loveToil); Toil afterSex = new Toil { initAction = delegate { //Log.Message("JobDriver_BestialityForFemale::MakeNewToils() - Calling aftersex"); // Trying to add some interactions and social logs SexUtility.ProcessSex(Partner, pawn); }, defaultCompleteMode = ToilCompleteMode.Instant }; yield return(afterSex); }
protected override IEnumerable <Toil> MakeNewToils() { setup_ticks(); //--Log.Message("JobDriver_Breeding::MakeNewToils() - setting fail conditions"); this.FailOnDespawnedNullOrForbidden(iTarget); this.FailOn(() => !pawn.CanReserve(Partner, BreederHelper.max_animals_at_once, 0)); // Fail if someone else reserves the target before the animal arrives. this.FailOn(() => !pawn.CanReach(Partner, PathEndMode.Touch, Danger.Some)); // Fail if animal cannot reach target. this.FailOn(() => pawn.Drafted); // Path to target yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); //if (!(pawn.IsDesignatedBreedingAnimal() && Partner.IsDesignatedBreeding())); if (!(pawn.IsAnimal() && Partner.IsAnimal())) { 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); // Breed target var breed = new Toil(); breed.defaultCompleteMode = ToilCompleteMode.Delay; breed.defaultDuration = duration; breed.handlingFacing = true; breed.initAction = delegate { Start(); }; breed.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) { if (xxx.is_zoophile(pawn) || xxx.is_animal(pawn)) { ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } else { ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart); } } if (pawn.IsHashIntervalTick(ticks_between_hits) && !xxx.is_zoophile(Partner)) { Roll_to_hit(pawn, Partner); } SexTick(pawn, Partner); if (!Partner.Dead) { SexUtility.reduce_rest(Partner, 1); } SexUtility.reduce_rest(pawn, 2); }; breed.AddFinishAction(delegate { End(); }); 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 isRape = !(pawn.relations.DirectRelationExists(PawnRelationDefOf.Bond, Partner) || (xxx.is_animal(pawn) && (pawn.RaceProps.wildness - pawn.RaceProps.petness + 0.18f) > Rand.Range(0.36f, 1.8f))); SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, sextype: sexType); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
protected override IEnumerable <Toil> MakeNewToils() { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - making toils"); setup_ticks(); this.FailOnDespawnedOrNull(iTarget); this.FailOnDespawnedNullOrForbidden(iBed); //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() fail conditions check " + !xxx.CanUse(pawn, Bed) + " " + !pawn.CanReserve(Partner)); this.FailOn(() => !xxx.CanUse(pawn, Bed) || !pawn.CanReserve(Partner)); 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)); //yield return Toils_Reserve.Reserve(BedInd, Bed.SleepingSlotsCount, 0); //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - generate toils"); Toil gotoBed = new Toil(); gotoBed.defaultCompleteMode = ToilCompleteMode.PatherArrival; gotoBed.FailOnWhorebedNoLongerUsable(iBed, Bed); gotoBed.AddFailCondition(() => Partner.Downed); gotoBed.FailOn(() => !Partner.CanReach(Bed, PathEndMode.Touch, Danger.Deadly)); gotoBed.initAction = delegate { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - gotoWhoreBed initAction is called"); 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); ticks_left = (int)(2000.0f * Rand.Range(0.30f, 1.30f)); Toil waitInBed = new Toil(); waitInBed.initAction = delegate { ticksLeftThisToil = 5000; }; waitInBed.tickAction = delegate { pawn.GainComfortFromCellIfPossible(); if (IsInOrByBed(Bed, Partner) && pawn.PositionHeld == Partner.PositionHeld) { ReadyForNextToil(); } }; waitInBed.defaultCompleteMode = ToilCompleteMode.Delay; yield return(waitInBed); Toil StartPartnerJob = new Toil(); StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; StartPartnerJob.socialMode = RandomSocialMode.Off; StartPartnerJob.initAction = delegate { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - StartPartnerJob"); 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 || Partner.CurJobDef != xxx.gettin_loved); loveToil.defaultCompleteMode = ToilCompleteMode.Never; loveToil.socialMode = RandomSocialMode.Off; loveToil.handlingFacing = true; loveToil.initAction = delegate { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - loveToil"); // TODO: replace this quick n dirty way CondomUtility.GetCondomFromRoom(pawn); // Try to use w***e's condom first, then client's usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner); Start(); if (xxx.HasNonPolyPartnerOnCurrentMap(Partner)) { Pawn lover = LovePartnerRelationUtility.ExistingLovePartner(Partner); // 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 && pawn != lover && !lover.Dead && (lover.Map == Partner.Map || Rand.Value < 0.25)) { lover.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, Partner); } } }; loveToil.AddPreTickAction(delegate { --ticks_left; if (pawn.IsHashIntervalTick(ticks_between_hearts)) { if (xxx.is_nympho(pawn)) { ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); } else { ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart); } } SexUtility.reduce_rest(Partner, 1); SexUtility.reduce_rest(pawn, 2); if (ticks_left <= 0) { ReadyForNextToil(); } }); loveToil.AddFinishAction(delegate { End(); }); yield return(loveToil); Toil afterSex = new Toil { initAction = delegate { // Adding interactions, social logs, etc SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, whoring: isWhoring, sextype: sexType); if (!(Partner.IsColonist && (pawn.IsPrisonerOfColony || pawn.IsColonist))) { int price = WhoringHelper.PriceOfWhore(pawn); //--Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Partner should pay the price now in afterSex.initAction"); int remainPrice = WhoringHelper.PayPriceToWhore(Partner, price, pawn); /*if (remainPrice <= 0) * { * --Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Paying price is success"); * } * else * { * --Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Paying price failed"); * }*/ xxx.UpdateRecords(pawn, price - remainPrice); } var thought = (pawn.IsPrisoner || xxx.is_slave(pawn)) ? 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 = JobMaker.MakeJob(JobDefOf.Clean); clean.AddQueuedTarget(TargetIndex.A, cum); pawn.jobs.jobQueue.EnqueueFirst(clean); } }, defaultCompleteMode = ToilCompleteMode.Instant }; yield return(afterSex); }