internal static IEnumerable <Toil> _MakeNewToils(this JobDriver_SocialRelax obj)
        {
            obj.EndOnDespawnedOrNull(GatherSpotParentInd, JobCondition.Incompletable);

            if (obj.HasChair())
            {
                obj.EndOnDespawnedOrNull(ChairOrSpotInd, JobCondition.Incompletable);
            }
            yield return(Toils_Reserve.Reserve(ChairOrSpotInd, 1));

            if (obj.HasDrinkOrDispenser())
            {
                obj.FailOnDestroyedNullOrForbidden(OptionalDrinkInd);
                yield return(Toils_Reserve.Reserve(OptionalDrinkInd, 1));

                if (obj.IsDispenser())
                {
                    yield return(Toils_Goto.GotoThing(OptionalDrinkInd, PathEndMode.InteractionCell));

                    yield return(Toils_FoodSynthesizer.TakeAlcoholFromSynthesizer(OptionalDrinkInd, obj.pawn));
                }
                else
                {
                    yield return(Toils_Goto.GotoThing(OptionalDrinkInd, PathEndMode.OnCell));

                    yield return(Toils_Haul.StartCarryThing(OptionalDrinkInd));
                }
            }

            yield return(Toils_Goto.GotoCell(ChairOrSpotInd, PathEndMode.OnCell));

            var relax = new Toil()
            {
                defaultCompleteMode = ToilCompleteMode.Delay,
                defaultDuration     = obj.pawn.CurJob.def.joyDuration,
                tickAction          = () =>
                {
                    var pawnDrawer     = obj.pawn.GetPawnDrawTracker();
                    var pawnFaceTarget = obj.ClosestGatherSpotParentCell();
                    pawnDrawer.rotator.FaceCell(pawnFaceTarget);
                    obj.pawn.GainComfortFromCellIfPossible();
                    JoyUtility.JoyTickCheckEnd(obj.pawn, JoyTickFullJoyAction.GoToNextToil, 1f);
                }
            };

            relax.AddFinishAction(() =>
                                  JoyUtility.TryGainRecRoomThought(obj.pawn)
                                  );
            relax.socialMode = RandomSocialMode.SuperActive;
            yield return(relax);

            if (obj.IsDrink())
            {
                yield return(Toils_Ingest.FinalizeIngest(obj.pawn, OptionalDrinkInd));
            }
        }
        protected override IEnumerable <Toil> MakeNewToils()
        {
            List <Toil>   toilsList       = new List <Toil>();
            Building_Pyre pyre            = this.TargetThingA as Building_Pyre;
            bool          beerIsAvailable = false;

            if (this.pawn.Position.InHorDistOf(pyre.Position, Building_Pyre.partyAreaRadius) == false)
            {
                // Go around pyre.
                toilsList.Add(base.ToilGetWanderCell(pyre.Position));
                Find.PawnDestinationManager.ReserveDestinationFor(this.pawn, this.CurJob.targetB.Cell);
                toilsList.Add(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell));
                // Release cell (the pawn will either go grab a beer or move on the next job).
                toilsList.Add(base.ToilReleaseCell());
            }
            // Look for an available beer.
            List <Thing> list = Find.ListerThings.ThingsOfDef(ThingDefOf.Beer);

            if (list.Count > 0)
            {
                Predicate <Thing> validator = (Thing t) => pawn.CanReserve(t, 1) && !t.IsForbidden(pawn);
                Thing             beer      = GenClosest.ClosestThing_Global_Reachable(pyre.Position, list, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), Building_Pyre.beerSearchAreaRadius, validator, null);
                if (beer != null)
                {
                    beerIsAvailable = true;
                    this.CurJob.SetTarget(TargetIndex.A, beer);
                    //this.CurJob.targetA = beer;
                    this.CurJob.maxNumToCarry = 1;
                    toilsList.Add(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A));
                    toilsList.Add(Toils_Ingest.PickupIngestible(TargetIndex.A, this.pawn)); // TargetIndex.A becomes the carried beer.
                    toilsList.Add(Toils_Ingest.CarryIngestibleToChewSpot(this.pawn));
                    toilsList.Add(Toils_Ingest.FindAdjacentEatSurface(TargetIndex.B, TargetIndex.A));
                    // float durationMultiplier = 1f / this.pawn.GetStatValue(StatDefOf.EatingSpeed, true); // Don't use it so the job duration is nearly the same for all pawns.
                    float durationMultiplier = 1f;
                    toilsList.Add(Toils_Ingest.ChewIngestible(this.pawn, durationMultiplier, TargetIndex.A, TargetIndex.B).FailOn((Toil x) => !this.Food.Spawned && (this.pawn.carrier == null || this.pawn.carrier.CarriedThing != this.Food)));
                    toilsList.Add(Toils_Ingest.FinalizeIngest(this.pawn, TargetIndex.A));
                }
            }
            // Draw a mote.
            ThingDef moteDef = null;

            if (beerIsAvailable)
            {
                moteDef = Util_CampfireParty.Mote_BeerAvailable;
            }
            else
            {
                moteDef = Util_CampfireParty.Mote_BeerUnavailable;
            }
            MoteAttached moteAttached = (MoteAttached)ThingMaker.MakeThing(moteDef);

            moteAttached.AttachTo(this.pawn);
            GenSpawn.Spawn(moteAttached, this.pawn.Position);

            return(toilsList);
        }
