public static Thing TryGetBackpackLastItem(Pawn pawn)
        {
            Apparel_Backpack backpack = ToolsForHaulUtility.TryGetBackpack(pawn);

            if (backpack == null)
            {
                return(null);
            }
            Thing lastItem        = null;
            int   lastItemInd     = -1;
            Thing foodInInventory = FoodUtility.BestFoodInInventory(pawn);

            if (pawn.inventory.container.Count > 0)
            {
                if (backpack.numOfSavedItems > 0)
                {
                    lastItemInd = ((backpack.numOfSavedItems >= pawn.inventory.container.Count)?pawn.inventory.container.Count : backpack.numOfSavedItems) - 1;
                    lastItem    = pawn.inventory.container[lastItemInd];
                }
                if (foodInInventory != null && backpack.numOfSavedItems < pawn.inventory.container.Count &&
                    pawn.inventory.container[lastItemInd + 1] == foodInInventory)
                {
                    lastItem = foodInInventory;
                }
            }
            return(lastItem);
        }
예제 #2
0
        public static Toil CheckDuplicates(Toil jumpToil, TargetIndex CarrierInd, TargetIndex HaulableInd)
        {
            Toil toil = new Toil();

            toil.initAction = () =>
            {
                IntVec3 storeCell = IntVec3.Invalid;
                Pawn    actor     = toil.GetActor();

                TargetInfo target = toil.actor.jobs.curJob.GetTarget(HaulableInd);
                if (target.Thing.def.stackLimit <= 1)
                {
                    return;
                }
                List <TargetInfo> targetQueue = toil.actor.jobs.curJob.GetTargetQueue(HaulableInd);
                if (!targetQueue.NullOrEmpty() && target.Thing.def.defName == targetQueue.First().Thing.def.defName)
                {
                    toil.actor.jobs.curJob.SetTarget(HaulableInd, targetQueue.First());
                    Find.Reservations.Reserve(actor, targetQueue.First());
                    targetQueue.RemoveAt(0);
                    toil.actor.jobs.curDriver.JumpToToil(jumpToil);
                    return;
                }
                Vehicle_Cart     cart     = toil.actor.jobs.curJob.GetTarget(CarrierInd).Thing as Vehicle_Cart;
                Apparel_Backpack backpack = toil.actor.jobs.curJob.GetTarget(CarrierInd).Thing as Apparel_Backpack;
                if (cart == null && backpack == null)
                {
                    Log.Error(actor.LabelCap + " Report: Don't have Carrier");
                    toil.actor.jobs.curDriver.EndJobWith(JobCondition.Errored);
                    return;
                }
                int curItemCount = (cart != null ? cart.storage.Count : actor.inventory.container.Count) + targetQueue.Count;
                int curItemStack = (cart != null ? cart.storage.TotalStackCount : actor.inventory.container.TotalStackCount)
                                   + targetQueue.Sum(item => item.Thing.stackCount);
                int maxItem  = cart != null ? cart.MaxItem : backpack.MaxItem;
                int maxStack = cart != null ? cart.MaxStack : backpack.MaxStack;
                if (curItemCount >= maxItem || curItemStack >= maxStack)
                {
                    return;
                }
                //Check target's nearby
                Thing thing = GenClosest.ClosestThing_Global_Reachable(actor.Position,
                                                                       ListerHaulables.ThingsPotentiallyNeedingHauling(),
                                                                       PathEndMode.Touch,
                                                                       TraverseParms.For(actor, Danger.Some),
                                                                       NearbyCell,
                                                                       item => !targetQueue.Contains(item) &&
                                                                       item.def.defName == target.Thing.def.defName &&
                                                                       !FireUtility.IsBurning(item) &&
                                                                       Find.Reservations.CanReserve(actor, item));
                if (thing != null)
                {
                    toil.actor.jobs.curJob.SetTarget(HaulableInd, thing);
                    Find.Reservations.Reserve(actor, thing);
                    toil.actor.jobs.curDriver.JumpToToil(jumpToil);
                    return;
                }
            };
            return(toil);
        }
