Пример #1
0
        public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_GrowerBase_WorkTable grower = t as Building_GrowerBase_WorkTable;

            if (grower == null)
            {
                return(false);
            }

            if (!grower.GrowerProps.productRequireManualExtraction)
            {
                return(false);
            }

            if (t.IsForbidden(pawn))
            {
                return(false);
            }

            if (!pawn.CanReserve(t))
            {
                return(false);
            }

            if (grower.status != CrafterStatus.Finished)
            {
                return(false);
            }

            return(true);
        }
        }//end JobOnThing()

        /// <summary>
        /// Checks if a pawn can be assigned to a bill based on factors including PawnRestrictions, workSkills, etc.
        /// If a bill passes all the checks, it's assigned as the ActiveBill in the billProcessor.
        /// </summary>
        /// <param name="p"></param>
        /// <param name="grower"></param>
        /// <param name="reason"></param>
        /// <returns></returns>
        public Bill GetBillPawnCanDo(Pawn p, Building_GrowerBase_WorkTable grower, out string reason)
        {
            reason = GenericFailReasonTrans;

            BillStack       bills  = grower.billStack;
            LocalTargetInfo target = grower;

            //loop through bills
            for (int i = 0; i < bills.Count; i++)
            {
                Bill_Production theBill = bills[i] as Bill_Production;

                if (!PawnCanDoThisBill(p, theBill, target, out reason))
                {
                    continue;
                }

                //check if cached ingredients search found ingredients for this bill
                Thing cachedThing;
                grower.billProc.ingredientsAvailableNow.TryGetValue(theBill.GetUniqueLoadID(), out cachedThing);
                if (cachedThing == null)
                {
                    QEEMod.TryLog("GetBillPawnCanDo - no ingredients available");
                    reason = NoIngredientsTrans;
                    continue;
                }

                grower.billProc.ActiveBill = theBill;
                QEEMod.TryLog(p.LabelShort + " can do bill " + theBill.GetUniqueLoadID());
                return(theBill);
            }
            return(null);
        } //end GetBillPawnCanDo()
Пример #3
0
        public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_GrowerBase_WorkTable grower = t as Building_GrowerBase_WorkTable;

            Job job = new Job(QEJobDefOf.QE_ExtractProductFromGrowerJob, t);

            return(job);
        }
Пример #4
0
        public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_GrowerBase_WorkTable grower = t as Building_GrowerBase_WorkTable;

            if (grower == null)
            {
                return(false);
            }

            IMaintainableGrower maintainable = grower as IMaintainableGrower;

            if (maintainable == null)
            {
                return(false);
            }

            if (t.IsForbidden(pawn))
            {
                return(false);
            }

            if (!pawn.CanReserve(t))
            {
                return(false);
            }

            if (grower.status != CrafterStatus.Crafting)
            {
                return(false);
            }

            bool shouldMaintainScience = true;

            if (maintainable.ScientistMaintenance > QEESettings.instance.maintWorkThresholdFloat)
            {
                if (maintainable.ScientistMaintenance > 0.90f)
                {
                    shouldMaintainScience = false;
                }
                shouldMaintainScience = forced;
            }

            bool shouldMaintainDoctor = true;

            if (maintainable.DoctorMaintenance > QEESettings.instance.maintWorkThresholdFloat)
            {
                if (maintainable.DoctorMaintenance > 0.90f)
                {
                    shouldMaintainDoctor = false;
                }
                shouldMaintainDoctor = forced;
            }

            bool maintainAtAll = shouldMaintainScience || shouldMaintainDoctor;

            return(maintainAtAll);
        }