Example #3
0
        internal static IEnumerable <Toil> _MakeNewToils(this JobDriver_FoodFeedPatient obj)
        {
            var foodThing = obj.TargetThing(FoodInd);
            var deliveree = (Pawn)obj.TargetThing(DelivereeInd);

            obj.FailOnDespawnedNullOrForbidden(DelivereeInd);
            obj.FailOn(() =>
            {
                return(!FoodUtility.ShouldBeFedBySomeone(deliveree));
            });

            yield return(Toils_Reserve.Reserve(DelivereeInd, 1));

            if (foodThing is Building)
            {
                yield return(Toils_Reserve.Reserve(FoodInd, 1));

                yield return(Toils_Goto.GotoThing(FoodInd, PathEndMode.InteractionCell).FailOnForbidden(FoodInd));

                if (foodThing is Building_NutrientPasteDispenser)
                {
                    yield return(Toils_Ingest.TakeMealFromDispenser(FoodInd, obj.pawn));
                }
                else if (foodThing is Building_AutomatedFactory)
                {
                    yield return(Toils_FoodSynthesizer.TakeMealFromSynthesizer(FoodInd, obj.pawn));
                }
                else // Unknown building
                {
                    throw new Exception("Food target for JobDriver_FoodDeliver is a building but not Building_NutrientPasteDispenser or Building_AutomatedFactory!");
                }
            }
            else if (
                (obj.pawn.inventory != null) &&
                (obj.pawn.inventory.Contains(foodThing))
                )
            {
                yield return(Toils_Misc.TakeItemFromInventoryToCarrier(obj.pawn, FoodInd));
            }
            else
            {
                yield return(Toils_Reserve.Reserve(FoodInd, 1));

                yield return(Toils_Goto.GotoThing(FoodInd, PathEndMode.ClosestTouch).FailOnForbidden(FoodInd));

                yield return(Toils_Ingest.PickupIngestible(FoodInd, deliveree));
            }

            yield return(Toils_Goto.GotoThing(DelivereeInd, PathEndMode.Touch));

            yield return(Toils_Ingest.ChewIngestible(deliveree, FeedDurationMultiplier, FoodInd));

            yield return(Toils_Ingest.FinalizeIngest(deliveree, FoodInd));
        }
Example #4
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            this.FailOn(() => !IngestibleSource.Destroyed && !IngestibleSource.IngestibleNow);
            Toil chew = Toils_Ingest.ChewIngestible(pawn, ChewDurationMultiplier, TargetIndex.A, TargetIndex.None).FailOn((Toil x) => !IngestibleSource.Spawned && (pawn.carryTracker == null || pawn.carryTracker.CarriedThing != IngestibleSource)).FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch);

            foreach (Toil toil in PrepareToIngestToils())
            {
                yield return(toil);
            }
            yield return(chew);

            yield return(Toils_Ingest.FinalizeIngest(pawn, TargetIndex.A));
        }
