internal static Thing _BestFoodSourceFor(Pawn getter, Pawn eater, bool fullDispensersOnly, out ThingDef foodDef) { var dispenserValidator = new DispenserValidator(); dispenserValidator.getter = getter; dispenserValidator.fullDispensersOnly = fullDispensersOnly; Thing bestFoodSpawnedFor = FoodUtility.BestFoodSpawnedFor(getter, eater, getter == eater); if ( (getter == eater) && (getter.RaceProps.predator) && (bestFoodSpawnedFor == null) ) { Pawn prey = BestPawnToHuntForPredator(getter); if (prey != null) { foodDef = prey.RaceProps.corpseDef; return((Thing)prey); } } if (getter.RaceProps.ToolUser) { // Try to find a working nutrient paste dispenser or food sythesizer var validatorPredicate = new Predicate <Thing>(dispenserValidator.Validate); var dispensers = Find.ListerThings.AllThings.Where(t => ( (t is Building_NutrientPasteDispenser) || ( (t is Building_AutomatedFactory) && (((Building_AutomatedFactory)t).CompAutomatedFactory.Properties.outputVector == FactoryOutputVector.DirectToPawn) ) )); if (dispensers.Any()) { // Check dispenses and synthesizers (automated factories) if (bestFoodSpawnedFor != null) { // Compare with best spawned meal float dist = (getter.Position - bestFoodSpawnedFor.Position).LengthManhattan; dispenserValidator.meal.thing = bestFoodSpawnedFor; dispenserValidator.meal.def = bestFoodSpawnedFor.def; dispenserValidator.meal.score = FoodOptimality(bestFoodSpawnedFor, dist); } else { // Nothing to compare to dispenserValidator.meal.thing = null; dispenserValidator.meal.def = null; dispenserValidator.meal.score = FoodOptimalityUnusable; } // Now find the best/closest dispenser var dispenser = GenClosest.ClosestThingReachable( getter.Position, ThingRequest.ForUndefined(), PathEndMode.InteractionCell, TraverseParms.For( dispenserValidator.getter, dispenserValidator.getter.NormalMaxDanger()), 9999f, validatorPredicate, dispensers, -1, true); if (dispenser != null) { // Found a dispenser/synthesizer and it's better than the spawned meal foodDef = dispenserValidator.meal.def; return(dispenser); } } } foodDef = bestFoodSpawnedFor == null ? null : bestFoodSpawnedFor.def; return(bestFoodSpawnedFor); }
internal static Thing _BestFoodSourceOnMap(Pawn getter, Pawn eater, bool desperate, FoodPreferability maxPref = FoodPreferability.MealLavish, bool allowPlant = true, bool allowLiquor = true, bool allowCorpse = true, bool allowDispenserFull = true, bool allowDispenserEmpty = true, bool allowForbidden = false) { 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(string.Format("{0} tried to find food to bring to {1} but {0} is incapable of Manipulation.", getter.LabelCap, eater.LabelCap)); Profiler.EndSample(); return(null); } var validator = new DispenserValidator(); validator.getterCanManipulate = getterCanManipulate; validator.allowDispenserFull = allowDispenserFull; validator.maxPref = maxPref; validator.allowForbidden = allowForbidden; validator.getter = getter; validator.allowDispenserEmpty = allowDispenserEmpty; validator.allowCorpse = allowCorpse; validator.allowLiquor = allowLiquor; validator.desperate = desperate; validator.eater = eater; validator.allowLiquor &= !desperate; validator.minPref = desperate ? FoodPreferability.DesperateOnly : !eater.RaceProps.Humanlike ? FoodPreferability.NeverForNutrition : eater.needs.food.CurCategory >= HungerCategory.UrgentlyHungry ? FoodPreferability.RawBad : FoodPreferability.MealAwful; var thingRequest = ( ((eater.RaceProps.foodType & (FoodTypeFlags.Plant | FoodTypeFlags.Tree)) == FoodTypeFlags.None) || (!allowPlant) ) ? ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree) : ThingRequest.ForGroup(ThingRequestGroup.FoodSource); var thingsRequested = Find.ListerThings.ThingsMatching(thingRequest); //DumpThingsRequestedForGroup( thingRequest, thingsRequested ); var potentialFoodSource = (Thing)null; if (getter.RaceProps.Humanlike) { //CCL_Log.Message( "Humanlike inner scan..." ); potentialFoodSource = SpawnedFoodSearchInnerScan( eater, getter.Position, thingsRequested, PathEndMode.ClosestTouch, TraverseParms.For( getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator.ValidateFast); } else { //CCL_Log.Message( "Non-humanlike closest reachable..." ); int searchRegionsMax = 30; if (getter.Faction == Faction.OfPlayer) { searchRegionsMax = 60; } potentialFoodSource = GenClosest.ClosestThingReachable( getter.Position, thingRequest, PathEndMode.ClosestTouch, TraverseParms.For( getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator.Validate, null, searchRegionsMax, false); if (potentialFoodSource == null) { //CCL_Log.Message( "Non-humanlike closest reachable desperate..." ); validator.desperate = true; potentialFoodSource = GenClosest.ClosestThingReachable( getter.Position, thingRequest, PathEndMode.ClosestTouch, TraverseParms.For( getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator.ValidateFast, null, searchRegionsMax, false); } } Profiler.EndSample(); //CCL_Log.Message( string.Format( "{0} picked {1} for {2}", getter.LabelShort, potentialFoodSource == null ? "nothing" : potentialFoodSource.ThingID, eater.LabelShort ) ); return(potentialFoodSource); }