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 : backpack.slotsComp.slots.Count) + targetQueue.Count; int curItemStack = (cart != null ? cart.storage.TotalStackCount : backpack.slotsComp.slots.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 && !item.IsBurning() && 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(toil); }
// OLD /* public static Toil CollectInInventory(TargetIndex HaulableInd) * { * * Toil toil = new Toil(); * toil.initAction = () => * { * Pawn actor = toil.actor; * Job curJob = actor.jobs.curJob; * Thing haulThing = curJob.GetTarget(HaulableInd).Thing; * * //Check haulThing is human_corpse. If other race has apparel, It need to change * if (haulThing.ThingID.IndexOf("Human_Corpse") <= -1 ? false : true) * { * Corpse corpse = (Corpse)haulThing; * List<Apparel> wornApparel = corpse.innerPawn.apparel.WornApparel; * * //Drop wornApparel. wornApparel cannot Add to container directly because it will be duplicated. * corpse.innerPawn.apparel.DropAll(corpse.innerPawn.Position, false); * * //Transfer in container * foreach (Thing apparel in wornApparel) * { * if (actor.inventory.container.TryAdd(apparel)) * { * apparel.holder = actor.inventory.GetContainer(); * apparel.holder.owner = actor.inventory; * } * } * } * //Collecting TargetIndex ind * if (actor.inventory.container.TryAdd(haulThing)) * { * haulThing.holder = actor.inventory.GetContainer(); * haulThing.holder.owner = actor.inventory; * } * * }; * toil.FailOn(() => * { * Pawn actor = toil.actor; * Job curJob = actor.jobs.curJob; * Thing haulThing = curJob.GetTarget(HaulableInd).Thing; * * if (!actor.inventory.container.CanAcceptAnyOf(haulThing)) * return true; * * * * return false; * }); * return toil; * } */ public static Toil CollectInBackpack(TargetIndex HaulableInd, Apparel_Backpack backpack) { Toil toil = new Toil(); toil.initAction = () => { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; Thing haulThing = curJob.GetTarget(HaulableInd).Thing; //Collecting TargetIndex ind if (backpack.slotsComp.slots.TryAdd(haulThing)) { haulThing.holder = backpack.slotsComp.GetContainer(); haulThing.holder.owner = backpack.slotsComp; } }; toil.FailOn(() => { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; Thing haulThing = curJob.GetTarget(HaulableInd).Thing; if (!backpack.slotsComp.slots.CanAcceptAnyOf(haulThing)) { return(true); } return(false); }); return(toil); }
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 : backpack.slotsComp.slots; 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); }
public static Thing TryGetBackpackLastItem(Pawn pawn) { Apparel_Backpack backpack = TryGetBackpack(pawn); if (backpack == null) { return(null); } Thing lastItem = null; int lastItemInd = -1; Thing foodInInventory = FoodUtility.BestFoodInInventory(pawn); if (backpack.slotsComp.slots.Count > 0) { if (backpack.numOfSavedItems > 0) { lastItemInd = (backpack.numOfSavedItems >= backpack.MaxItem ? backpack.slotsComp.slots.Count : backpack.numOfSavedItems) - 1; lastItem = backpack.slotsComp.slots[lastItemInd]; } if (foodInInventory != null && backpack.numOfSavedItems < backpack.slotsComp.slots.Count && backpack.slotsComp.slots[lastItemInd + 1] == foodInInventory) { lastItem = foodInInventory; } } return(lastItem); }
protected override IEnumerable <Toil> MakeNewToils() { Apparel_Backpack backpack = CurJob.GetTarget(BackpackInd).Thing as Apparel_Backpack; // no free slots this.FailOn(() => backpack.slotsComp.slots.Count >= backpack.MaxItem); // reserve resources yield return(Toils_Reserve.ReserveQueue(HaulableInd)); // extract next target thing from targetQueue Toil toilExtractNextTarget = Toils_JobTransforms.ExtractNextTargetFromQueue(HaulableInd); yield return(toilExtractNextTarget); Toil toilGoToThing = Toils_Goto.GotoThing(HaulableInd, PathEndMode.ClosestTouch) .FailOnDespawnedOrNull(HaulableInd); yield return(toilGoToThing); Toil pickUpThingIntoSlot = new Toil { initAction = () => { if (!backpack.slotsComp.slots.TryAdd(CurJob.targetA.Thing)) { EndJobWith(JobCondition.Incompletable); } } }; yield return(pickUpThingIntoSlot); yield return(Toils_Jump.JumpIfHaveTargetInQueue(HaulableInd, toilExtractNextTarget)); }
public override Job JobOnThing(Pawn pawn, Thing t) { if (t is Corpse) { return(null); } if (!HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t)) { return(null); } Apparel_Backpack backpack = ToolsForHaulUtility.TryGetBackpack(pawn); if (backpack != null) { if ( !t.def.thingCategories.Exists( category => backpack.slotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)))) { JobFailReason.Is("Backpack can't hold that thing"); return(null); } else { return(ToolsForHaulUtility.HaulWithTools(pawn)); } } JobFailReason.Is("NoBackpack".Translate()); return(null); }
internal static bool TryDrop(this Pawn_ApparelTracker _this, Apparel ap, out Apparel resultingAp, IntVec3 pos, bool forbid = true) { // drop all toolbelt & backpack stuff so that it won't disappear Apparel_Backpack backpack = ap as Apparel_Backpack; Thing dropThing = null; if (backpack?.slotsComp?.slots?.Count >= 1) { foreach (Thing slot in backpack.slotsComp.slots) { GenThing.TryDropAndSetForbidden(slot, pos, ThingPlaceMode.Near, out dropThing, forbid); } } if (!_this.WornApparel.Contains(ap)) { Log.Warning(_this.pawn.LabelCap + " tried to drop apparel he didn't have: " + ap.LabelCap); resultingAp = null; return(false); } _this.WornApparel.Remove(ap); ap.wearer = null; Thing thing = null; bool flag = GenThing.TryDropAndSetForbidden(ap, pos, ThingPlaceMode.Near, out thing, forbid); resultingAp = (thing as Apparel); _this.ApparelChanged(); if (flag && _this.pawn.outfits != null) { _this.pawn.outfits.forcedHandler.SetForced(ap, false); } Combat_Realism.CR_Utility.TryUpdateInventory(_this.pawn); // Apparel was dropped, update inventory return(flag); }
private float GetStatFactor(Pawn thisPawn) { float result = 1f; if (MapComponent_ToolsForHaul.currentVehicle.ContainsKey(thisPawn)) { Vehicle_Cart vehicleCart = MapComponent_ToolsForHaul.currentVehicle[thisPawn] as Vehicle_Cart; if (vehicleCart != null) { if (vehicleCart.mountableComp.IsMounted && !vehicleCart.mountableComp.Driver.RaceProps.Animal && vehicleCart.mountableComp.Driver == thisPawn) { if (vehicleCart.IsCurrentlyMotorized()) { result = Mathf.Clamp(vehicleCart.VehicleSpeed, 2f, 100f); } else { result = Mathf.Clamp(vehicleCart.VehicleSpeed, 0.5f, 1f); } return(result); } } Vehicle_Turret vehicleTank = MapComponent_ToolsForHaul.currentVehicle[thisPawn] as Vehicle_Turret; if (vehicleTank != null) { if (vehicleTank.mountableComp.IsMounted && !vehicleTank.mountableComp.Driver.RaceProps.Animal && vehicleTank.mountableComp.Driver == thisPawn) { if (vehicleTank.IsCurrentlyMotorized()) { result = Mathf.Clamp(vehicleTank.VehicleSpeed, 2f, 100f); } else { result = Mathf.Clamp(vehicleTank.VehicleSpeed, 0.5f, 1f); } return(result); } } } Apparel_Backpack apparelBackpack = ToolsForHaulUtility.TryGetBackpack(thisPawn); CompSlotsBackpack compSlotsBackpack = apparelBackpack?.slotsComp; if (compSlotsBackpack != null) { result = Mathf.Clamp(compSlotsBackpack.moveSpeedFactor - compSlotsBackpack.encumberPenalty, 0.1f, 1f); } CompInventory compInventory = thisPawn.TryGetComp <CompInventory>(); if (compInventory != null) { result = Mathf.Clamp(compInventory.moveSpeedFactor - compInventory.encumberPenalty, 0.1f, 1f); return(result); } return(result); }
internal static bool TryDrop(this Pawn_ApparelTracker _this, Apparel ap, out Apparel resultingAp, IntVec3 pos, bool forbid = true) { // drop all toolbelt & backpack stuff so that it won't disappear Apparel_Backpack backpack = ap as Apparel_Backpack; Apparel_Toolbelt toolbelt = ap as Apparel_Toolbelt; Thing dropThing = null; if (backpack?.SlotsComp?.slots?.Count >= 1) { foreach (Thing slot in backpack.SlotsComp.slots) { GenThing.TryDropAndSetForbidden(slot, pos, ap.Map, ThingPlaceMode.Near, out dropThing, forbid); } } if (toolbelt?.slotsComp?.slots?.Count >= 1) { foreach (Thing slot in toolbelt.slotsComp.slots) { GenThing.TryDropAndSetForbidden(slot, pos, ap.Map, ThingPlaceMode.Near, out dropThing, forbid); } for (int i = MapComponent_ToolsForHaul.CachedToolEntries.Count - 1; i >= 0; i--) { var entry = MapComponent_ToolsForHaul.CachedToolEntries[i]; if (entry.pawn == _this.pawn) { MapComponent_ToolsForHaul.CachedToolEntries.RemoveAt(i); } } } if (!_this.WornApparel.Contains(ap)) { Log.Warning(_this.pawn.LabelCap + " tried to drop apparel he didn't have: " + ap.LabelCap); resultingAp = null; return(false); } if (_this.pawn.MapHeld == null) { Log.Warning(_this.pawn.LabelCap + " tried to drop apparel but his MapHeld is null."); resultingAp = null; return(false); } ap.Notify_Stripped(_this.pawn); _this.Remove(ap); Thing thing = null; bool result = GenThing.TryDropAndSetForbidden(ap, pos, _this.pawn.MapHeld, ThingPlaceMode.Near, out thing, forbid); resultingAp = (thing as Apparel); #if CR Combat_Realism.CR_Utility.TryUpdateInventory(_this.pawn); // Apparel was dropped, update inventory #endif return(result); }
public override IEnumerable <Thing> PotentialWorkThingsGlobal(Pawn pawn) { List <Thing> list = new List <Thing>(); Apparel_Backpack backpack = ToolsForHaulUtility.TryGetBackpack(pawn); foreach (Thing thing in ListerHaulables.ThingsPotentiallyNeedingHauling()) { if (thing.def.thingCategories.Exists(category => backpack.slotsComp.Properties.allowedThingCategoryDefs.Exists(subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Exists(subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)))) { list.Add(thing); } //return ToolsForHaulUtility.Cart(); } return(list); }
public override bool ShouldSkip(Pawn pawn) { Trace.DebugWriteHaulingPawn(pawn); Apparel_Backpack backpack = ToolsForHaulUtility.TryGetBackpack(pawn); //Should skip pawn that don't have backpack. if (backpack == null) { return(true); } if (backpack.MaxItem - backpack.slotsComp.slots.Count == 0) { return(true); } return(false); }
public static Toil DropTheCarriedFromBackpackInCell( TargetIndex StoreCellInd, ThingPlaceMode placeMode, Apparel_Backpack backpack) { Toil toil = new Toil(); toil.initAction = () => { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; if (backpack.SlotsComp.slots.Count <= 0) { return; } // Check dropThing is last item that should not be dropped Thing dropThing = null; dropThing = backpack.SlotsComp.slots.First(); if (dropThing == null) { Log.Error( toil.actor + " tried to drop null thing in " + actor.jobs.curJob.GetTarget(StoreCellInd).Cell); return; } IntVec3 destLoc = actor.jobs.curJob.GetTarget(StoreCellInd).Cell; Thing dummy; if (destLoc.GetStorable(actor.Map) == null) { actor.Map.designationManager.RemoveAllDesignationsOn(dropThing); backpack.SlotsComp.slots.TryDrop(dropThing, destLoc, actor.Map, placeMode, out dummy); } }; return(toil); }
private float GetStatFactor(Pawn thisPawn) { float result = 1f; Apparel_Backpack apparelBackpack = ToolsForHaulUtility.TryGetBackpack(thisPawn); CompSlotsBackpack compSlotsBackpack = apparelBackpack?.SlotsComp; if (compSlotsBackpack != null) { result = Mathf.Clamp(compSlotsBackpack.MoveSpeedFactor - compSlotsBackpack.encumberPenalty, 0.5f, 1f); } #if CR CompInventory compInventory = thisPawn.TryGetComp <CompInventory>(); if (compInventory != null) { result = Mathf.Clamp(compInventory.moveSpeedFactor - compInventory.encumberPenalty, 0.1f, 1f); return(result); } #endif return(result); }
public static Job HaulWithTools(Pawn pawn, Map map, Thing haulThing = null) { Trace.stopWatchStart(); // Job Setting bool useBackpack = false; JobDef jobDef = null; LocalTargetInfo targetC; int maxItem; int thresholdItem; int reservedMaxItem; IEnumerable <Thing> remainingItems; bool shouldDrop; // Thing lastItem = TryGetBackpackLastItem(pawn); Apparel_Backpack backpack = TryGetBackpack(pawn); // if (cart == null) { jobDef = HaulJobDefOf.HaulWithBackpack; targetC = backpack; maxItem = backpack.MaxItem; // thresholdItem = (int)Math.Ceiling(maxItem * 0.5); thresholdItem = 2; reservedMaxItem = backpack.SlotsComp.slots.Count; remainingItems = backpack.SlotsComp.slots; shouldDrop = false; useBackpack = true; // if (lastItem != null) // { // for (int i = 0; i < backpack.slotsComp.slots.Count; i++) // { // if (backpack.slotsComp.slots[i] == lastItem && reservedMaxItem - (i + 1) <= 0) // { // shouldDrop = false; // break; // } // } // } } Job job = new Job(jobDef) { targetQueueA = new List <LocalTargetInfo>(), targetQueueB = new List <LocalTargetInfo>(), targetC = targetC }; if (useBackpack) { job.countQueue = new List <int>(); } 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 (useBackpack && startDrop == false) * { * if (remainingItems.ElementAt(i) == lastItem) * { * startDrop = true; * } * else * { * continue; * } * } */ Thing thing = remainingItems.ElementAt(i); IntVec3 storageCell; //= FindStorageCell(pawn, remainingItems.ElementAt(i), map, job.targetQueueB); StoragePriority currentPriority = HaulAIUtility.StoragePriorityAtFor(thing.Position, thing); if (StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out storageCell)) { job.targetQueueB.Add(storageCell); break; } } if (!job.targetQueueB.NullOrEmpty()) { Trace.AppendLine("Dropping Job is issued"); Trace.LogMessage(); return(job); } JobFailReason.Is(NoEmptyPlaceLowerTrans); Trace.AppendLine("End Drop remaining item"); Trace.AppendLine("No Job. Reason: " + JobFailReason.Reason); Trace.LogMessage(); return(null); } // Collect item Trace.AppendLine("Start Collect item"); IntVec3 searchPos; if (haulThing != null) { searchPos = haulThing.Position; } else { searchPos = pawn.Position; } foreach (SlotGroup slotGroup in map.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 = map.listerHaulables.ThingsPotentiallyNeedingHauling() .Count(item => slotGroup.Settings.AllowedToAccept(item)); // Finding valid items Trace.AppendLine("Start Finding valid items"); //ToDo TEST if this works without that line if (thingsCount > thresholdItem) { Thing thing; if (haulThing == null) { // ClosestThing_Global_Reachable Configuration Predicate <Thing> predicate = item => !job.targetQueueA.Contains(item) && !item.IsBurning() && !item.IsInAnyStorage() && (item.def.thingCategories.Exists( category => backpack.SlotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.SlotsComp.Properties.forbiddenSubThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)))) && slotGroup.Settings.AllowedToAccept(item) && HaulAIUtility.PawnCanAutomaticallyHaul(pawn, item, true); // && !(item is UnfinishedThing && ((UnfinishedThing)item).BoundBill != null) // && (item.def.IsNutritionSource && !SocialProperness.IsSociallyProper(item, pawn, false, false)); thing = GenClosest.ClosestThing_Global_Reachable( searchPos, map, map.listerHaulables.ThingsPotentiallyNeedingHauling(), PathEndMode.ClosestTouch, TraverseParms.For(pawn, pawn.NormalMaxDanger()), 9999, predicate); if (thing == null) { continue; } } else { thing = haulThing; } // Find StorageCell IntVec3 storageCell = FindStorageCell(pawn, thing, map, job.targetQueueB); if (storageCell == IntVec3.Invalid) { break; } // Add Queue & Reserve job.targetQueueA.Add(thing); // for backpacks if (useBackpack) { job.countQueue.Add(thing.def.stackLimit); } job.targetQueueB.Add(storageCell); IntVec3 center = thing.Position; // Enqueue SAME items in valid distance Trace.AppendLine("Start Enqueuing SAME items in valid distance"); foreach (Thing item in map.listerHaulables.ThingsPotentiallyNeedingHauling() .Where( item => !job.targetQueueA.Contains(item) && !item.IsBurning() && !item.IsInAnyStorage() && (item.def.thingCategories.Exists( category => backpack.SlotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.SlotsComp.Properties.forbiddenSubThingCategoryDefs .Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains( category))) && slotGroup.Settings.AllowedToAccept(item) && HaulAIUtility.PawnCanAutomaticallyHaul(pawn, item, true) && center.DistanceToSquared(item.Position) <= ValidDistance))) { job.targetQueueA.Add(item); if (useBackpack) { job.countQueue.Add(item.def.stackLimit); } reservedMaxItem++; if (reservedMaxItem + job.targetQueueA.Count >= maxItem) { break; } } // Find storage cell Trace.AppendLine("Start Finding storage cell"); if (reservedMaxItem + job.targetQueueA.Count >= thresholdItem) { StoragePriority currentPriority = HaulAIUtility.StoragePriorityAtFor(thing.Position, thing); IntVec3 storeCell; if ( StoreUtility.TryFindBestBetterStoreCellFor( thing, pawn, pawn.Map, currentPriority, pawn.Faction, out storeCell)) { job.targetQueueB.Add(storeCell); if (job.targetQueueB.Count >= job.targetQueueA.Count) { break; } } } job.targetQueueA.Clear(); } } 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 (job.targetQueueA.NullOrEmpty()) { JobFailReason.Is("NoHaulable".Translate()); } else if (reservedMaxItem + job.targetQueueA.Count <= thresholdItem) { JobFailReason.Is(TooLittleHaulable); } else if (job.targetQueueB.NullOrEmpty()) { JobFailReason.Is(NoEmptyPlaceLowerTrans); } Trace.AppendLine("No Job. Reason: " + JobFailReason.Reason); Trace.LogMessage(); return(null); }
protected override IEnumerable <Toil> MakeNewToils() { Apparel_Backpack backpack = this.CurJob.GetTarget(BackpackInd).Thing as Apparel_Backpack; /// // Set fail conditions /// // no free slots this.FailOn(() => backpack.SlotsComp.slots.Count >= backpack.MaxItem); //// hauling stuff not allowed // foreach (ThingCategoryDef category in CurJob.targetA.Thing.def.thingCategories) // { // this.FailOn(() => !backpack.slotsComp.Properties.allowedThingCategoryDefs.Contains(category)); // this.FailOn(() => backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Contains(category)); // } /// // Define Toil /// Toil endOfJob = new Toil { initAction = () => { this.EndJobWith(JobCondition.Succeeded); } }; Toil checkStoreCellEmpty = Toils_Jump.JumpIf(endOfJob, () => this.CurJob.GetTargetQueue(StoreCellInd).NullOrEmpty()); Toil checkHaulableEmpty = Toils_Jump.JumpIf(checkStoreCellEmpty, () => this.CurJob.GetTargetQueue(HaulableInd).NullOrEmpty()); Toil checkBackpackEmpty = Toils_Jump.JumpIf(endOfJob, () => backpack.SlotsComp.slots.Count <= 0); /// // 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) .FailOnDestroyedOrNull(HaulableInd); yield return(gotoThing); // yield return Toils_Collect.CollectInBackpack(HaulableInd, backpack); Toil pickUpThingIntoSlot = new Toil { initAction = () => { if (!backpack.SlotsComp.slots.TryAdd(this.CurJob.targetA.Thing)) { this.EndJobWith(JobCondition.Incompletable); } } }; yield return(pickUpThingIntoSlot); yield return(Toils_Collect.CheckDuplicates(gotoThing, BackpackInd, HaulableInd)); yield return(Toils_Jump.JumpIfHaveTargetInQueue(HaulableInd, extractA)); } // JumpIf toilEnd yield return(checkStoreCellEmpty); { // Drop TargetQueue yield return(checkBackpackEmpty); Toil extractB = Toils_Collect.Extract(StoreCellInd); yield return(extractB); Toil gotoCell = Toils_Goto.GotoCell(StoreCellInd, PathEndMode.ClosestTouch); yield return(gotoCell); yield return(Toils_Collect.DropTheCarriedFromBackpackInCell(StoreCellInd, ThingPlaceMode.Direct, backpack)); yield return(Toils_Jump.JumpIfHaveTargetInQueue(StoreCellInd, checkBackpackEmpty)); yield return(Toils_Collect.CheckNeedStorageCell(gotoCell, BackpackInd, StoreCellInd)); } yield return(endOfJob); }
public static Job HaulWithTools(Pawn pawn, Vehicle_Cart cart = null, Thing haulThing = null) { Trace.stopWatchStart(); //Job Setting bool UseBackpack = false; JobDef jobDef = null; TargetInfo targetC; int maxItem; int thresholdItem; int reservedMaxItem; IEnumerable <Thing> remainingItems; bool ShouldDrop; Thing lastItem = TryGetBackpackLastItem(pawn); Apparel_Backpack backpack = TryGetBackpack(pawn); if (cart == null) { jobDef = HaulJobDefOf.HaulWithBackpack; targetC = backpack; maxItem = backpack.MaxItem; // thresholdItem = (int)Math.Ceiling(maxItem * 0.5); thresholdItem = 2; reservedMaxItem = backpack.slotsComp.slots.Count; remainingItems = backpack.slotsComp.slots; ShouldDrop = false; UseBackpack = true; if (lastItem != null) { for (int i = 0; i < backpack.slotsComp.slots.Count; i++) { if (backpack.slotsComp.slots[i] == lastItem && reservedMaxItem - (i + 1) <= 0) { ShouldDrop = false; break; } } } } else { if (cart.mountableComp.IsMounted) { jobDef = cart.mountableComp.Driver.RaceProps.Animal ? HaulJobDefOf.HaulWithAnimalCart : HaulJobDefOf.HaulWithCart; } else { jobDef = HaulJobDefOf.HaulWithCart; } targetC = cart; maxItem = cart.MaxItem; thresholdItem = (int)Math.Ceiling(maxItem * 0.25); reservedMaxItem = cart.storage.Count; remainingItems = cart.storage; ShouldDrop = reservedMaxItem > 0 ? true : false; } Job job = new Job(jobDef) { targetQueueA = new List <TargetInfo>(), targetQueueB = new List <TargetInfo>(), targetC = targetC }; if (UseBackpack) { job.numToBringList = new List <int>(); } 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 (UseBackpack && 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("Dropping Job is issued"); Trace.LogMessage(); return(job); } if (!UseBackpack && job.def == HaulJobDefOf.HaulWithCart && !cart.IsInValidStorage()) { Trace.AppendLine("In DismountInBase"); return(DismountInBase(pawn, cart)); } JobFailReason.Is(NoEmptyPlaceLowerTrans); Trace.AppendLine("End Drop remaining item"); Trace.AppendLine("No Job. Reason: " + JobFailReason.Reason); Trace.LogMessage(); return(null); } //Collect item Trace.AppendLine("Start Collect item"); IntVec3 searchPos; if (haulThing != null) { searchPos = haulThing.Position; } else if (!UseBackpack) { searchPos = cart.Position; } else { searchPos = pawn.Position; } 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) { Thing thing; if (haulThing == null) { //ClosestThing_Global_Reachable Configuration Predicate <Thing> predicate = item => !job.targetQueueA.Contains(item) && !item.IsBurning() && !item.IsInAnyStorage() && (UseBackpack ? item.def.thingCategories.Exists( category => backpack.slotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category))) : cart.allowances.Allows(item)) && !item.IsForbidden(pawn.Faction) && slotGroup.Settings.AllowedToAccept(item) && pawn.CanReserveAndReach(item, PathEndMode.Touch, pawn.NormalMaxDanger()); //&& !(item is UnfinishedThing && ((UnfinishedThing)item).BoundBill != null) //&& (item.def.IsNutritionSource && !SocialProperness.IsSociallyProper(item, pawn, false, false)); thing = GenClosest.ClosestThing_Global_Reachable(searchPos, ListerHaulables.ThingsPotentiallyNeedingHauling(), PathEndMode.ClosestTouch, TraverseParms.For(pawn, pawn.NormalMaxDanger()), 9999, predicate); if (thing == null) { continue; } } else { thing = haulThing; } //Find StorageCell IntVec3 storageCell = FindStorageCell(pawn, thing, job.targetQueueB); if (storageCell == IntVec3.Invalid) { break; } //Add Queue & Reserve job.targetQueueA.Add(thing); //for backpacks if (UseBackpack) { job.numToBringList.Add(thing.def.stackLimit); } job.targetQueueB.Add(storageCell); IntVec3 center = thing.Position; //Enqueue SAME items in valid distance Trace.AppendLine("Start Enqueuing SAME items in valid distance"); foreach (Thing item in ListerHaulables.ThingsPotentiallyNeedingHauling().Where(item => !job.targetQueueA.Contains(item) && !item.IsBurning() && !item.IsInAnyStorage() && (UseBackpack ? item.def.thingCategories.Exists( category => backpack.slotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category))) : cart.allowances.Allows(item)) && !item.IsForbidden(pawn.Faction) && slotGroup.Settings.AllowedToAccept(item) && pawn.CanReserveAndReach(item, PathEndMode.Touch, pawn.NormalMaxDanger()) && center.DistanceToSquared(item.Position) <= ValidDistance)) { job.targetQueueA.Add(item); if (UseBackpack) { job.numToBringList.Add(item.def.stackLimit); } reservedMaxItem++; if (reservedMaxItem + job.targetQueueA.Count >= maxItem) { break; } } //Enqueue other items in valid distance if (reservedMaxItem + job.targetQueueA.Count < maxItem) { Trace.AppendLine("Start Enqueuing items in valid distance"); foreach (Thing item in ListerHaulables.ThingsPotentiallyNeedingHauling().Where(item => !job.targetQueueA.Contains(item) && !item.IsBurning() && !item.IsInAnyStorage() && (UseBackpack ? item.def.thingCategories.Exists( category => backpack.slotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category))) : cart.allowances.Allows(item)) && !item.IsForbidden(pawn.Faction) && slotGroup.Settings.AllowedToAccept(item) && pawn.CanReserveAndReach(item, PathEndMode.Touch, pawn.NormalMaxDanger()) && center.DistanceToSquared(item.Position) <= ValidDistance)) { job.targetQueueA.Add(item); if (UseBackpack) { job.numToBringList.Add(item.def.stackLimit); } reservedMaxItem++; if (reservedMaxItem + job.targetQueueA.Count >= maxItem) { break; } } } //Also enqueue items in whiche are not in their best storage cell if (reservedMaxItem + job.targetQueueA.Count < maxItem) { Trace.AppendLine("Start Enqueuing items in valid distance & not in best storage cell"); foreach (Thing item in ListerHaulables.ThingsPotentiallyNeedingHauling().Where(item => !job.targetQueueA.Contains(item) && !item.IsBurning() && !item.IsInValidBestStorage() && (UseBackpack ? item.def.thingCategories.Exists( category => backpack.slotsComp.Properties.allowedThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category)) && !backpack.slotsComp.Properties.forbiddenSubThingCategoryDefs.Exists( subCategory => subCategory.ThisAndChildCategoryDefs.Contains(category))) : cart.allowances.Allows(item)) && !item.IsForbidden(pawn.Faction) && slotGroup.Settings.AllowedToAccept(item) && pawn.CanReserveAndReach(item, PathEndMode.Touch, pawn.NormalMaxDanger()) && center.DistanceToSquared(item.Position) <= ValidDistance)) { job.targetQueueA.Add(item); if (UseBackpack) { job.numToBringList.Add(item.def.stackLimit); } reservedMaxItem++; if (reservedMaxItem + job.targetQueueA.Count >= maxItem) { break; } } } //Find storage cell Trace.AppendLine("Start Finding storage cell"); if (reservedMaxItem + job.targetQueueA.Count > thresholdItem) { foreach ( IntVec3 cell in slotGroup.CellsList.Where( cell => pawn.CanReserveAndReach(cell, PathEndMode.ClosestTouch, Danger.Some) && cell.Standable() && cell.GetStorable() == null)) { StoragePriority currentPriority = HaulAIUtility.StoragePriorityAtFor(thing.Position, thing); IntVec3 storeCell = cell; if ( !StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, currentPriority, pawn.Faction, out storeCell)) { if (cell.InAllowedArea(pawn)) { job.targetQueueB.Add(cell); } if (job.targetQueueB.Count >= job.targetQueueA.Count) { break; } } else { if (storeCell.InAllowedArea(pawn)) { job.targetQueueB.Add(storeCell); } if (job.targetQueueB.Count >= job.targetQueueA.Count) { break; } } } break; } job.targetQueueA.Clear(); } } 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 == HaulJobDefOf.HaulWithCart && !cart.IsInValidStorage()) { Trace.AppendLine("In DismountInBase: "); return(DismountInBase(pawn, cart)); } if (job.targetQueueA.NullOrEmpty()) { JobFailReason.Is("NoHaulable".Translate()); } else if (reservedMaxItem + job.targetQueueA.Count <= thresholdItem) { JobFailReason.Is(TooLittleHaulable); } else if (job.targetQueueB.NullOrEmpty()) { JobFailReason.Is(NoEmptyPlaceLowerTrans); } Trace.AppendLine("No Job. Reason: " + JobFailReason.Reason); Trace.LogMessage(); return(null); }