public static Thing BestWaterSpawnedFor(Pawn getter, float wantedLitres, Predicate<Thing> validator = null, IntVec3? near = null, bool allowPleasureDrug = true) { if (!near.HasValue) { near = getter.Position; } Predicate<Thing> baseValidator; if (validator == null) { baseValidator = (Thing t) => { return (!t.IsForbidden(getter) && t.IsSociallyProper(getter) && getter.AnimalAwareOfEx(t) && (!ShouldReserveWaterSource(t, wantedLitres) || getter.CanReserve(t, 1))); }; } else { baseValidator = (Thing t) => { return (!t.IsForbidden(getter) && t.IsSociallyProper(getter) && getter.AnimalAwareOfEx(t) && (!ShouldReserveWaterSource(t, wantedLitres) || getter.CanReserve(t, 1)) && validator(t)); }; } // Can drink from anything that is a non-empty water container. Predicate<Thing> toolValidator = (Thing t) => { if (!baseValidator(t)) { return false; } var wc = t.TryGetComp<CompWaterContainer>(); return (wc != null && wc.StoredLitres > 0); }; // Can drink from anything that is a non-empty water container, but only if // it doesn't require tool use. Predicate<Thing> noToolValidator = (Thing t) => { if (!baseValidator(t)) { return false; } var wc = t.TryGetComp<CompWaterContainer>(); return (wc != null && wc.StoredLitres > 0 && !wc.props.needsToolUser); }; // Prefer a water source that has at least as much as we want. // Otherwise prefer the one with the most. Func<Thing, int> priorityGetter = (Thing t) => { var wc = t.TryGetComp<CompWaterContainer>(); if (wc == null) { return -1; } if (wc.StoredLitres >= wantedLitres) { return int.MaxValue; } return (int) Math.Round(wc.StoredLitres, 0, MidpointRounding.AwayFromZero); }; // TODO: may be able to narrow down the ThingRequestGroup. var allThings = ThingRequest.ForGroup(ThingRequestGroup.Everything); var traverse = TraverseParms.For(getter, Danger.Deadly, TraverseMode.ByPawn); Predicate<Thing> searchValidator = toolValidator; if (!getter.RaceProps.ToolUser) { searchValidator = noToolValidator; } Thing result = GenClosest.RegionwiseBFSWorker( near.Value, allThings, PathEndMode.ClosestTouch, traverse, searchValidator, priorityGetter, 9, 30, 9999f); return result; }