Example #5
0
        private IEnumerable <Toil> Nibble()
        {
            Toil gotoCorpse = Toils_Goto.GotoThing(CorpseInd, PathEndMode.Touch);

            yield return(gotoCorpse);

            float durationMultiplier = 1f / this.pawn.GetStatValue(StatDefOf.EatingSpeed, true);

            yield return(Toils_Ingest.ChewIngestible(this.pawn, durationMultiplier, CorpseInd, TargetIndex.None).FailOnDespawnedOrNull(CorpseInd).FailOnCannotTouch(CorpseInd, PathEndMode.Touch));

            yield return(Toils_Ingest.FinalizeIngest(this.pawn, CorpseInd));

            yield return(Toils_Jump.JumpIf(gotoCorpse, () => this.pawn.needs.food.CurLevelPercentage < 0.9f));
        }
Example #6
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            this.EndOnDespawnedOrNull(TargetIndex.A, JobCondition.Incompletable);
            if (HasChair)
            {
                this.EndOnDespawnedOrNull(TargetIndex.B, JobCondition.Incompletable);
            }
            if (HasDrink)
            {
                this.FailOnDestroyedNullOrForbidden(TargetIndex.C);
                yield return(Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.OnCell).FailOnSomeonePhysicallyInteracting(TargetIndex.C));

                yield return(Toils_Haul.StartCarryThing(TargetIndex.C, false, false, false));
            }
            yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell));

            Toil chew = new Toil();

            chew.tickAction = delegate
            {
                pawn.rotationTracker.FaceCell(ClosestGatherSpotParentCell);
                pawn.GainComfortFromCellIfPossible();
                JoyUtility.JoyTickCheckEnd(pawn, JoyTickFullJoyAction.GoToNextToil, 1f);

                if (pawn.IsHashIntervalTick(100))
                {
                    MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Note);
                }
            };
            chew.handlingFacing      = true;
            chew.defaultCompleteMode = ToilCompleteMode.Delay;
            chew.defaultDuration     = job.def.joyDuration;
            chew.AddFinishAction(delegate
            {
                JoyUtility.TryGainRecRoomThought(pawn);
            });
            chew.socialMode = RandomSocialMode.SuperActive;
            Toils_Ingest.AddIngestionEffects(chew, pawn, TargetIndex.C, TargetIndex.None);
            yield return(chew);

            if (HasDrink)
            {
                yield return(Toils_Ingest.FinalizeIngest(pawn, TargetIndex.C));
            }
            yield break;
        }
        protected override IEnumerable <Toil> MakeNewToils()
        {
            if (!usingNutrientPasteDispenser)
            {
                this.FailOn(() => !IngestibleSource.Destroyed && !IngestibleSource.IngestibleNow);
            }
            Toil chew = Toils_Ingest.ChewIngestible(pawn, ChewDurationMultiplier, TargetIndex.A, TargetIndex.B).FailOn((Toil x) => (!IngestibleSource.Spawned && (pawn.carryTracker != null)) || pawn.mindState.anyCloseHostilesRecently).FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch);

            foreach (Toil item in PrepareToIngestToils(chew))
            {
                yield return(item);
            }
            yield return(chew);

            yield return(Toils_Ingest.FinalizeIngest(pawn, TargetIndex.A));

            yield return(Toils_Jump.JumpIf(chew, () => job.GetTarget(TargetIndex.A).Thing is Corpse && pawn.needs.food.CurLevelPercentage < 0.9f));
        }
    protected override IEnumerable <Toil> MakeNewToils()
    {
        //Toil definitions

        AddFinishAction(delegate
        {
            if (Cocoon != null)
            {
                Cocoon.CurrentDrinker = null;
            }
        });

        var gotoBody = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);

        gotoBody.AddPreInitAction(delegate
        {
            Cocoon.CurrentDrinker = pawn as PawnWebSpinner;

            if (Victim != null && (Victim?.Faction != Faction.OfPlayerSilentFail || Victim.Dead || notifiedPlayer))
            {
                return;
            }

            notifiedPlayer = true;
            var sound      = Victim?.Dead ?? false ? MessageTypeDefOf.NeutralEvent : MessageTypeDefOf.ThreatBig;
            Messages.Message("ROM_SpiderEatingColonist".Translate(pawn.Label, Victim?.Label),
                             sound);
        });

        //Toil executions
        yield return(gotoBody);

        yield return(Liquify());

        var durationMultiplier = 1f / pawn.GetStatValue(StatDefOf.EatingSpeed);

        yield return(DrinkCorpse(durationMultiplier));

        yield return(Toils_Ingest.FinalizeIngest(pawn, TargetIndex.B));

        yield return(Toils_Jump.JumpIf(gotoBody, () => pawn.needs.food.CurLevelPercentage < 0.9f)
                     .FailOnDestroyedNullOrForbidden(TargetIndex.B));
    }
