using System.Collections.Generic; using RimWorld; using rjw; using Verse; using Verse.AI; namespace rjwwhoring { public class JobDriver_WhoreInvitingVisitors : JobDriver { // List of jobs that can be interrupted by whores. public static readonly List allowedJobs = new List { null, JobDefOf.Wait_Wander, JobDefOf.GotoWander, JobDefOf.Clean, JobDefOf.ClearSnow, JobDefOf.CutPlant, JobDefOf.HaulToCell, JobDefOf.Deconstruct, JobDefOf.Harvest, JobDefOf.LayDown, JobDefOf.Research, JobDefOf.SmoothFloor, JobDefOf.SmoothWall, JobDefOf.SocialRelax, JobDefOf.StandAndBeSociallyActive, JobDefOf.RemoveApparel, JobDefOf.Strip, JobDefOf.Tame, JobDefOf.Wait, JobDefOf.Wear, JobDefOf.FixBrokenDownBuilding, JobDefOf.FillFermentingBarrel, JobDefOf.DoBill, JobDefOf.Sow, JobDefOf.Shear, JobDefOf.BuildRoof, JobDefOf.DeliverFood, JobDefOf.HaulToContainer, JobDefOf.Hunt, JobDefOf.Mine, JobDefOf.OperateDeepDrill, JobDefOf.OperateScanner, JobDefOf.RearmTurret, JobDefOf.Refuel, JobDefOf.RefuelAtomic, JobDefOf.RemoveFloor, JobDefOf.RemoveRoof, JobDefOf.Repair, JobDefOf.TakeBeerOutOfFermentingBarrel, JobDefOf.Train, JobDefOf.Uninstall, xxx.Masturbate}; public bool successfulPass = true; private Pawn Whore => GetActor(); private Pawn TargetPawn => TargetThingA as Pawn; private Building_Bed TargetBed => TargetThingB as Building_Bed; private readonly TargetIndex TargetPawnIndex = TargetIndex.A; private readonly TargetIndex TargetBedIndex = TargetIndex.B; private bool DoesTargetPawnAcceptAdvance() { if (WhoringBase.DebugWhoring) ModLog.Message($"JobDriver_InvitingVisitors::DoesTargetPawnAcceptAdvance() - {xxx.get_pawnname(TargetPawn)}"); //if (RJWSettings.WildMode) return true; if (PawnUtility.EnemiesAreNearby(TargetPawn)) { if (WhoringBase.DebugWhoring) ModLog.Message($" fail - enemy near"); return false; } if (!allowedJobs.Contains(TargetPawn.jobs.curJob.def)) { if (WhoringBase.DebugWhoring) ModLog.Message($" fail - not allowed job"); return false; } if (WhoringBase.DebugWhoring) { ModLog.Message("Will try hookup " + WhoringHelper.WillPawnTryHookup(TargetPawn)); ModLog.Message("Is whore appealing " + WhoringHelper.IsHookupAppealing(TargetPawn, Whore)); ModLog.Message("Can afford whore " + WhoringHelper.CanAfford(TargetPawn, Whore)); ModLog.Message("Need sex " + (xxx.need_some_sex(TargetPawn) >= 1)); } if (WhoringHelper.WillPawnTryHookup(TargetPawn) && WhoringHelper.IsHookupAppealing(TargetPawn, Whore) && WhoringHelper.CanAfford(TargetPawn, Whore) && xxx.need_some_sex(TargetPawn) >= 1f) { if (!Whore.IsPrisoner) Whore.skills.Learn(SkillDefOf.Social, 1.2f); return true; } return false; } public override bool TryMakePreToilReservations(bool errorOnFailed) => true; protected override IEnumerable MakeNewToils() { this.FailOnDespawnedOrNull(TargetPawnIndex); this.FailOnDespawnedNullOrForbidden(TargetBedIndex); this.FailOn(() => Whore is null || !WhoreBed_Utility.CanUseForWhoring(Whore, TargetBed));//|| !Whore.CanReserve(TargetPawn) this.FailOn(() => pawn.Drafted); if (!Whore.IsPrisoner) { yield return Toils_Goto.GotoThing(TargetPawnIndex, PathEndMode.Touch); Toil TryItOn = new Toil(); TryItOn.AddFailCondition(() => !xxx.IsTargetPawnOkay(TargetPawn)); TryItOn.defaultCompleteMode = ToilCompleteMode.Delay; TryItOn.initAction = delegate { //ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - TryItOn - initAction is called"); Whore.jobs.curDriver.ticksLeftThisToil = 50; FleckMaker.ThrowMetaIcon(Whore.Position, Whore.Map, FleckDefOf.Heart); }; yield return TryItOn; } Toil AwaitResponse = new Toil(); AwaitResponse.defaultCompleteMode = ToilCompleteMode.Delay; AwaitResponse.defaultDuration = 10; AwaitResponse.initAction = delegate { List extraSentencePacks = new List(); successfulPass = DoesTargetPawnAcceptAdvance(); //ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - AwaitResponse - initAction is called"); if (successfulPass) { FleckMaker.ThrowMetaIcon(TargetPawn.Position, TargetPawn.Map, FleckDefOf.Heart); TargetPawn.jobs.EndCurrentJob(JobCondition.Incompletable); if (xxx.RomanceDiversifiedIsActive) { extraSentencePacks.Add(RulePackDef.Named("HookupSucceeded")); } if (Whore.health.HasHediffsNeedingTend()) { successfulPass = false; string key = "RJW_VisitorSickWhore"; string text = key.Translate(TargetPawn.LabelIndefinite(), Whore.LabelIndefinite()).CapitalizeFirst(); Messages.Message(text, Whore, MessageTypeDefOf.TaskCompletion); } else { string key = "RJW_VisitorAcceptWhore"; if (Whore.IsPrisoner) { key = "RJW_VisitorSolicitWhore"; } string text = key.Translate(TargetPawn.LabelIndefinite(), Whore.LabelIndefinite()).CapitalizeFirst(); Messages.Message(text, TargetPawn, MessageTypeDefOf.TaskCompletion); } } if (!successfulPass) { // remove bed reservation TargetBed.UnreserveForWhoring(); FleckMaker.ThrowMetaIcon(TargetPawn.Position, TargetPawn.Map, FleckDefOf.IncapIcon); TargetPawn.needs.mood.thoughts.memories.TryGainMemory( TargetPawn.Faction == Whore.Faction ? ThoughtDef.Named("RJWTurnedDownWhore") : ThoughtDef.Named("RJWFailedSolicitation"), Whore); if (xxx.RomanceDiversifiedIsActive) { Whore.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("RebuffedMyHookupAttempt"), TargetPawn); TargetPawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("FailedHookupAttemptOnMe"), Whore); extraSentencePacks.Add(RulePackDef.Named("HookupFailed")); } //Disabled rejection notifications //Messages.Message("RJW_VisitorRejectWhore".Translate(new object[] { xxx.get_pawnname(TargetPawn), xxx.get_pawnname(Whore) }), TargetPawn, MessageTypeDefOf.SilentInput); } if (xxx.RomanceDiversifiedIsActive) { Find.PlayLog.Add(new PlayLogEntry_Interaction(DefDatabase.GetNamed("TriedHookupWith"), pawn, TargetPawn, extraSentencePacks)); } //Log.Message("[RJW] AwaitResponse initAction - successfulPass: " + successfulPass.ToString()); }; yield return AwaitResponse; Toil BothGoToBed = new Toil(); BothGoToBed.AddFailCondition(() => !successfulPass || !WhoreBed_Utility.CanUseForWhoring(Whore, TargetBed)); BothGoToBed.defaultCompleteMode = ToilCompleteMode.Instant; BothGoToBed.initAction = delegate { //ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - BothGoToBed - initAction is called0"); if (!successfulPass) return; if (!WhoreBed_Utility.CanUseForWhoring(Whore, TargetBed) && Whore.CanReserve(TargetPawn, 1, 0)) { //ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - BothGoToBed - cannot use the whore bed"); return; } //ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - BothGoToBed - initAction is called1"); TargetBed.ReserveForWhoring(Whore, 1800);//is 1800 ticks long enough to go to the bed (until next reservation is made?) Whore.jobs.jobQueue.EnqueueFirst(JobMaker.MakeJob(xxx.whore_is_serving_visitors, TargetPawn, TargetBed)); //TargetPawn.jobs.jobQueue.EnqueueFirst(JobMaker.MakeJob(DefDatabase.GetNamed("WhoreIsServingVisitors"), Whore, TargetBed, (TargetBed.MaxAssignedPawnsCount>1)?TargetBed.GetSleepingSlotPos(1): TargetBed.)), null); Whore.jobs.curDriver.EndJobWith(JobCondition.InterruptOptional); //TargetPawn.jobs.curDriver.EndJobWith(JobCondition.InterruptOptional); }; yield return BothGoToBed; } } }