private bool ValidatePreferences(FoodSearchItem item)
        {
            // Only care about preferences at all if not desperate or animalistic
            if (parameters.Desperate || parameters.Eater.IsWildAnimal() || parameters.Eater.IsWildMan())
            {
                return(true);
            }


            if (item.Def.ingestible.preferability > parameters.MaxPref)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: preferability {item.Def.ingestible.preferability} exceeds requested maximum {parameters.MaxPref}");
                return(false);
            }

            if (item.Thing.Faction != parameters.Getter.Faction &&
                item.Thing.Faction != parameters.Getter.HostFaction)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} not owner or guest of {item.Thing.Faction}");
                return(false);
            }

            if (!parameters.AllowCorpse && (item.Thing is Corpse))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is corpse");
                return(false);
            }

            if (!parameters.AllowDrug && item.Def.IsDrug)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is drug");
                return(false);
            }

            if (!parameters.AllowSociallyImproper && !item.Thing.IsSociallyProper(parameters.Eater))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is not socially proper for {parameters.Eater}");
                return(false);
            }


            // Animals don't have thoughts (fixing null bug in alien framework patch intercepting pets)
            if (parameters.Eater.IsAnimal())
            {
                return(true);
            }


            var thoughtsFromConsuming         = FoodUtility.ThoughtsFromIngesting(parameters.Eater, item.Thing, item.Def);
            var desperateThoughtFromConsuming = thoughtsFromConsuming.FirstOrDefault(DesperateOnlyThoughts.Contains);

            if (desperateThoughtFromConsuming != null)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: would cause desperate thought {desperateThoughtFromConsuming}");
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Validates that the given item is eligible for eating in this situation
        /// </summary>
        /// <remarks>
        /// Performing validation checks as late as possible maximizes optimistic performance
        /// </remarks>
        private bool Validate(FoodSearchItem item)
        {
            if (!parameters.AllowForbidden && item.Thing.IsForbidden(parameters.Getter))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is forbidden to {parameters.Getter}");
                return(false);
            }

            if ((!parameters.Getter.RaceProps.ToolUser || !parameters.Getter.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || !parameters.CanUseInventory) &&
                parameters.Getter.inventory.Contains(item.Thing))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} cannot use item from his invenory in this situation");
                return(false);
            }

            if (!parameters.Getter.CanReserve(item.Thing, stackCount: 1))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} cannot reserve any from stack");
                return(false);
            }

            if (!parameters.Eater.WillEat(item.Def, parameters.Getter))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Eater} will not eat def {item.Def}");
                return(false);
            }

            if (!ValidateHunt(item))
            {
                return(false);
            }

            if (!ValidatePlant(item))
            {
                return(false);
            }

            if (!ValidateDispenser(item))
            {
                return(false);
            }

            if (!ValidatePreferences(item))
            {
                return(false);
            }

            // Potentially expensive path calculation last
            if (!item.IsInInventory &&
                !parameters.Getter.CanReach(new LocalTargetInfo(item.Position), Verse.AI.PathEndMode.OnCell, Danger.Unspecified, parameters.Desperate))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} cannot reach");
                return(false);
            }

            return(true);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Validates that the given item is eligible for eating in this situation
        /// </summary>
        /// <remarks>
        /// Performing validation checks as late as possible maximizes optimistic performance
        /// </remarks>
        private bool Validate(FoodSearchItem item)
        {
            if (!parameters.AllowForbidden && item.Thing.IsForbidden(parameters.Getter))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is forbidden to {parameters.Getter}");
                return(false);
            }

            if (!parameters.CanUseInventory && item.IsInInventory)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is in inventory");
                return(false);
            }

            if (!parameters.Getter.CanReserve(item.Thing, stackCount: 1))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} cannot reserve any from stack");
                return(false);
            }

            if (!parameters.Eater.WillEat(item.Def, parameters.Getter))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Eater} will not eat def {item.Def}");
                return(false);
            }

            if (!ValidateHunt(item))
            {
                return(false);
            }

            if (!ValidatePlant(item))
            {
                return(false);
            }

            if (!ValidateDispenser(item))
            {
                return(false);
            }

            if (!ValidatePreferences(item))
            {
                return(false);
            }

            // Potentially expensive path calculation last
            if (!item.IsInInventory &&
                !parameters.Getter.CanReach(new LocalTargetInfo(item.Position), Verse.AI.PathEndMode.OnCell, Danger.Unspecified, parameters.Desperate))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} cannot reach");
                return(false);
            }

            return(true);
        }
        private bool ValidateDispenser(FoodSearchItem item)
        {
            var nutrientPasteDispenser = item.Thing as Building_NutrientPasteDispenser;

            if (nutrientPasteDispenser == null)
            {
                return(true);
            }


            // Vanilla disallow logic:
            // !allowDispenserFull
            // || !getterCanManipulate
            // || (ThingDefOf.MealNutrientPaste.ingestible.preferability < minPref
            //     || ThingDefOf.MealNutrientPaste.ingestible.preferability > maxPref)
            // || (!eater.WillEat(ThingDefOf.MealNutrientPaste, getter)
            //     || t.Faction != getter.Faction
            //     && t.Faction != getter.HostFaction)
            // || (!allowForbidden && t.IsForbidden(getter)
            //     || !nutrientPasteDispenser.powerComp.PowerOn
            //     || (!allowDispenserEmpty
            //         && !nutrientPasteDispenser.HasEnoughFeedstockInHoppers()
            //         || (!t.InteractionCell.Standable(t.Map)
            //             || !FoodUtility.IsFoodSourceOnMapSociallyProper(t, getter, eater, allowSociallyImproper))))
            // || (getter.IsWildMan()
            //     || !getter.Map.reachability.CanReachNonLocal(getter.Position, new TargetInfo(t.InteractionCell, t.Map, false), PathEndMode.OnCell, TraverseParms.For(getter, Danger.Some, TraverseMode.ByPawn, false)))

            if (!parameters.AllowDispenserFull)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: search requested no dispensers");
                return(false);
            }

            if (!parameters.Getter.CanManipulate())
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} cannot manipulate dispenser");
                return(false);
            }

            if (!nutrientPasteDispenser.CanDispenseNow)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: dispenser cannot dispense now");
                return(false);
            }

            if (!nutrientPasteDispenser.InteractionCell.Standable(item.Thing.Map))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: dispenser interaction cell not standable");
                return(false);
            }

            return(true);
        }
        private bool ValidatePlant(FoodSearchItem item)
        {
            if (item.Def.plant == null)
            {
                return(true);
            }

            var plant = item.Thing as Plant;

            if (plant == null)
            {
                return(true);
            }


            if (!parameters.AllowPlant)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: is plant");
                return(false);
            }

            // TODO: harvestable plants
            if (parameters.AllowHarvest &&
                plant.HarvestableNow &&
                item.Def.plant.harvestedThingDef.IsIngestible)
            {
                traceOutput?.AppendLine("TODO: harvest plant?");
                // var harvestedThingDef = thing.def.plant.harvestedThingDef;

                // Vanilla harvest logic?
                //Thing foodSource = GenClosest.ClosestThingReachable(getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.HarvestablePlant), PathEndMode.Touch, TraverseParms.For(getter, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, (Predicate<Thing>)(x =>
                //{
                //    Plant t = (Plant)x;
                //    if (!t.HarvestableNow)
                //        return false;
                //    ThingDef harvestedThingDef = t.def.plant.harvestedThingDef;
                //    return harvestedThingDef.IsNutritionGivingIngestible && eater.WillEat(harvestedThingDef, getter) && getter.CanReserve((LocalTargetInfo)((Thing)t), 1, -1, (ReservationLayerDef)null, false) && ((allowForbidden || !t.IsForbidden(getter)) && (bestThing == null || FoodUtility.GetFinalIngestibleDef(bestThing, false).ingestible.preferability < harvestedThingDef.ingestible.preferability));
                //}), (IEnumerable<Thing>)null, 0, searchRegionsMax, false, RegionType.Set_Passable, false);
                //if (foodSource != null)
                //{
                //    bestThing = foodSource;
                //    foodDef = FoodUtility.GetFinalIngestibleDef(foodSource, true);
                //}
            }

            if (parameters.Getter != parameters.Eater)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: pawns should not carry plants");
                return(false);
            }

            return(true);
        }
        private bool ValidateHunt(FoodSearchItem item)
        {
            if (item.FoodCategory != FoodCategory.Hunt)
            {
                return(true);
            }


            if (parameters.Getter != parameters.Eater)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: will not hunt for others");
                return(false);
            }

            if (parameters.Getter == item.Thing)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: {parameters.Getter} will not hunt self");
                return(false);
            }

            var pawn = item.Thing as Pawn;

            if (pawn == null)
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: unable to find Pawn reference for hunting evaluation");
                return(false);
            }

            if (!FoodUtility.IsAcceptablePreyFor(parameters.Getter, pawn))
            {
                traceOutput?.AppendLine($"Rejecting {item.Thing}: not acceptable prey for {parameters.Getter}");
                return(false);
            }

            return(true);
        }
 public FoodSearchResult(FoodSearchItem foodSearchItem)
 {
     Thing   = foodSearchItem.Thing;
     Def     = foodSearchItem.Def;
     Success = true;
 }