public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_Shelf shelf = t as Building_Shelf;

            if (shelf == null || !shelf.HasEmptyCell())
            {
                return(false);
            }

            if (!shelf.slotGroup.EmptyCells().Any(cell =>
                                                  pawn.CanReserveAndReach(new LocalTargetInfo(cell), PathEndMode.Touch, pawn.NormalMaxDanger(), 1, -1, null, false)))
            {
                return(false);
            }

            LocalTargetInfo target = t;

            if (!pawn.CanReserve(target, 1, -1, null, false))
            {
                JobFailReason.Is("ShelfReserved".Translate());
                return(false);
            }

            foreach (SlotGroup sg in pawn.Map?.haulDestinationManager.AllGroupsListInPriorityOrder ?? Enumerable.Empty <SlotGroup>())
            {
                if (sg.Settings.Priority > shelf.settings.Priority ||
                    ((sg.Settings.Priority == shelf.settings.Priority) && (sg.parent is Building_Shelf)) ||
                    sg.parent == shelf)
                {
                    continue;
                }
                else
                {
                    foreach (Thing thing in sg.HeldThings)
                    {
                        if ((thing.stackCount >= thing.def.stackLimit || forced) && shelf.settings.filter.Allows(thing) &&
                            StockingUtility.PawnCanAutomaticallyHaul(pawn, thing, forced, shelf.InForbiddenMode))
                        {
                            return(true);
                        }
                    }
                }
            }
            if (!JobFailReason.HaveReason)
            {
                JobFailReason.Is("FillEmptyStock_NoItemsFound_JobFailReason".Translate());
            }
            if (JobFailReason.Reason == "ForbiddenLower".Translate())
            {
                JobFailReason.Is("FillEmptyStock_AllItemsFoundAreForbidden_JobFailReason".Translate());
            }
            return(false);
        }
        public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_Shelf shelf      = t as Building_Shelf;
            List <Thing>   potentials = new List <Thing> ();

            if (shelf == null)
            {
                return(null);
            }

            foreach (SlotGroup sg in pawn.Map?.haulDestinationManager.AllGroupsListInPriorityOrder ?? Enumerable.Empty <SlotGroup>())
            {
                if (sg.Settings.Priority > shelf.settings.Priority ||
                    ((sg.Settings.Priority == shelf.settings.Priority) && (sg.parent is Building_Shelf)))
                {
                    continue;
                }
                else
                {
                    foreach (Thing thing in sg.HeldThings)
                    {
                        if ((thing.stackCount >= thing.def.stackLimit || forced) && shelf.settings.filter.Allows(thing) &&
                            StockingUtility.PawnCanAutomaticallyHaul(pawn, thing, forced, shelf.InForbiddenMode))
                        {
                            potentials.Add(thing);
                        }
                    }
                }
            }

            int   minDist = 200000000;
            float maxPartialFullStackFound = 0f;
            Thing chosenThing = null;

            foreach (Thing thing in potentials)                 //I KNOW THIS IS TERRIBLE, BUT I LOVE IT ANYWAYS
            {
                int dist = (thing.Position - pawn.Position).LengthHorizontalSquared + (thing.Position - shelf.Position).LengthHorizontalSquared;
                if (forced)
                {
                    float part = (float)thing.stackCount / (float)thing.def.stackLimit;
                    if (part < maxPartialFullStackFound)
                    {
                        continue;
                    }
                    if (part > maxPartialFullStackFound)
                    {
                        maxPartialFullStackFound = part;
                        chosenThing = thing;
                        minDist     = dist;
                        continue;
                    }
                }
                if (dist < minDist)
                {
                    minDist     = dist;
                    chosenThing = thing;
                }
            }

            if (chosenThing == null)
            {
                return(null);
            }
            IntVec3 destEmptyCell = shelf.slotGroup.EmptyCells().FirstOrDefault(cell =>
                                                                                pawn.CanReserveAndReach(new LocalTargetInfo(cell), PathEndMode.Touch, pawn.NormalMaxDanger(), 1, -1, null, false));

            if (destEmptyCell == default(IntVec3))
            {
                return(null);
            }
            Job job = new Job(StockingJobDefOf.FillEmptyStock, chosenThing, destEmptyCell, shelf);

            job.haulOpportunisticDuplicates = true;
            job.haulMode = HaulMode.ToCellStorage;
            job.count    = chosenThing.stackCount;

            return(job);
        }