Пример #5
0
        /// <summary>
        /// Finds the closest Thing on the map to a pawn that matches the ThingDef needed by the Bill.
        /// The available ingredients are cached in the BillProcessor variable in Building_GrowerBase_WorkTable.
        /// If the cached ThingDef is no longer available, it will look for another ThingDef that's needed.
        /// </summary>
        /// <param name="theBill"></param>
        /// <param name="finder"></param>
        /// <param name="countForVat"></param>
        /// <returns></returns>
        public static Thing ThingPawnShouldRetrieveForBill(Bill theBill, Pawn finder, ref int countForVat)
        {
            Building_GrowerBase_WorkTable vat = theBill.billStack.billGiver as Building_GrowerBase_WorkTable;
            ThingOwner vatStoredIngredients   = vat.GetDirectlyHeldThings();

            Thing cachedThing     = null;
            bool  ingAreAvailable = vat.billProc.ingredientsAvailableNow.TryGetValue(theBill.GetUniqueLoadID(), out cachedThing);

            if (cachedThing == null)
            {
                QEEMod.TryLog("ThingPawnShouldRetrieveForBill() returning null. Reason - cachedThing is null");
                return(null);
            }

            if (ingAreAvailable == false)
            {
                QEEMod.TryLog("ThingPawnShouldRetrieveForBill() returning null. Reason - ingAreAvailable is false");
                return(null);
            }

            ThingRequest      tRequest;
            ThingOrderRequest desiredRequest;

            vat.billProc.desiredRequests.TryGetValue(cachedThing.def.defName, out desiredRequest);

            //check that the vat still needs the cached ingredient before searching the map for the same ThingDef
            if (desiredRequest == null || desiredRequest.amount <= 0)
            {
                QEEMod.TryLog("Cached ingredient " + cachedThing.LabelShort + " is already fulfilled in vat. Looking for next ingredient in recipe");

                //this ingredient isn't in desiredIngredients or the vat has the full amount. Refresh desiredIngredients and try once more
                vat.billProc.UpdateDesiredRequests();

                //now get a random item in the dictionary of desired requests
                foreach (ThingOrderRequest value in vat.billProc.desiredRequests.Values)
                {
                    desiredRequest = value;
                }

                //return if there's no thingDef or desiredRequest is null
                if (desiredRequest == null)
                {
                    QEEMod.TryLog("ThingPawnShouldRetrieveForBill() returning null. Reason - Desired ThingOrderRequest is null");
                    return(null);
                }

                //return if the amount for this request is 0
                if (desiredRequest.amount <= 0)
                {
                    QEEMod.TryLog("ThingPawnShouldRetrieveForBill() returning null. Reason - Desired Thing " + desiredRequest.Label + " has 0 amount");
                    return(null);
                }
            }

            tRequest = desiredRequest.GetThingRequest();

            if (tRequest.IsUndefined)
            {
                QEEMod.TryLog("ThingPawnShouldRetrieveForBill() returning null. Reason - ThingRequest for " + desiredRequest.Label +
                              " returned undefined ThingRequest");
                return(null);
            }

            countForVat = desiredRequest.amount;


            QEEMod.TryLog("Searching map for closest " + desiredRequest.Label + " to " + finder.LabelShort);

            //search the map for the closest Thing to the pawn that matches the ThingDef in 'tRequest'
            Thing result = GenClosest.ClosestThingReachable(finder.Position, finder.Map, tRequest,
                                                            PathEndMode.OnCell, TraverseParms.For(finder),
                                                            validator :
                                                            delegate(Thing testThing)
            {
                if (tRequest.Accepts(testThing))
                {
                    if (testThing.IsForbidden(finder))
                    {
                        return(false);
                    }

                    if (!finder.CanReserve(testThing))
                    {
                        return(false);
                    }
                    return(true);
                }

                return(false);
            });

            if (result != null)
            {
                QEEMod.TryLog(finder.LabelShort + " should retrieve: " + result.Label + " | stackCount: " + result.stackCount +
                              " | countForVat: " + countForVat);
            }

            return(result);
        } //end FindClosestIngForBill
