public override StateGraph CreateGraph() { StateGraph stateGraph = new StateGraph(); LordToil_HangOut lordToil_HangOut = new LordToil_HangOut(new Pawn[] { initiator, recipient }); stateGraph.AddToil(lordToil_HangOut); LordToil_End lordToil_End = new LordToil_End(); stateGraph.AddToil(lordToil_End); Transition transition = new Transition(lordToil_HangOut, lordToil_End); transition.AddTrigger(new Trigger_TickCondition(() => this.ShouldBeCalledOff())); transition.AddTrigger(new Trigger_TickCondition(() => this.initiator.health.summaryHealth.SummaryHealthPercent < 1f || this.recipient.health.summaryHealth.SummaryHealthPercent < 1f)); transition.AddTrigger(new Trigger_TickCondition(() => this.initiator.Drafted || this.recipient.Drafted)); transition.AddTrigger(new Trigger_PawnLost()); stateGraph.AddTransition(transition); this.timeoutTrigger = new Trigger_TicksPassed(Rand.RangeInclusive(GenDate.TicksPerHour * 4, GenDate.TicksPerHour * 6)); Transition transition2 = new Transition(lordToil_HangOut, lordToil_End); transition2.AddTrigger(this.timeoutTrigger); transition2.AddPreAction(new TransitionAction_Custom((Action) delegate { this.Finished(); })); stateGraph.AddTransition(transition2); return(stateGraph); }
protected override Job TryGiveJob(Pawn pawn) { LordToil_HangOut toil = pawn.GetLord().CurLordToil as LordToil_HangOut; Pawn friend = (pawn == toil.friends[0] ? toil.friends[1] : toil.friends[0]); if (friend == null) { return(null); } /* If they are partners, possibly send them to lay down together so they'll do lovin'. */ if (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, friend) && pawn.ownership.OwnedBed != null && !pawn.GetPosture().Laying() && (pawn.IsHashIntervalTick(GenDate.TicksPerHour) || friend.IsHashIntervalTick(GenDate.TicksPerHour))) { return(new Job(JobDefOf.LayDown, pawn.ownership.OwnedBed, GenDate.TicksPerHour)); } /* If they have no joy activity assigned, or they've been doing it for 1-3 hours, give them a new one. */ if (toil.hangOut == null || toil.ticksToNextJoy < Find.TickManager.TicksGame) { toil.hangOut = base.TryGiveJob(pawn); toil.ticksToNextJoy = Find.TickManager.TicksGame + Rand.RangeInclusive(GenDate.TicksPerHour, GenDate.TicksPerHour * 3); } /* If they need joy, go do the joy activity.*/ if (toil.hangOut != null && friend.needs.food.CurLevel > 0.33f && pawn.needs.joy.CurLevel < 0.8f) { /* Sometimes the joy activity can't be reserved because it's for one person only. */ Job job = new Job(toil.hangOut.def); job.targetA = toil.hangOut.targetA; job.targetB = toil.hangOut.targetB; job.targetC = toil.hangOut.targetC; job.targetQueueA = toil.hangOut.targetQueueA; job.targetQueueB = toil.hangOut.targetQueueB; job.count = toil.hangOut.count; job.countQueue = toil.hangOut.countQueue; job.expiryInterval = toil.hangOut.expiryInterval; job.locomotionUrgency = toil.hangOut.locomotionUrgency; if (job.TryMakePreToilReservations(pawn, false)) { return(job); } else { pawn.ClearAllReservations(false); } } if (((pawn.Position - friend.Position).LengthHorizontalSquared >= 54 || !GenSight.LineOfSight(pawn.Position, friend.Position, pawn.Map, true))) { /* Make sure they are close to each other if they're not actively doing a joy activity. */ /* If the other pawn is already walking over, just hang around until they get there. */ if (friend.CurJob.def != JobDefOf.Goto) { return(new Job(JobDefOf.Goto, friend)); } else { pawn.rotationTracker.FaceCell(friend.Position); return(null); } } else { /* If they are already standing close enough, but can't do the joy activity together, then wander around. */ IntVec3 result; /* Make sure they only wander within conversational distance. */ Predicate <IntVec3> validator = (IntVec3 x) => x.Standable(pawn.Map) && x.InAllowedArea(pawn) && !x.IsForbidden(pawn) && pawn.CanReserveAndReach(x, PathEndMode.OnCell, Danger.None, 1, -1, null, false) && (x - friend.Position).LengthHorizontalSquared < 50 && GenSight.LineOfSight(x, friend.Position, pawn.Map, true) && x != friend.Position; if (CellFinder.TryFindRandomReachableCellNear(pawn.Position, pawn.Map, 12f, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Deadly, false), (IntVec3 x) => validator(x), null, out result)) { if ((pawn.Position - friend.Position).LengthHorizontalSquared >= 5 || (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, friend) && pawn.Position != friend.Position)) { /* Sending them to goto a friend ends with them standing right next to/on top of them. So make them respect personal space a little more. */ pawn.mindState.nextMoveOrderIsWait = !pawn.mindState.nextMoveOrderIsWait; if (!result.IsValid || pawn.mindState.nextMoveOrderIsWait) { /* Alternate between relaxing socially and wandering. */ pawn.rotationTracker.FaceCell(friend.Position); return(null); } } Job wander = new Job(JobDefOf.GotoWander, result); pawn.Map.pawnDestinationReservationManager.Reserve(pawn, wander, result); return(wander); } /* If we can't find a valid spot, just relax socially. */ pawn.rotationTracker.FaceCell(friend.Position); return(null); } }
protected override Job TryGiveJob(Pawn pawn) { LordToil_HangOut toil = pawn.GetLord().CurLordToil as LordToil_HangOut; Pawn friend = (pawn == toil.friends[0] ? toil.friends[1] : toil.friends[0]); if (pawn.needs.food.CurLevel < 0.33f) { return(null); } if (friend.needs.food.CurLevel < 0.33f) { return(null); } if (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, friend) && pawn.jobs.curDriver != null && pawn.jobs.curDriver.layingDown == LayingDownState.NotLaying && (pawn.IsHashIntervalTick(GenDate.TicksPerHour) || friend.IsHashIntervalTick(GenDate.TicksPerHour))) { return(new Job(JobDefOf.LayDown, pawn.ownership.OwnedBed)); } if (toil.hangOut != null && toil.hangOut.GetTarget(TargetIndex.A) != null && !pawn.CanReserve(toil.hangOut.GetTarget(TargetIndex.A), toil.hangOut.def.joyMaxParticipants, 0, null)) { Log.Message("can't reserve the target of the hangout"); /* Try our best to figure out which JoyGiver was used for the unreservable job. */ int prefix = "JoyGiver".Count(); var def = ( from j in DefDatabase <JoyGiverDef> .AllDefs where j.jobDef == toil.hangOut.def || (j.jobDef == null && DefDatabase <JobDef> .GetNamedSilentFail(nameof(j.giverClass).Substring(prefix)) == toil.hangOut.def) select j ).FirstOrDefault(); if (def != null) { Log.Message("giving job of def " + def.defName); do { toil.hangOut = base.TryGiveJobFromJoyGiverDefDirect(def, pawn); } while (toil.hangOut.GetTarget(TargetIndex.A).Thing.GetRoom() != friend.GetRoom()); } else { toil.hangOut = null; } } if (toil.hangOut == null || toil.ticksToNextJoy < Find.TickManager.TicksGame) { toil.hangOut = base.TryGiveJob(pawn); toil.ticksToNextJoy = Find.TickManager.TicksGame + Rand.RangeInclusive(GenDate.TicksPerHour, GenDate.TicksPerHour * 3); } if (pawn.needs.joy.CurLevel < 0.8f) { return(toil.hangOut); } Log.Message("no joy hangout available"); IntVec3 root = WanderUtility.BestCloseWanderRoot(toil.hangOut.targetA.Cell, pawn); Func <Pawn, IntVec3, bool> validator = delegate(Pawn wanderer, IntVec3 loc) { IntVec3 wanderRoot = root; Room room = wanderRoot.GetRoom(pawn.Map); return(room == null || WanderUtility.InSameRoom(wanderRoot, loc, pawn.Map)); }; pawn.mindState.nextMoveOrderIsWait = !pawn.mindState.nextMoveOrderIsWait; IntVec3 wanderDest = RCellFinder.RandomWanderDestFor(pawn, root, 5f, validator, PawnUtility.ResolveMaxDanger(pawn, Danger.Some)); if (!wanderDest.IsValid || pawn.mindState.nextMoveOrderIsWait) { if ((pawn.Position - friend.Position).LengthHorizontalSquared >= 42f && friend.jobs.curJob.def != JobDefOf.Goto) { Log.Message("friend not nearby, going to friend"); IntVec3 friendDest = RCellFinder.RandomWanderDestFor(pawn, friend.Position, 5f, validator, PawnUtility.ResolveMaxDanger(pawn, Danger.Some)); pawn.Map.pawnDestinationManager.ReserveDestinationFor(pawn, friendDest); return(new Job(JobDefOf.Goto, friendDest)); } Log.Message("waiting"); return(null); } Log.Message("wandering"); pawn.Map.pawnDestinationManager.ReserveDestinationFor(pawn, wanderDest); return(new Job(JobDefOf.GotoWander, wanderDest)); }