예제 #3
0
        public static Toil CheckNeedStorageCell(Toil jumpToil, TargetIndex CarrierInd, TargetIndex StoreCellInd)
        {
            Toil toil = new Toil();

            toil.initAction = () =>
            {
                Pawn actor = toil.actor;

                Vehicle_Cart     cart     = toil.actor.jobs.curJob.GetTarget(CarrierInd).Thing as Vehicle_Cart;
                Apparel_Backpack backpack = toil.actor.jobs.curJob.GetTarget(CarrierInd).Thing as Apparel_Backpack;
                if (cart == null && backpack == null)
                {
                    Log.Error(actor.LabelCap + " Report: Don't have Carrier");
                    toil.actor.jobs.curDriver.EndJobWith(JobCondition.Errored);
                }
                ThingContainer container = cart != null ? cart.storage : actor.inventory.container;
                if (container.Count == 0)
                {
                    return;
                }

                IntVec3 cell = ToolsForHaulUtility.FindStorageCell(actor, container.First());
                if (cell != IntVec3.Invalid)
                {
                    toil.actor.jobs.curJob.SetTarget(StoreCellInd, cell);
                    Find.Reservations.Reserve(actor, cell);
                    toil.actor.jobs.curDriver.JumpToToil(jumpToil);
                }
            };
            return(toil);
        }
        protected override IEnumerable <Toil> MakeNewToils()
        {
            Apparel_Backpack backpack = CurJob.GetTarget(BackpackInd).Thing as Apparel_Backpack;

            ///
            //Set fail conditions
            ///


            //Backpack is full.
            this.FailOn(() => { return((pawn.inventory.container.Count < backpack.MaxItem) ? false : true); });

            ///
            //Define Toil
            ///

            Toil extractB = new Toil();

            extractB.initAction = () =>
            {
                if (!CurJob.targetQueueB.NullOrEmpty())
                {
                    CurJob.targetB = CurJob.targetQueueB.First();
                    CurJob.targetQueueB.RemoveAt(0);
                    this.FailOnDestroyedOrNull(HaulableInd);
                }
                else
                {
                    this.EndJobWith(JobCondition.Succeeded);
                }
            };

            Toil toilGoToThing = Toils_Goto.GotoThing(HaulableInd, PathEndMode.ClosestTouch)
                                 .FailOnDestroyedOrNull(HaulableInd);

            ///
            //Toils Start
            ///

            //Reserve thing to be stored and storage cell
            yield return(Toils_Reserve.Reserve(BackpackInd));

            yield return(Toils_Reserve.Reserve(HaulableInd));

            yield return(Toils_Reserve.ReserveQueue(HaulableInd));


            yield return(Toils_Jump.JumpIf(toilGoToThing, () => { return (CurJob.targetB.HasThing) ? true : false; }));

            //Collect TargetQueue
            {
                //Extract an haulable into TargetA
                yield return(extractB);

                yield return(toilGoToThing);

                //CollectIntoCarrier
                Toil toilPutInInventory = new Toil();
                toilPutInInventory.initAction = () =>
                {
                    if (pawn.inventory.container.Count < backpack.MaxItem &&
                        backpack.wearer.inventory.container.TotalStackCount < backpack.MaxStack)
                    {
                        if (CurJob.targetB.Thing.TryGetComp <CompForbiddable>() != null && CurJob.targetB.Thing.TryGetComp <CompForbiddable>().Forbidden == true)
                        {
                            CurJob.targetB.Thing.TryGetComp <CompForbiddable>().Forbidden = false;
                        }
                        if (pawn.inventory.container.TryAdd(CurJob.targetB.Thing, CurJob.maxNumToCarry))
                        {
                            CurJob.targetB.Thing.holder       = pawn.inventory.GetContainer();
                            CurJob.targetB.Thing.holder.owner = pawn.inventory;
                            backpack.numOfSavedItems++;
                        }
                    }
                    else
                    {
                        this.EndJobWith(JobCondition.Incompletable);
                    }
                };
                yield return(toilPutInInventory);

                yield return(Toils_Jump.JumpIfHaveTargetInQueue(HaulableInd, extractB));
            }
        }
        public static Job HaulWithTools(Pawn pawn, Vehicle_Cart cart = null)
        {
            Trace.stopWatchStart();

            //Job Setting
            JobDef              jobDef;
            TargetInfo          targetC;
            int                 maxItem;
            int                 thresholdItem;
            int                 reservedMaxItem;
            IEnumerable <Thing> remainingItems;
            bool                ShouldDrop;
            Thing               lastItem = ToolsForHaulUtility.TryGetBackpackLastItem(pawn);

            if (cart == null)
            {
                Apparel_Backpack backpack = ToolsForHaulUtility.TryGetBackpack(pawn);
                jobDef          = jobDefHaulWithBackpack;
                targetC         = backpack;
                maxItem         = backpack.MaxItem;
                thresholdItem   = (int)Math.Ceiling(maxItem * 0.5);
                reservedMaxItem = pawn.inventory.container.Count;
                remainingItems  = pawn.inventory.container;
                ShouldDrop      = true;
                if (lastItem != null)
                {
                    for (int i = 0; i < pawn.inventory.container.Count; i++)
                    {
                        if (pawn.inventory.container[i] == lastItem && (reservedMaxItem - (i + 1)) <= 0)
                        {
                            ShouldDrop = false;
                            break;
                        }
                    }
                }
            }
            else
            {
                jobDef = (cart.TryGetComp <CompMountable>().IsMounted&& cart.TryGetComp <CompMountable>().Driver.RaceProps.Animal)?
                         jobDefHaulWithAnimalCart : jobDefHaulWithCart;
                targetC         = cart;
                maxItem         = cart.MaxItem;
                thresholdItem   = (int)Math.Ceiling(maxItem * 0.5);
                reservedMaxItem = cart.storage.Count;
                remainingItems  = cart.storage;
                ShouldDrop      = (reservedMaxItem > 0) ? true : false;
            }
            Job job = new Job(jobDef);

            job.targetQueueA = new List <TargetInfo>();
            job.targetQueueB = new List <TargetInfo>();
            job.targetC      = targetC;

            Trace.AppendLine(pawn.LabelCap + " In HaulWithTools: " + jobDef.defName + "\n"
                             + "MaxItem: " + maxItem + " reservedMaxItem: " + reservedMaxItem);

            //Drop remaining item
            if (ShouldDrop)
            {
                Trace.AppendLine("Start Drop remaining item");
                bool startDrop = false;
                for (int i = 0; i < remainingItems.Count(); i++)
                {
                    if (cart == null && startDrop == false)
                    {
                        if (remainingItems.ElementAt(i) == lastItem)
                        {
                            startDrop = true;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    IntVec3 storageCell = FindStorageCell(pawn, remainingItems.ElementAt(i), job.targetQueueB);
                    if (storageCell == IntVec3.Invalid)
                    {
                        break;
                    }
                    job.targetQueueB.Add(storageCell);
                }
                if (!job.targetQueueB.NullOrEmpty())
                {
                    Trace.AppendLine("Droping Job is issued");
                    Trace.LogMessage();
                    return(job);
                }
                if (cart != null && job.def == jobDefHaulWithCart && !cart.IsInValidStorage())
                {
                    Trace.AppendLine("In DismountInBase");
                    return(DismountInBase(pawn, cart));
                }
                JobFailReason.Is(ToolsForHaulUtility.NoEmptyPlaceLowerTrans);
                Trace.AppendLine("End Drop remaining item");
                Trace.AppendLine("No Job. Reason: " + JobFailReason.Reason);
                Trace.LogMessage();
                return((Job)null);
            }

            //Collect item
            Trace.AppendLine("Start Collect item");
            IntVec3 searchPos = (cart != null) ? cart.Position : pawn.Position;
            bool    flag1     = false;

            foreach (SlotGroup slotGroup in Find.SlotGroupManager.AllGroupsListInPriorityOrder)
            {
                Trace.AppendLine("Start searching slotGroup");
                if (slotGroup.CellsList.Count() - slotGroup.HeldThings.Count() < maxItem)
                {
                    continue;
                }

                //Counting valid items
                Trace.AppendLine("Start Counting valid items");
                int thingsCount = ListerHaulables.ThingsPotentiallyNeedingHauling().Count(item => slotGroup.Settings.AllowedToAccept(item));

                //Finding valid items
                Trace.AppendLine("Start Finding valid items");
                if (thingsCount > thresholdItem)
                {
                    //ClosestThing_Global_Reachable Configuration
                    Predicate <Thing> predicate = item
                                                  => !job.targetQueueA.Contains(item) && !FireUtility.IsBurning(item) &&
                                                  ((cart != null && cart.allowances.Allows(item)) || cart == null) &&
                                                  slotGroup.Settings.AllowedToAccept(item) &&
                                                  pawn.CanReserveAndReach(item, PathEndMode.Touch, DangerUtility.NormalMaxDanger(pawn));
                    //&& !(item is UnfinishedThing && ((UnfinishedThing)item).BoundBill != null)
                    //&& (item.def.IsNutritionSource && !SocialProperness.IsSociallyProper(item, pawn, false, false));
                    Thing thing = GenClosest.ClosestThing_Global_Reachable(searchPos,
                                                                           ListerHaulables.ThingsPotentiallyNeedingHauling(),
                                                                           PathEndMode.ClosestTouch,
                                                                           TraverseParms.For(TraverseMode.ByPawn, DangerUtility.NormalMaxDanger(pawn)),
                                                                           9999,
                                                                           predicate);
                    if (thing == null)
                    {
                        continue;
                    }
                    IntVec3 center = thing.Position;

                    //Enqueue items in valid distance
                    Trace.AppendLine("Start Enqueuing items in valid distance");
                    foreach (Thing item in ListerHaulables.ThingsPotentiallyNeedingHauling().Where(item
                                                                                                   => !job.targetQueueA.Contains(item) && !FireUtility.IsBurning(item) &&
                                                                                                   ((cart != null && cart.allowances.Allows(item)) || cart == null) &&
                                                                                                   slotGroup.Settings.AllowedToAccept(item) &&
                                                                                                   pawn.CanReserveAndReach(item, PathEndMode.Touch, DangerUtility.NormalMaxDanger(pawn)) &&
                                                                                                   center.DistanceToSquared(item.Position) <= ValidDistance))
                    {
                        job.targetQueueA.Add(item);
                        if (reservedMaxItem + job.targetQueueA.Count >= maxItem)
                        {
                            break;
                        }
                    }

                    //Find storage cell
                    Trace.AppendLine("Start Finding storage cell");
                    if (reservedMaxItem + job.targetQueueA.Count > thresholdItem)
                    {
                        List <IntVec3> availableCells = new List <IntVec3>();
                        foreach (IntVec3 cell in slotGroup.CellsList.Where(cell => ReservationUtility.CanReserve(pawn, cell) && cell.Standable() && cell.GetStorable() == null))
                        {
                            job.targetQueueB.Add(cell);
                            if (job.targetQueueB.Count >= job.targetQueueA.Count)
                            {
                                break;
                            }
                        }
                        flag1 = true;
                        break;
                    }
                    else
                    {
                        job.targetQueueA.Clear();
                    }
                }
                if (flag1)
                {
                    break;
                }
            }
            Trace.AppendLine("Elapsed Time");
            Trace.stopWatchStop();

            //Check job is valid
            if (!job.targetQueueA.NullOrEmpty() && reservedMaxItem + job.targetQueueA.Count > thresholdItem &&
                !job.targetQueueB.NullOrEmpty())
            {
                Trace.AppendLine("Hauling Job is issued");
                Trace.LogMessage();
                return(job);
            }
            if (cart != null && job.def == jobDefHaulWithCart && !cart.IsInValidStorage())
            {
                Trace.AppendLine("In DismountInBase: ");
                return(DismountInBase(pawn, cart));
            }

            if (job.targetQueueA.NullOrEmpty())
            {
                JobFailReason.Is(ToolsForHaulUtility.NoHaulable);
            }
            else if (reservedMaxItem + job.targetQueueA.Count <= thresholdItem)
            {
                JobFailReason.Is(ToolsForHaulUtility.TooLittleHaulable);
            }
            else if (job.targetQueueB.NullOrEmpty())
            {
                JobFailReason.Is(ToolsForHaulUtility.NoEmptyPlaceLowerTrans);
            }
            Trace.AppendLine("No Job. Reason: " + JobFailReason.Reason);
            Trace.LogMessage();
            return((Job)null);
        }
        protected override IEnumerable <Toil> MakeNewToils()
        {
            Apparel_Backpack backpack = CurJob.GetTarget(BackpackInd).Thing as Apparel_Backpack;
            Thing            lastItem = ToolsForHaulUtility.TryGetBackpackLastItem(pawn);

            ///
            //Set fail conditions
            ///

            ///
            //Define Toil
            ///

            Toil endOfJob = new Toil();

            endOfJob.initAction = () => { EndJobWith(JobCondition.Succeeded); };
            Toil checkStoreCellEmpty = Toils_Jump.JumpIf(endOfJob, () => CurJob.GetTargetQueue(StoreCellInd).NullOrEmpty());
            Toil checkHaulableEmpty  = Toils_Jump.JumpIf(checkStoreCellEmpty, () => CurJob.GetTargetQueue(HaulableInd).NullOrEmpty());

            ///
            //Toils Start
            ///

            //Reserve thing to be stored and storage cell
            yield return(Toils_Reserve.ReserveQueue(HaulableInd));

            yield return(Toils_Reserve.ReserveQueue(StoreCellInd));

            //JumpIf checkStoreCellEmpty
            yield return(checkHaulableEmpty);

            //Collect TargetQueue
            {
                Toil extractA = Toils_Collect.Extract(HaulableInd);
                yield return(extractA);

                Toil gotoThing = Toils_Goto.GotoThing(HaulableInd, PathEndMode.ClosestTouch)
                                 .FailOnDestroyed(HaulableInd);
                yield return(gotoThing);

                yield return(ToolsForHaul.Toils_Collect.CollectInInventory(HaulableInd));

                yield return(Toils_Collect.CheckDuplicates(gotoThing, BackpackInd, HaulableInd));

                yield return(Toils_Jump.JumpIfHaveTargetInQueue(HaulableInd, extractA));
            }

            //JumpIf toilEnd
            yield return(checkStoreCellEmpty);

            //Drop TargetQueue
            {
                Toil extractB = Toils_Collect.Extract(StoreCellInd);
                yield return(extractB);

                yield return(Toils_Goto.GotoCell(StoreCellInd, PathEndMode.ClosestTouch)
                             .FailOnBurningImmobile(StoreCellInd));

                yield return(ToolsForHaul.Toils_Collect.DropTheCarriedInCell(StoreCellInd, ThingPlaceMode.Direct, lastItem));

                yield return(Toils_Jump.JumpIfHaveTargetInQueue(StoreCellInd, extractB));
            }

            yield return(endOfJob);
        }