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_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); }