protected override IEnumerable <Toil> MakeNewToils() { this.FailOn(() => PrisonerFoodReservation.isReserved(TargetA.Thing)); yield return(Toils_Reserve.Reserve(TargetIndex.B, 1, -1, null)); if (eatingFromInventory) { yield return(Toils_Misc.TakeItemFromInventoryToCarrier(pawn, TargetIndex.A)); } else if (usingNutrientPasteDispenser) { yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell) .FailOnForbidden(TargetIndex.A)); yield return(Toils_Ingest.TakeMealFromDispenser(TargetIndex.A, pawn)); } else { yield return(Toils_Reserve.Reserve(TargetIndex.A, 1, -1, null)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch) .FailOnForbidden(TargetIndex.A)); yield return(Toils_Ingest.PickupIngestible(TargetIndex.A, Deliveree)); } var toil = new Toil(); toil.initAction = delegate { var actor = toil.actor; var curJob = actor.jobs.curJob; actor.pather.StartPath(curJob.targetC, PathEndMode.OnCell); }; toil.defaultCompleteMode = ToilCompleteMode.PatherArrival; toil.FailOnDestroyedNullOrForbidden(TargetIndex.B); toil.AddFailCondition(delegate { var pawn = (Pawn)toil.actor.jobs.curJob.targetB.Thing; return(!pawn.IsPrisonerOfColony || !pawn.guest.CanBeBroughtFood); }); yield return(toil); yield return(new Toil { initAction = delegate { Thing thing; pawn.carryTracker.TryDropCarriedThing(toil.actor.jobs.curJob.targetC.Cell, ThingPlaceMode.Direct, out thing, null); PrisonerFoodReservation.reserve(thing, (Pawn)toil.actor.jobs.curJob.targetB.Thing); }, defaultCompleteMode = ToilCompleteMode.Instant }); }
public static Thing BestFoodSourceOnMap(Pawn getter, Pawn eater, bool desperate, FoodPreferability maxPref = FoodPreferability.MealLavish, bool allowPlant = true, bool allowDrug = true, bool allowCorpse = true, bool allowDispenserFull = true, bool allowDispenserEmpty = true, bool allowForbidden = false, bool allowSociallyImproper = false) { var getterCanManipulate = getter.RaceProps.ToolUser && getter.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation); if (!getterCanManipulate && getter != eater) { Log.Error(string.Concat(getter, " tried to find food to bring to ", eater, " but ", getter, " is incapable of Manipulation.")); return(null); } FoodPreferability minPref; if (!eater.RaceProps.Humanlike || eater == getter && eater.IsPrisoner) { minPref = FoodPreferability.NeverForNutrition; } else if (desperate) { minPref = FoodPreferability.DesperateOnly; } else { minPref = eater.needs.food.CurCategory <= HungerCategory.UrgentlyHungry ? FoodPreferability.RawBad : FoodPreferability.MealAwful; } Predicate <Thing> foodValidator = delegate(Thing t) { if (PrisonerFoodReservation.isReserved(t) && (eater != getter || !eater.IsPrisoner) && !desperate) { return(false); } if (!allowForbidden && t.IsForbidden(getter)) { return(false); } var building_NutrientPasteDispenser = t as Building_NutrientPasteDispenser; if (building_NutrientPasteDispenser != null) { if (!allowDispenserFull || ThingDefOf.MealNutrientPaste.ingestible.preferability < minPref || ThingDefOf.MealNutrientPaste.ingestible.preferability > maxPref || !getterCanManipulate || t.Faction != getter.Faction && t.Faction != getter.HostFaction || !building_NutrientPasteDispenser.powerComp.PowerOn || !allowDispenserEmpty && !building_NutrientPasteDispenser.HasEnoughFeedstockInHoppers() || !IsFoodSourceOnMapSociallyProper(t, getter, eater, allowSociallyImproper) || !t.InteractionCell.Standable(t.Map) || !getter.Map.reachability.CanReachNonLocal( getter.Position, new TargetInfo(t.InteractionCell, t.Map, false), PathEndMode.OnCell, TraverseParms.For(getter, Danger.Some, TraverseMode.ByPawn, false))) { return(false); } } else { if (t.def.ingestible.preferability < minPref) { return(false); } if (t.def.ingestible.preferability > maxPref) { return(false); } if (!t.IngestibleNow || !t.def.IsNutritionGivingIngestible || !allowCorpse && t is Corpse || !allowDrug && t.def.IsDrug || !desperate && t.IsNotFresh() || t.IsDessicated() || !eater.RaceProps.WillAutomaticallyEat(t) || !IsFoodSourceOnMapSociallyProper(t, getter, eater, allowSociallyImproper) || !getter.AnimalAwareOf(t) || !getter.CanReserve(t, 1, -1, null, false)) { return(false); } } return(true); }; ThingRequest thingRequest; if ((eater.RaceProps.foodType & (FoodTypeFlags.Plant | FoodTypeFlags.Tree)) != FoodTypeFlags.None && allowPlant) { thingRequest = ThingRequest.ForGroup(ThingRequestGroup.FoodSource); } else { thingRequest = ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree); } Thing thing; if (getter.RaceProps.Humanlike) { var validator = foodValidator; thing = SpawnedFoodSearchInnerScan(eater, getter.Position, getter.Map.listerThings.ThingsMatching(thingRequest), PathEndMode.ClosestTouch, TraverseParms.For(getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator); } else { var searchRegionsMax = 30; if (getter.Faction == Faction.OfPlayer) { searchRegionsMax = 100; } filtered.Clear(); foreach (var current in GenRadial.RadialDistinctThingsAround(getter.Position, getter.Map, 2f, true)) { var pawn = current as Pawn; if (pawn != null && pawn != getter && pawn.RaceProps.Animal && pawn.CurJob != null && pawn.CurJob.def == JobDefOf.Ingest && pawn.CurJob.GetTarget(TargetIndex.A).HasThing) { filtered.Add(pawn.CurJob.GetTarget(TargetIndex.A).Thing); } } var flag = !allowForbidden && ForbidUtility.CaresAboutForbidden(getter, true) && getter.playerSettings != null && getter.playerSettings.EffectiveAreaRestrictionInPawnCurrentMap != null; Predicate <Thing> predicate = t => foodValidator(t) && !filtered.Contains(t) && t.def.ingestible.preferability > FoodPreferability.DesperateOnly && !t.IsNotFresh(); var validator = predicate; var ignoreEntirelyForbiddenRegions = flag; thing = GenClosest.ClosestThingReachable(getter.Position, getter.Map, thingRequest, PathEndMode.ClosestTouch, TraverseParms.For(getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null, 0, searchRegionsMax, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions); filtered.Clear(); if (thing == null) { desperate = true; validator = foodValidator; ignoreEntirelyForbiddenRegions = flag; thing = GenClosest.ClosestThingReachable(getter.Position, getter.Map, thingRequest, PathEndMode.ClosestTouch, TraverseParms.For(getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null, 0, searchRegionsMax, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions); } } return(thing); }