Пример #6
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            this.FailOnBurningImmobile(BillGiverInd);
            this.FailOnDestroyedNullOrForbidden(BillGiverInd);
            this.FailOnForbidden(IngredientInd);
            this.FailOn(delegate
            {
                Thing building       = job.GetTarget(BillGiverInd).Thing;
                IBillGiver billGiver = building as IBillGiver;
                if (building == null || billGiver == null || job.bill == null)
                {
                    QEEMod.TryLog("something is null, failing job");
                    return(true);
                }

                Building_GrowerBase_WorkTable grower = job.GetTarget(BillGiverInd).Thing as Building_GrowerBase_WorkTable;
                if (job.bill.DeletedOrDereferenced)
                {
                    QEEMod.TryLog("Bill deleted, failing job");

                    //refund ingredients if player cancels bill during Filling phase
                    if (grower != null && grower.status == CrafterStatus.Filling)
                    {
                        QEEMod.TryLog("Bill cancelled, refunding ingredients");
                        grower.StopCrafting(true);
                    }

                    return(true);
                }

                if (grower.status != CrafterStatus.Filling)
                {
                    QEEMod.TryLog("Crafter is not 'filling', ending job");
                    return(true);
                }

                return(false);
            });


            Toil logToil = new Toil()
            {
                initAction = delegate()
                {
                    QEEMod.TryLog("Pawn " + GetActor().LabelShort + " | Toil: " + logCounter + " | Job: " + job.GetUniqueLoadID());
                    logCounter++;
                }
            };
            ////yield return logToil;

            //travel to ingredient and carry it
            Toil reserveIng = Toils_Reserve.Reserve(IngredientInd);

            yield return(reserveIng);

            //yield return logToil;

            Toil travelToil = Toils_Goto.GotoThing(IngredientInd, PathEndMode.OnCell);

            yield return(travelToil);

            //yield return logToil;

            Toil carryThing = Toils_Haul.StartCarryThing(IngredientInd, subtractNumTakenFromJobCount: true);

            yield return(carryThing);

            //yield return logToil;

            //Opportunistically haul a nearby ingredient of same ThingDef. Checks 8 square radius.
            yield return(Toils_Haul.CheckForGetOpportunityDuplicate(reserveIng, IngredientInd, TargetIndex.None, takeFromValidStorage: true));

            //yield return logToil;


            //head back to grower
            yield return(Toils_Goto.GotoThing(BillGiverInd, PathEndMode.InteractionCell).FailOnDestroyedOrNull(IngredientInd));

            //yield return logToil;

            //deposit into grower
            Toil depositIntoGrower = new Toil()
            {
                initAction = delegate()
                {
                    Building_GrowerBase_WorkTable grower = TargetThingA as Building_GrowerBase_WorkTable;
                    if (grower != null)
                    {
                        grower.FillThing(GetActor().carryTracker.CarriedThing);
                    }
                }
            };

            yield return(depositIntoGrower);

            Toil tryStartCrafting = new Toil()
            {
                initAction = delegate()
                {
                    Building_GrowerBase_WorkTable grower = job.GetTarget(BillGiverInd).Thing as Building_GrowerBase_WorkTable;
                    Pawn actor = GetActor();

                    //if all ingredients have been loaded, start crafting
                    if (grower?.billProc != null)
                    {
                        if (grower.billProc.AnyPendingRequests == false)
                        {
                            grower.Notify_CraftingStarted();
                        }
                    }

                    actor.jobs.EndCurrentJob(JobCondition.Succeeded);
                }
            };

            yield return(tryStartCrafting);
        } //end function MakeNewToils()
Пример #7
0
        } // end TryDropProductOnFloor

        /// <summary>
        /// Generates the recipe product, then looks for a valid cell in the Bill's output stockpile.
        /// If a valid cell is found, puts the product into the pawn's arms for transport in a future Toil.
        /// Uses code from the Toils_Recipe.FinishRecipeAndStartStoringProduct() toil in vanilla.
        /// </summary>
        /// <param name="vat"></param>
        /// <returns></returns>
        public static Toil StartCarryProductToStockpile(Building_GrowerBase_WorkTable vat)
        {
            Toil toil = new Toil();

            toil.initAction = delegate
            {
                Pawn actor  = toil.actor;
                Job  curJob = actor.jobs.curJob;

                //Skip null checking, as it was done in previous toil

                Thing product = ThingMaker.MakeThing(vat.activeRecipe.products[0].thingDef);
                product.stackCount = vat.activeRecipe.products[0].count;
                Bill_Production activeBill = vat.billProc.ActiveBill;

                //decrement billstack count
                if (activeBill.repeatMode == BillRepeatModeDefOf.RepeatCount)
                {
                    if (activeBill.repeatCount > 0)
                    {
                        activeBill.repeatCount--;
                    }
                }

                IntVec3 foundCell = IntVec3.Invalid;

                //find the best cell to put the product in
                if (activeBill.GetStoreMode() == BillStoreModeDefOf.BestStockpile)
                {
                    StoreUtility.TryFindBestBetterStoreCellFor(product, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out foundCell);
                }
                else if (activeBill.GetStoreMode() == BillStoreModeDefOf.SpecificStockpile)
                {
                    StoreUtility.TryFindBestBetterStoreCellForIn(product, actor, actor.Map, StoragePriority.Unstored, actor.Faction,
                                                                 activeBill.GetStoreZone().slotGroup, out foundCell);
                }
                else
                {
                    Log.ErrorOnce("Unknown bill store mode", 9158246);
                }

                //if a cell was found in a stockpile, start a hauling job to move the product from the ground to that cell
                if (foundCell.IsValid)
                {
                    bool tryCarrySuccess = actor.carryTracker.TryStartCarry(product);
                    QEEMod.TryLog("Valid stockpile found - haul product to cell " + foundCell + ". TryStartCarry() result for "
                                  + actor.LabelShort + ": " + tryCarrySuccess);

                    curJob.targetB = foundCell;
                    curJob.targetA = product;
                    curJob.count   = 99999;

                    vat.Notify_ProductExtracted(actor);

                    //the next toil in the JobDriver will now haul the carried object to the stockpile
                }
                else
                {
                    QEEMod.TryLog("No stockpile found to haul " + product.Label + " to. Dropping product on ground.");
                    if (GenPlace.TryPlaceThing(product, actor.Position, actor.Map, ThingPlaceMode.Near))
                    {
                        vat.Notify_ProductExtracted(actor);
                    }
                    else
                    {
                        QEEMod.TryLog(actor + " could not drop recipe product " + product + " near " + actor.Position + ". Ending extract job.");
                    }

                    actor.jobs.EndCurrentJob(JobCondition.Succeeded);
                }
            };
            return(toil);
        } // end StartCarryProductToStockpile