Example #9
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            // Declare these early - jumping points
            var waitForWaiter = Toils_Dining.WaitForWaiter(SpotIndex, WaiterIndex).FailOnRestaurantClosed().FailOnDangerous();
            var waitForMeal   = Toils_Dining.WaitForMeal(MealIndex).FailOnDangerous();

            this.FailOn(() => DiningSpot.Destroyed);
            yield return(Toils_Dining.GoToDineSpot(pawn, SpotIndex).FailOnRestaurantClosed());

            yield return(Toils_Dining.TurnToEatSurface(SpotIndex));

            // Order broken? Jump straight to waiter
            yield return(Toils_Jump.JumpIf(waitForWaiter, () => !pawn.GetRestaurant().Orders.CheckOrderOfWaitingPawn(pawn)));

            // Already has ordered? Jump to waiting for meal
            yield return(Toils_Jump.JumpIf(waitForMeal, () => pawn.GetRestaurant().Orders.GetOrderFor(pawn) != null));

            yield return(waitForWaiter);

            yield return(waitForMeal);

            yield return(Toils_Misc.TakeItemFromInventoryToCarrier(pawn, MealIndex));

            yield return(Toils_Reserve.Reserve(MealIndex, 1, 1));

            yield return(Toils_Dining.TurnToEatSurface(SpotIndex, MealIndex));

            yield return(Toils_Dining.WaitDuringDinner(SpotIndex, 100, 250));

            yield return(Toils_Ingest.ChewIngestible(pawn, ChewDurationMultiplier, MealIndex, SpotIndex));

            yield return(Toils_Ingest.FinalizeIngest(pawn, MealIndex));

            yield return(Toils_Dining.OnCompletedMeal(pawn));

            yield return(Toils_Dining.MakeTableMessy(SpotIndex, () => pawn.Position));

            yield return(Toils_Jump.JumpIf(waitForWaiter, () => pawn.needs.food.CurLevelPercentage < 0.9f));

            yield return(Toils_Dining.WaitDuringDinner(SpotIndex, 100, 250));

            yield return(Toils_Dining.PayDebt(pawn));
        }
        internal static IEnumerable <Toil> _MakeNewToils(this JobDriver_FoodFeedPatient obj)
        {
            Pawn deliveree = (Pawn)obj.pawn.CurJob.targetB.Thing;

            obj.FailOnDespawnedNullOrForbidden(TargetIndex.B);
            obj.FailOn(() =>
            {
                return(!FoodUtility.ShouldBeFedBySomeone(deliveree));
            });

            yield return(Toils_Reserve.Reserve(TargetIndex.B, 1));

            var targetThingA = obj.TargetThingA();

            if (targetThingA is Building)
            {
                yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell).FailOnForbidden(TargetIndex.A));

                if (targetThingA is Building_NutrientPasteDispenser)
                {
                    yield return(Toils_Ingest.TakeMealFromDispenser(TargetIndex.A, obj.pawn));
                }
                if (targetThingA is Building_AutomatedFactory)
                {
                    yield return(Toils_FoodSynthesizer.TakeMealFromSynthesizer(TargetIndex.A, obj.pawn));
                }
            }
            else
            {
                yield return(Toils_Reserve.Reserve(TargetIndex.A, 1));

                yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnForbidden(TargetIndex.A));

                yield return(Toils_Ingest.PickupIngestible(TargetIndex.A, deliveree));
            }

            yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch));

            yield return(Toils_Ingest.ChewIngestible(deliveree, 1.5f, TargetIndex.A));

            yield return(Toils_Ingest.FinalizeIngest(deliveree, TargetIndex.A));
        }
        /// <summary>
        /// gets the Feeds toils.
        /// </summary>
        /// <returns></returns>
        protected virtual IEnumerable <Toil> FeedToils()
        {
            var toil = new Toil();

            toil.initAction          = delegate { feedNutritionLeft = RequiredNutritionPerFeed(Animal); };
            toil.defaultCompleteMode = ToilCompleteMode.Instant;
            yield return(toil);

            Toil gotoAnimal = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);

            yield return(gotoAnimal);

            yield return(StartFeedAnimal(TargetIndex.A));

            yield return(Toils_Ingest.FinalizeIngest(Animal, TargetIndex.B));

            yield return(Toils_General.PutCarriedThingInInventory());

            yield return(Toils_General.ClearTarget(TargetIndex.B));

            yield return(Toils_Jump.JumpIf(gotoAnimal, () => feedNutritionLeft > 0f));
        }
