private static bool Prefix(ref Thing __result, Pawn getter, Pawn eater, bool desperate, out ThingDef foodDef, 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, bool allowHarvest = false, bool forceScanWholeMap = false) { foodDef = null; if (!Registry.IsActive) { return(true); } var rules = Registry.GetRules(eater); if (eater.InMentalState || (rules == null) || rules.GetRestriction(RestrictionType.Food).IsVoid) { return(true); } Profiler.BeginSample("BestFoodInWorldFor getter=" + getter.LabelCap + " eater=" + eater.LabelCap); var getterCanManipulate = getter.RaceProps.ToolUser && getter.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation); if (!getterCanManipulate && (getter != eater)) { Log.Error(getter + " tried to find food to bring to " + eater + " but " + getter + " is incapable of Manipulation."); Profiler.EndSample(); __result = null; return(false); } var minPref = !eater.NonHumanlikeOrWildMan() ? (!desperate ? (eater.needs.food.CurCategory < HungerCategory.UrgentlyHungry ? FoodPreferability.MealAwful : FoodPreferability.RawBad) : FoodPreferability.DesperateOnly) : FoodPreferability.NeverForNutrition; var foodValidator = (Predicate <Thing>)(thing => { Profiler.BeginSample("foodValidator"); if (!rules.GetRestriction(RestrictionType.Food).Allows(thing.def)) { Profiler.EndSample(); return(false); } if (thing is Building_NutrientPasteDispenser nutrientPasteDispenser) { if (!allowDispenserFull || !getterCanManipulate || (ThingDefOf.MealNutrientPaste.ingestible.preferability < minPref) || (ThingDefOf.MealNutrientPaste.ingestible.preferability > maxPref) || !eater.RaceProps.CanEverEat(ThingDefOf.MealNutrientPaste) || ((thing.Faction != getter.Faction) && (thing.Faction != getter.HostFaction)) || (!allowForbidden && thing.IsForbidden(getter)) || !nutrientPasteDispenser.powerComp.PowerOn || (!allowDispenserEmpty && !nutrientPasteDispenser.HasEnoughFeedstockInHoppers()) || !thing.InteractionCell.Standable(thing.Map) || !PrivateAccess.RimWorld_FoodUtility_IsFoodSourceOnMapSociallyProper(thing, getter, eater, allowSociallyImproper) || getter.IsWildMan() || !getter.Map.reachability.CanReachNonLocal(getter.Position, new TargetInfo(thing.InteractionCell, thing.Map), PathEndMode.OnCell, TraverseParms.For(getter, Danger.Some))) { Profiler.EndSample(); return(false); } } else if ((thing.def.ingestible.preferability < minPref) || (thing.def.ingestible.preferability > maxPref) || !eater.RaceProps.WillAutomaticallyEat(thing) || !thing.def.IsNutritionGivingIngestible || !thing.IngestibleNow || (!allowCorpse && thing is Corpse) || (!allowDrug && thing.def.IsDrug) || (!allowForbidden && thing.IsForbidden(getter)) || (!desperate && thing.IsNotFresh()) || thing.IsDessicated() || !PrivateAccess.RimWorld_FoodUtility_IsFoodSourceOnMapSociallyProper(thing, getter, eater, allowSociallyImproper) || (!getter.AnimalAwareOf(thing) && !forceScanWholeMap) || !getter.CanReserve((LocalTargetInfo)thing)) { Profiler.EndSample(); return(false); } Profiler.EndSample(); return(true); }); var req = ((eater.RaceProps.foodType & (FoodTypeFlags.Plant | FoodTypeFlags.Tree)) == FoodTypeFlags.None) || !allowPlant?ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree) : ThingRequest.ForGroup(ThingRequestGroup.FoodSource); Thing bestThing; if (getter.RaceProps.Humanlike) { bestThing = PrivateAccess.RimWorld_FoodUtility_SpawnedFoodSearchInnerScan(eater, getter.Position, getter.Map.listerThings.ThingsMatching(req), PathEndMode.ClosestTouch, TraverseParms.For(getter), 9999f, foodValidator); if (allowHarvest && getterCanManipulate) { var searchRegionsMax = !forceScanWholeMap || (bestThing != null) ? 30 : -1; bool Validator(Thing thing) { if (!rules.GetRestriction(RestrictionType.Food).Allows(thing.def)) { return(false); } var plant = (Plant)thing; if (!plant.HarvestableNow) { return(false); } var harvestedThingDef = plant.def.plant.harvestedThingDef; return(harvestedThingDef.IsNutritionGivingIngestible && eater.RaceProps.CanEverEat(harvestedThingDef) && getter.CanReserve((LocalTargetInfo)plant) && (allowForbidden || !plant.IsForbidden(getter)) && ((bestThing == null) || (FoodUtility.GetFinalIngestibleDef(bestThing).ingestible.preferability < harvestedThingDef.ingestible.preferability))); } var foodSource = GenClosest.ClosestThingReachable(getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.HarvestablePlant), PathEndMode.Touch, TraverseParms.For(getter), 9999f, Validator, null, 0, searchRegionsMax); if (foodSource != null) { bestThing = foodSource; foodDef = FoodUtility.GetFinalIngestibleDef(foodSource, true); } } if ((foodDef == null) && (bestThing != null)) { foodDef = FoodUtility.GetFinalIngestibleDef(bestThing); } } else { var maxRegionsToScan = PrivateAccess.RimWorld_FoodUtility_GetMaxRegionsToScan(getter, forceScanWholeMap); PrivateAccess.RimWorld_FoodUtility_Filtered().Clear(); foreach (var thing in GenRadial.RadialDistinctThingsAround(getter.Position, getter.Map, 2f, true)) { if (thing is Pawn pawn && (pawn != getter) && pawn.RaceProps.Animal && (pawn.CurJob != null) && (pawn.CurJob.def == JobDefOf.Ingest) && pawn.CurJob.GetTarget(TargetIndex.A).HasThing) { PrivateAccess.RimWorld_FoodUtility_Filtered().Add(pawn.CurJob.GetTarget(TargetIndex.A).Thing); } } var flag = !allowForbidden && ForbidUtility.CaresAboutForbidden(getter, true) && (getter.playerSettings?.EffectiveAreaRestrictionInPawnCurrentMap != null); var predicate = (Predicate <Thing>)(thing => foodValidator(thing) && !PrivateAccess.RimWorld_FoodUtility_Filtered().Contains(thing) && (thing is Building_NutrientPasteDispenser || (thing.def.ingestible.preferability > FoodPreferability.DesperateOnly)) && !thing.IsNotFresh()); var position1 = getter.Position; var map1 = getter.Map; var thingReq1 = req; var traverseParams1 = TraverseParms.For(getter); var validator1 = predicate; var ignoreEntirelyForbiddenRegions1 = flag; bestThing = GenClosest.ClosestThingReachable(position1, map1, thingReq1, PathEndMode.ClosestTouch, traverseParams1, 9999f, validator1, null, 0, maxRegionsToScan, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions1); PrivateAccess.RimWorld_FoodUtility_Filtered().Clear(); if (bestThing == null) { desperate = true; var position2 = getter.Position; var map2 = getter.Map; var thingReq2 = req; var traverseParams2 = TraverseParms.For(getter); var validator2 = foodValidator; var ignoreEntirelyForbiddenRegions2 = flag; bestThing = GenClosest.ClosestThingReachable(position2, map2, thingReq2, PathEndMode.ClosestTouch, traverseParams2, 9999f, validator2, null, 0, maxRegionsToScan, false, RegionType.Set_Passable, ignoreEntirelyForbiddenRegions2); } if (bestThing != null) { foodDef = FoodUtility.GetFinalIngestibleDef(bestThing); } } Profiler.EndSample(); __result = bestThing; return(false); }
private static bool Prefix(ref bool __result, Pawn getter, Pawn eater, bool desperate, out Thing foodSource, out ThingDef foodDef, bool canRefillDispenser = true, bool canUseInventory = true, bool allowForbidden = false, bool allowCorpse = true, bool allowSociallyImproper = false, bool allowHarvest = false, bool forceScanWholeMap = false) { var flag = getter.RaceProps.ToolUser && getter.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation); var allowDrug = !eater.IsTeetotaler(); var thing1 = (Thing)null; if (canUseInventory) { if (flag) { thing1 = FoodUtility.BestFoodInInventory(getter, eater, FoodPreferability.MealAwful); } if (thing1 != null) { if (getter.Faction != Faction.OfPlayer) { foodSource = thing1; foodDef = FoodUtility.GetFinalIngestibleDef(foodSource); __result = true; return(false); } var comp = thing1.TryGetComp <CompRottable>(); if ((comp != null) && (comp.Stage == RotStage.Fresh) && (comp.TicksUntilRotAtCurrentTemp < 30000)) { foodSource = thing1; foodDef = FoodUtility.GetFinalIngestibleDef(foodSource); __result = true; return(false); } } } var getter1 = getter; var eater1 = eater; var desperate1 = desperate; var allowPlant = getter == eater; var allowDispenserEmpty = canRefillDispenser; var foodSource1 = FoodUtility.BestFoodSourceOnMap(getter1, eater1, desperate1, out var foodDef1, FoodPreferability.MealLavish, allowPlant, allowDrug, allowCorpse, true, allowDispenserEmpty, allowForbidden, allowSociallyImproper, allowHarvest, forceScanWholeMap); if ((thing1 != null) || (foodSource1 != null)) { if ((thing1 == null) && (foodSource1 != null)) { foodSource = foodSource1; foodDef = foodDef1; __result = true; return(false); } var finalIngestibleDef = FoodUtility.GetFinalIngestibleDef(thing1); if (foodSource1 == null) { foodSource = thing1; foodDef = finalIngestibleDef; __result = true; return(false); } if (FoodUtility.FoodOptimality(eater, foodSource1, foodDef1, (getter.Position - foodSource1.Position).LengthManhattan) > (double)(FoodUtility.FoodOptimality(eater, thing1, finalIngestibleDef, 0.0f) - 32f)) { foodSource = foodSource1; foodDef = foodDef1; __result = true; return(false); } foodSource = thing1; foodDef = FoodUtility.GetFinalIngestibleDef(foodSource); __result = true; return(false); } if (canUseInventory && flag) { var thing2 = FoodUtility.BestFoodInInventory(getter, eater, FoodPreferability.DesperateOnly, FoodPreferability.MealLavish, 0.0f, allowDrug); if (thing2 != null) { foodSource = thing2; foodDef = FoodUtility.GetFinalIngestibleDef(foodSource); __result = true; return(false); } } if ((foodSource1 == null) && (getter == eater) && (getter.RaceProps.predator || (getter.IsWildMan() && !getter.IsPrisoner))) { var huntForPredator = PrivateAccess.RimWorld_FoodUtility_BestPawnToHuntForPredator(getter, forceScanWholeMap); if (huntForPredator != null) { foodSource = huntForPredator; foodDef = FoodUtility.GetFinalIngestibleDef(foodSource); __result = true; return(false); } } foodSource = null; foodDef = null; __result = false; return(false); }