Пример #8
0
        /// <summary>
        /// Checks if Bill specifies to drop product on ground, and if so, creates the product and drops it.
        /// The current grower's active Bill is retrieved programmatically via grower members.
        /// Heavily modified version of the Toils_Recipe.FinishRecipeAndStartStoringProduct() toil in vanilla.
        /// </summary>
        /// <returns></returns>
        public static Toil TryDropProductOnFloor(Building_GrowerBase_WorkTable vat)
        {
            Toil toil = new Toil();

            toil.initAction = delegate
            {
                Pawn            actor      = toil.actor;
                Bill_Production activeBill = vat.billProc.ActiveBill;

                if (vat?.activeRecipe?.products[0]?.thingDef == null)
                {
                    if (vat?.activeRecipe?.label != null)
                    {
                        QEEMod.TryLog("No product found in recipe " + vat.activeRecipe.label + ".Ending extract Job.");
                    }
                    else
                    {
                        QEEMod.TryLog("No product found in recipe. Ending extract Job.");
                    }

                    //decrement billstack count
                    if (activeBill.repeatMode == BillRepeatModeDefOf.RepeatCount)
                    {
                        if (activeBill.repeatCount > 0)
                        {
                            activeBill.repeatCount--;
                        }
                    }

                    actor.jobs.EndCurrentJob(JobCondition.Succeeded);
                }
                else if (activeBill == null || activeBill.GetStoreMode() == BillStoreModeDefOf.DropOnFloor)
                {
                    //true if no output stockpile specified in bill options

                    Thing product = ThingMaker.MakeThing(vat.activeRecipe.products[0].thingDef);
                    product.stackCount = vat.activeRecipe.products[0].count;

                    if (activeBill?.GetUniqueLoadID() != null)
                    {
                        QEEMod.TryLog("activeBill: " + activeBill?.GetUniqueLoadID() + " specifies dropping " + product.Label + " on floor.");
                    }
                    else
                    {
                        QEEMod.TryLog("activeBill is null, dropping " + product.Label + " on floor.");
                    }

                    //put the product on the ground on the same cell as the pawn
                    if (GenPlace.TryPlaceThing(product, actor.Position, actor.Map, ThingPlaceMode.Near))
                    {
                        vat.Notify_ProductExtracted(actor);
                    }
                    else
                    {
                        QEEMod.TryLog(actor + " could not drop recipe product " + product + " near " + actor.Position + ". Ending extract job.");
                    }

                    //decrement billstack count
                    if (activeBill.repeatMode == BillRepeatModeDefOf.RepeatCount)
                    {
                        if (activeBill.repeatCount > 0)
                        {
                            activeBill.repeatCount--;
                        }
                    }

                    actor.jobs.EndCurrentJob(JobCondition.Succeeded);
                }
            };
            return(toil);
        } // end TryDropProductOnFloor
        /* return true if all conditions are met:
         *  a) any bills outstanding
         *  b) status is 'Idle'
         *  c) the usual reservation and forbidden checks pass
         */
        public override bool HasJobOnThing(Pawn pawn, Thing aThing, bool forced = false)
        {
            Building_GrowerBase_WorkTable grower = aThing as Building_GrowerBase_WorkTable;
            IBillGiver      billGiver            = aThing as IBillGiver;
            BillProcessor   processor            = grower.billProc;
            LocalTargetInfo target = aThing;

            if (grower == null || billGiver == null)
            {
                return(false);
            }

            if (grower.status == CrafterStatus.Crafting || grower.status == CrafterStatus.Finished)
            {
                JobFailReason.Is(GrowerBusyTrans);

                return(false);
            }

            if (!processor.AnyPendingRequests)
            {
                JobFailReason.Is(NoBillsQueuedTrans);
                return(false);
            }

            //check if the grower's cached ingredients search found ingredients for any bill
            if (grower.billProc.anyBillIngredientsAvailable == false)
            {
                JobFailReason.Is(NoIngredientsTrans);
                return(false);
            }

            if (aThing.IsBurning())
            {
                JobFailReason.Is(IsBurningTrans);
                return(false);
            }

            if (aThing.IsForbidden(pawn))
            {
                return(false);
            }

            if (!ThingIsUsableBillGiver(aThing))
            {
                return(false);
            }

            string reason = "";

            //if the grower isn't growing anything, loop through the billstack and check for any bill the pawn can do
            if (grower.billProc.ActiveBill == null)
            {
                if (GetBillPawnCanDo(pawn, grower, out reason) == null)
                {
                    JobFailReason.Is(reason);
                    return(false);
                }
            }

            else if (!PawnCanDoThisBill(pawn, grower.billProc.ActiveBill, target, out reason))
            {
                JobFailReason.Is(reason);
                return(false);
            }

            return(true);
        }//end HasJobOnThing()
        }//end HasJobOnThing()

        public override Job JobOnThing(Pawn p, Thing t, bool forced = false)
        {
            IBillGiver billGiver = t as IBillGiver;
            Building_GrowerBase_WorkTable grower = t as Building_GrowerBase_WorkTable;
            BillProcessor processor = grower.billProc;

            //if null is returned from this function, the game will throw an error. Instead,
            //return this simple wait job to avoid unnecessary errors.
            Job returnJobOnFailure = new Job(JobDefOf.Wait, 5);

            //check if there are any pending requests (unfulfilled bills)
            if (!processor.AnyPendingRequests)
            {
                QEEMod.TryLog("AnyPendingRequests is false inside JobOnThing()!");
                return(returnJobOnFailure);
            }

            //check if there are ingredients available for those bills
            if (processor.ingredientsAvailableNow.Count <= 0)
            {
                QEEMod.TryLog("ingredientsAvailableNow.Count is 0 inside JobOnThing()!");
                return(returnJobOnFailure);
            }

            //get the reference to the currently active bill
            Bill theBill = processor.ActiveBill;

            if (theBill == null)
            {
                QEEMod.TryLog("Attempt to get ActiveBill failed inside JobOnThing()!");
                return(returnJobOnFailure);
            }

            //get the cached ingredient that's available. This Thing is not always going to be used in the Job,
            //but we know there's at least one stack of this Thing available on the map
            Thing cachedThing;

            grower.billProc.ingredientsAvailableNow.TryGetValue(theBill.GetUniqueLoadID(), out cachedThing);
            if (cachedThing == null)
            {
                QEEMod.TryLog("Attempt to retrieve cached ingredients failed for " + theBill.GetUniqueLoadID());
                return(returnJobOnFailure);
            }

            //get the nearest Thing to the Pawn with the same ThingDef
            int   countForVat = 0;
            Thing thingToFill = IngredientUtility.ThingPawnShouldRetrieveForBill(theBill, p, ref countForVat);

            if (thingToFill == null)
            {
                grower.billProc.anyBillIngredientsAvailable = false;
                QEEMod.TryLog("ThingPawnShouldRetrieveForBill() is null for " + theBill.GetUniqueLoadID());

                return(returnJobOnFailure);
            }

            //all checks have passed! Return the Job and notify the grower that it's time to start Filling
            grower.Notify_FillingStarted(theBill);

            Job returnJob = new Job(QEJobDefOf.QE_LoadGrowerJob, t, thingToFill);

            returnJob.count = countForVat;
            returnJob.bill  = theBill;
            return(returnJob);
        }//end JobOnThing()