Example #12
0
        public override IEnumerable <Toil> MakeNewToils()
        {
            base.AddFinishAction(delegate
            {
                this.Map.attackTargetsCache.UpdateTarget(this.pawn);
            });
            Toil prepareToEatCorpse = new Toil();

            prepareToEatCorpse.initAction = delegate()
            {
                Pawn   actor  = prepareToEatCorpse.actor;
                Corpse corpse = this.Corpse;
                if (corpse == null)
                {
                    Pawn prey = this.Prey;
                    if (prey == null)
                    {
                        actor.jobs.EndCurrentJob(JobCondition.Incompletable, true, true);
                        return;
                    }
                    corpse = prey.Corpse;
                    if (corpse == null || !corpse.Spawned)
                    {
                        actor.jobs.EndCurrentJob(JobCondition.Incompletable, true, true);
                        return;
                    }
                }
                if (actor.Faction == Faction.OfPlayer)
                {
                    corpse.SetForbidden(false, false);
                }
                else
                {
                    corpse.SetForbidden(true, false);
                }
                actor.CurJob.SetTarget(TargetIndex.A, corpse);
            };
            yield return(Toils_General.DoAtomic(delegate
            {
                this.Map.attackTargetsCache.UpdateTarget(this.pawn);
            }));

            Action hitAction = delegate()
            {
                Pawn prey           = this.Prey;
                bool surpriseAttack = this.firstHit && !prey.IsColonist;
                if (this.pawn.meleeVerbs.TryMeleeAttack(prey, this.job.verbToUse, surpriseAttack))
                {
                    if (!this.notifiedPlayerAttacked && PawnUtility.ShouldSendNotificationAbout(prey))
                    {
                        this.notifiedPlayerAttacked = true;
                        Messages.Message("MessageAttackedByPredator".Translate(prey.LabelShort, this.pawn.LabelIndefinite(), prey.Named("PREY"), this.pawn.Named("PREDATOR")).CapitalizeFirst(), prey, MessageTypeDefOf.ThreatSmall, true);
                    }
                    this.Map.attackTargetsCache.UpdateTarget(this.pawn);
                    this.firstHit = false;
                }
            };
            Toil toil = Toils_Combat.FollowAndMeleeAttack(TargetIndex.A, hitAction).JumpIfDespawnedOrNull(TargetIndex.A, prepareToEatCorpse).JumpIf(() => this.Corpse != null, prepareToEatCorpse).FailOn(() => Find.TickManager.TicksGame > this.startTick + 5000 && (float)(this.job.GetTarget(TargetIndex.A).Cell - this.pawn.Position).LengthHorizontalSquared > 4f);

            toil.AddPreTickAction(new Action(this.CheckWarnPlayer));
            yield return(toil);

            yield return(prepareToEatCorpse);

            Toil gotoCorpse = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);

            yield return(gotoCorpse);

            float durationMultiplier = 1f / this.pawn.GetStatValue(StatDefOf.EatingSpeed, true);

            yield return(Toils_Ingest.ChewIngestible(this.pawn, durationMultiplier, TargetIndex.A, TargetIndex.None).FailOnDespawnedOrNull(TargetIndex.A).FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch));

            yield return(Toils_Ingest.FinalizeIngest(this.pawn, TargetIndex.A));

            yield return(Toils_Jump.JumpIf(gotoCorpse, () => this.pawn.needs.food.CurLevelPercentage < 0.9f));

            yield break;
        }
Example #13
0
        static IEnumerable <Toil> _MakeToils(this JobDriver_SocialRelax driver)
        {
            //driver.EndOnDespawnedOrNull(TargetIndex.A, JobCondition.Incompletable);
            driver.AddEndCondition(delegate
            {
                LocalTargetInfo target = driver.GetActor().jobs.curJob.GetTarget(TargetIndex.A);
                Thing thing            = target.Thing;
                if (thing == null && target.IsValid || thing is Filth)
                {
                    return(JobCondition.Ongoing);
                }
                if (thing == null || !thing.Spawned || thing.Map != driver.GetActor().Map)
                {
                    return(JobCondition.Incompletable);
                }
                return(JobCondition.Ongoing);
            });

            if (driver.HasChair())
            {
                driver.EndOnDespawnedOrNull(TargetIndex.B, JobCondition.Incompletable);
            }
            if (driver.HasDrink())
            {
                driver.FailOnDestroyedNullOrForbidden(TargetIndex.C);
                yield return(Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.OnCell).FailOnSomeonePhysicallyInteracting(TargetIndex.C));

                yield return(Toils_Haul.StartCarryThing(TargetIndex.C, false, false, false));
            }

            //cleaning patch
            Toil GoToRelaxPlace = Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell);

            if (Settings.adv_cleaning_ingest && !Utility.IncapableOfCleaning(driver.pawn))
            {
                Toil FilthList = new Toil();
                FilthList.initAction = delegate()
                {
                    Job curJob = FilthList.actor.jobs.curJob;
                    if (curJob.GetTargetQueue(TargetIndex.A).NullOrEmpty())
                    {
                        LocalTargetInfo     A = curJob.GetTarget(TargetIndex.A);
                        IEnumerable <Filth> l = Utility.SelectAllFilth(FilthList.actor, A, Settings.adv_clean_num);
                        Utility.AddFilthToQueue(curJob, TargetIndex.A, l, FilthList.actor);
                        FilthList.actor.ReserveAsManyAsPossible(curJob.GetTargetQueue(TargetIndex.A), curJob);
                        curJob.targetQueueA.Add(A);
                    }
                };
                yield return(FilthList);

                yield return(Toils_Jump.JumpIf(GoToRelaxPlace, () => driver.job.GetTargetQueue(TargetIndex.A).NullOrEmpty()));

                Toil CleanFilthList = Toils_JobTransforms.ClearDespawnedNullOrForbiddenQueuedTargets(TargetIndex.A, null);
                yield return(CleanFilthList);

                yield return(Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A, true));

                yield return(Toils_Jump.JumpIf(GoToRelaxPlace, () => driver.job.GetTargetQueue(TargetIndex.A).NullOrEmpty()));

                yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch).JumpIfDespawnedOrNullOrForbidden(TargetIndex.A, CleanFilthList).JumpIfOutsideHomeArea(TargetIndex.A, CleanFilthList));

                //
                driver.job.GetTargetQueue(TargetIndex.B).Add(new IntVec3(0, 0, 0));
                Toil clean = new Toil();
                clean.initAction = delegate()
                {
                    Filth filth   = clean.actor.jobs.curJob.GetTarget(TargetIndex.A).Thing as Filth;
                    var   progQue = clean.actor.jobs.curJob.GetTargetQueue(TargetIndex.B);
                    progQue[0] = new IntVec3(0, 0, (int)filth.def.filth.cleaningWorkToReduceThickness * filth.thickness);
                };
                clean.tickAction = delegate()
                {
                    Filth   filth   = clean.actor.jobs.curJob.GetTarget(TargetIndex.A).Thing as Filth;
                    var     progQue = clean.actor.jobs.curJob.GetTargetQueue(TargetIndex.B);
                    IntVec3 iv      = progQue[0].Cell;
                    iv.x += 1;
                    iv.y += 1;
                    if (iv.x > filth.def.filth.cleaningWorkToReduceThickness)
                    {
                        filth.ThinFilth();
                        iv.x = 0;
                        if (filth.Destroyed)
                        {
                            clean.actor.records.Increment(RecordDefOf.MessesCleaned);
                            driver.ReadyForNextToil();
                            return;
                        }
                    }
                    progQue[0] = iv;
                };
                clean.defaultCompleteMode = ToilCompleteMode.Never;
                clean.WithEffect(EffecterDefOf.Clean, TargetIndex.A);
                clean.WithProgressBar(TargetIndex.A,
                                      delegate()
                {
                    var q        = driver.job.GetTargetQueue(TargetIndex.B)[0];
                    float result = (float)q.Cell.y / q.Cell.z;
                    return(result);
                }
                                      , true, -0.5f);
                clean.PlaySustainerOrSound(() => SoundDefOf.Interact_CleanFilth);
                clean.JumpIfDespawnedOrNullOrForbidden(TargetIndex.A, CleanFilthList);
                clean.JumpIfOutsideHomeArea(TargetIndex.A, CleanFilthList);
                yield return(clean);

                yield return(Toils_Jump.Jump(CleanFilthList));
            }

            yield return(GoToRelaxPlace);

            //
            float    joyoffset;
            ThingDef def = driver.job.GetTarget(TargetIndex.C).HasThing ? driver.job.GetTarget(TargetIndex.C).Thing.def : null;

            if (Settings.social_relax_economy && def != null && def.IsIngestible)
            {
                joyoffset = def.ingestible.joy * driver.pawn.needs.joy.tolerances.JoyFactorFromTolerance(def.ingestible.JoyKind);
                //minimum amount of time for action to perform
                float baseoffset = Mathf.Max(0.36f / 2500f * def.ingestible.baseIngestTicks, 0.36f / 2500f * 60f * 4f);
                float expected   = 1f - driver.pawn.needs.joy.CurLevel - joyoffset;
                if (expected < baseoffset)
                {
                    float expected2 = 1f - driver.pawn.needs.joy.CurLevel - baseoffset;
                    if (expected2 < 0f)
                    {
                        joyoffset = 0f;
                    }
                    else if (expected2 < baseoffset)
                    {
                        joyoffset = baseoffset - expected2;
                    }
                    else
                    {
                        joyoffset += expected - baseoffset;
                    }
                }
            }
            else
            {
                joyoffset = 0f;
            }

            Toil toil = new Toil();

            toil.tickAction = delegate()
            {
                driver.pawn.rotationTracker.FaceCell(driver.ClosestGatherSpotParentCell());
                driver.pawn.GainComfortFromCellIfPossible(false);
                JoyTickCheckEndOffset(driver.pawn, joyoffset, JoyTickFullJoyAction.GoToNextToil);
            };
            toil.handlingFacing      = true;
            toil.defaultCompleteMode = ToilCompleteMode.Delay;
            toil.defaultDuration     = driver.job.def.joyDuration;
            toil.AddFinishAction(delegate
            {
                JoyUtility.TryGainRecRoomThought(driver.pawn);
            });
            toil.socialMode = RandomSocialMode.SuperActive;
            Toils_Ingest.AddIngestionEffects(toil, driver.pawn, TargetIndex.C, TargetIndex.None);
            yield return(toil);

            if (driver.HasDrink())
            {
                yield return(Toils_Ingest.FinalizeIngest(driver.pawn, TargetIndex.C));
            }
            yield break;
        }
        internal static IEnumerable <Toil> _MakeNewToils(this JobDriver_Ingest obj)
        {
            if (obj.IsDispenser())
            {
                yield return(Toils_Goto.GotoThing(FoodOrDispenserInd, PathEndMode.InteractionCell).FailOnDespawnedNullOrForbidden(FoodOrDispenserInd));

                if (obj.Alcohol() == null)
                {
                    // Meals
                    if (obj.Dispenser() is Building_NutrientPasteDispenser)
                    {
                        yield return(Toils_Ingest.TakeMealFromDispenser(FoodOrDispenserInd, obj.pawn));
                    }
                    if (obj.Dispenser() is Building_AutomatedFactory)
                    {
                        yield return(Toils_FoodSynthesizer.TakeMealFromSynthesizer(FoodOrDispenserInd, obj.pawn));
                    }
                }
                else
                {
                    // Alcohol
                    if (obj.Dispenser() is Building_AutomatedFactory)
                    {
                        yield return(Toils_FoodSynthesizer.TakeAlcoholFromSynthesizer(FoodOrDispenserInd, obj.pawn));
                    }
                }
                yield return(Toils_Ingest.CarryIngestibleToChewSpot(obj.pawn).FailOnDestroyedNullOrForbidden(FoodOrDispenserInd));

                yield return(Toils_Ingest.FindAdjacentEatSurface(TableCellInd, FoodOrDispenserInd));
            }
            else if (obj.pawn.RaceProps.ToolUser)
            {
                if (obj.pawn.CurJob.eatFromInventory)
                {
                    var dropIfNeeded = new Toil();
                    dropIfNeeded.initAction = new Action(() =>
                    {
                        Pawn pawn            = obj.pawn;
                        Thing resultingThing = obj.Food();
                        Thing thing          = resultingThing;
                        if (
                            (pawn.inventory == null) ||
                            (!pawn.inventory.container.Contains(resultingThing))
                            )
                        {
                            return;
                        }
                        int count = Mathf.Min(resultingThing.stackCount, pawn.CurJob.maxNumToCarry);
                        if (!pawn.inventory.container.TryDrop(resultingThing, pawn.Position, ThingPlaceMode.Near, count, out resultingThing))
                        {
                            Verse.Log.Error(pawn + " could not drop their food to eat it.");
                            obj.EndJobWith(JobCondition.Errored);
                        }
                        else
                        {
                            if (resultingThing == thing)
                            {
                                return;
                            }
                            pawn.CurJob.SetTarget(FoodOrDispenserInd, (TargetInfo)resultingThing);
                        }
                    });

                    yield return(dropIfNeeded);
                }
                yield return(obj.ReserveFoodIfWillEatWholeStack());

                yield return(Toils_Goto.GotoThing(FoodOrDispenserInd, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(FoodOrDispenserInd));

                yield return(Toils_Ingest.PickupIngestible(FoodOrDispenserInd, obj.pawn));

                yield return(Toils_Ingest.CarryIngestibleToChewSpot(obj.pawn).FailOnDestroyedNullOrForbidden(FoodOrDispenserInd));

                yield return(Toils_Ingest.FindAdjacentEatSurface(TableCellInd, FoodOrDispenserInd));
            }
            else // Non-Tool User
            {
                yield return(obj.ReserveFoodIfWillEatWholeStack());

                yield return(Toils_Goto.GotoThing(FoodOrDispenserInd, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(FoodOrDispenserInd));
            }

            var durationMultiplier = 1f / obj.pawn.GetStatValue(StatDefOf.EatingSpeed, true);
            var chew = Toils_Ingest.ChewIngestible(obj.pawn, durationMultiplier, FoodOrDispenserInd, TableCellInd).FailOn(() =>
            {
                if (!obj.Food().Spawned)
                {
                    return((obj.pawn.carrier == null ? 0 : (obj.pawn.carrier.CarriedThing == obj.Food() ? 1 : 0)) == 0);
                }
                return(false);
            });

            yield return(chew);

            yield return(Toils_Ingest.FinalizeIngest(obj.pawn, FoodOrDispenserInd));

            yield return(Toils_Jump.JumpIf(chew, () =>
            {
                if (obj.Food() is Corpse)
                {
                    return (double)obj.pawn.needs.food.CurLevelPercentage < JobDriver_Ingest.EatCorpseBodyPartsUntilFoodLevelPct;
                }
                return false;
            }));
        }