protected override Job TryGiveJob(Pawn pawn) { Predicate <Thing> validator = delegate(Thing t) { if (t.IsForbidden(pawn)) { return(false); } if (!HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t, forced: false)) { return(false); } if (pawn.carryTracker.MaxStackSpaceEver(t.def) <= 0) { return(false); } if (!StoreUtility.TryFindBestBetterStoreCellFor(t, pawn, pawn.Map, StoreUtility.CurrentStoragePriorityOf(t), pawn.Faction, out IntVec3 _)) { return(false); } return(true); }; Thing thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling(), PathEndMode.OnCell, TraverseParms.For(pawn), 9999f, validator); if (thing != null) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } return(null); }
private Action RestoreRemainingThings(Thing t, int amount) { return(delegate { pawn.jobs.TryTakeOrderedJob(HaulAIUtility.HaulToStorageJob(pawn, t)); }); }
/// <summary> /// the workgiver checks for encumbered, this is purely extra for CE /// </summary> /// <returns></returns> public Toil CheckForOverencumberedForCombatExtended() { Toil toil = new Toil(); if (!ModCompatibilityCheck.CombatExtendedIsActive) { return(toil); } toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; Thing nextThing = curJob.targetA.Thing; var ceOverweight = CompatHelper.CeOverweight(pawn); if (!(MassUtility.EncumbrancePercent(actor) <= 0.9f && !ceOverweight)) { Job haul = HaulAIUtility.HaulToStorageJob(actor, nextThing); if (haul?.TryMakePreToilReservations(actor, false) ?? false) { //note that HaulToStorageJob etc doesn't do opportunistic duplicate hauling for items in valid storage. REEEE actor.jobs.jobQueue.EnqueueFirst(haul, JobTag.Misc); EndJobWith(JobCondition.Succeeded); } } }; return(toil); }
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { if (!HaulAIUtility.PawnCanAutomaticallyHaul(pawn, t, forced)) { return(null); } return(HaulAIUtility.HaulToStorageJob(pawn, t)); }
private void Haul() { if (HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, Silver, false)) { pawn.jobs.StartJob(HaulAIUtility.HaulToStorageJob(pawn, Silver), JobCondition.Succeeded); } else { pawn.jobs.EndCurrentJob(JobCondition.Incompletable); } }
public static Job PutAwayTool(this Pawn pawn, ThingWithComps tool, bool bestLoc = true) { if (bestLoc) { return(HaulAIUtility.HaulToStorageJob(pawn, tool)); } else { return(HaulAIUtility.HaulToStorageJob(pawn, tool)); } }
public static Job TryGiveJob(this JobGiver_Haul @this, Pawn pawn) { Predicate <Thing> validator = t => !t.IsForbidden(pawn) && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t) && IsPlaceToPutThing(pawn, t); Thing thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling(), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); if (thing != null) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } return(null); }
protected override Job TryGiveJob(Pawn pawn) { if (pawn.Map == null) { return(null); } if (!pawn.story.WorkTagIsDisabled(WorkTags.Cleaning) && pawn.Map.listerFilthInHomeArea.FilthInHomeArea.Count > 0) { Thing closestFilth = pawn.Map.listerFilthInHomeArea.FilthInHomeArea.RandomElement(); if (closestFilth != null && pawn.CanReserveAndReach(closestFilth, PathEndMode.Touch, Danger.Some)) { Job job = new Job(JobDefOf.Clean); job.AddQueuedTarget(TargetIndex.A, closestFilth); int num = 15; Map map = closestFilth.Map; Room room = closestFilth.GetRoom(RegionType.Set_Passable); for (int i = 0; i < 100; i++) { IntVec3 intVec = closestFilth.Position + GenRadial.RadialPattern[i]; if (intVec.InBounds(map) && intVec.GetRoom(map, RegionType.Set_Passable) == room) { List <Thing> thingList = intVec.GetThingList(map); for (int j = 0; j < thingList.Count; j++) { Thing thing = thingList[j]; if (thing != closestFilth && IsValidFilth(pawn, thing)) { job.AddQueuedTarget(TargetIndex.A, thing); } } if (job.GetTargetQueue(TargetIndex.A).Count >= num) { break; } } } if (job.targetQueueA != null && job.targetQueueA.Count >= 5) { job.targetQueueA.SortBy((LocalTargetInfo targ) => targ.Cell.DistanceToSquared(pawn.Position)); } return(job); } } if (!pawn.story.WorkTagIsDisabled(WorkTags.Hauling) && pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling().Count > 0) { Thing thing = pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling().RandomElement(); if (thing != null && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, true) && pawn.CanReserveAndReach(thing, PathEndMode.Touch, Danger.Some)) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } } return(null); }
// drop tool and haul it to stockpile, if necessary public Job TryReturnTool(Pawn pawn) { ThingWithComps tool; // drops primary equipment (weapon) as forbidden pawn.equipment.TryDropEquipment(pawn.equipment.Primary, out tool, pawn.Position); // making it non forbidden tool.SetForbidden(false); // tr to haul to the stockpile return(HaulAIUtility.HaulToStorageJob(pawn, tool)); }
public Job ReturnTool(Pawn pawn) { // NOTE: temporary solution using default jobs, need future improvement ThingWithComps tool; // drops primary equipment (weapon) as forbidden pawn.equipment.TryDropEquipment(pawn.equipment.Primary, out tool, pawn.Position); // making it non forbidden tool.SetForbidden(false); // vanilla haul to best stockpile job return(HaulAIUtility.HaulToStorageJob(pawn, tool)); }
//pick up stuff until you can't anymore, //while you're up and about, pick up something and haul it //before you go out, empty your pockets public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false) { CompHauledToInventory takenToInventory = pawn.TryGetComp <CompHauledToInventory>(); if (takenToInventory == null) { return(null); } if (thing is Corpse) { return(null); } if (!HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced)) { return(null); } if (thing.IsForbidden(pawn) || StoreUtility.IsInValidBestStorage(thing)) { return(null); } //bulky gear (power armor + minigun) so don't bother. if (MassUtility.GearMass(pawn) / MassUtility.Capacity(pawn) >= 0.8f) { return(null); } StoragePriority currentPriority = HaulAIUtility.StoragePriorityAtFor(thing.Position, thing); if (StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out IntVec3 storeCell, true)) { //since we've gone through all the effort of getting the loc, might as well use it. //Don't multi-haul food to hoppers. if (thing.def.IsNutritionGivingIngestible) { if (thing.def.ingestible.preferability == FoodPreferability.RawBad || thing.def.ingestible.preferability == FoodPreferability.RawTasty) { List <Thing> thingList = storeCell.GetThingList(thing.Map); for (int i = 0; i < thingList.Count; i++) { Thing thingAtCell = thingList[i]; if (thingAtCell.def == ThingDefOf.Hopper) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } } } } }
public static bool TryGiveJob(ref Job __result, Pawn pawn) { int validationChecks = 0; int validatorFalses1 = 0; int validatorFalses2 = 0; int validatorFalses3 = 0; int validatorFalses4 = 0; Predicate <Thing> validator = delegate(Thing t) { validationChecks++; if (t.IsForbidden(pawn)) { validatorFalses1++; return(false); } if (!HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t, forced: false)) { validatorFalses2++; return(false); } if (pawn.carryTracker.MaxStackSpaceEver(t.def) <= 0) { validatorFalses3++; return(false); } IntVec3 foundCell; bool tryFindBestBetterStoreCellFor = StoreUtility.TryFindBestBetterStoreCellFor(t, pawn, pawn.Map, StoreUtility.CurrentStoragePriorityOf(t), pawn.Faction, out foundCell) ? true : false; if (!tryFindBestBetterStoreCellFor) { validatorFalses4++; } return(tryFindBestBetterStoreCellFor); }; //Log.Error(pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling().Count.ToString()); Thing thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling(), PathEndMode.OnCell, TraverseParms.For(pawn), 9999f, validator); if (validationChecks > 10) { Log.Error("Validator Checks: " + validationChecks.ToString() + " " + validatorFalses1.ToString() + " " + validatorFalses2.ToString() + " " + validatorFalses3.ToString() + " " + validatorFalses4.ToString() + " "); } if (thing != null) { __result = HaulAIUtility.HaulToStorageJob(pawn, thing); return(false); } __result = null; return(false); }
//pick up stuff until you can't anymore, //while you're up and about, pick up something and haul it //before you go out, empty your pockets public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false) { //bulky gear (power armor + minigun) so don't bother. if (MassUtility.GearMass(pawn) / MassUtility.Capacity(pawn) >= 0.8f) { return(null); } DesignationDef haulUrgentlyDesignation = DefDatabase <DesignationDef> .GetNamed("HaulUrgentlyDesignation", false); // Misc. Robots compatibility // See https://github.com/catgirlfighter/RimWorld_CommonSense/blob/master/Source/CommonSense11/CommonSense/OpportunisticTasks.cs#L129-L140 if (pawn.TryGetComp <CompHauledToInventory>() == null) { return(null); } //This WorkGiver gets hijacked by AllowTool and expects us to urgently haul corpses. if (ModCompatibilityCheck.AllowToolIsActive && thing is Corpse && pawn.Map.designationManager.DesignationOn(thing)?.def == haulUrgentlyDesignation && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced)) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } if (!GoodThingToHaul(thing, pawn) || !HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced)) { return(null); } StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(thing); if (StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out IntVec3 storeCell, true)) { //since we've gone through all the effort of getting the loc, might as well use it. //Don't multi-haul food to hoppers. if (thing.def.IsNutritionGivingIngestible) { if (thing.def.ingestible.preferability == FoodPreferability.RawBad || thing.def.ingestible.preferability == FoodPreferability.RawTasty) { List <Thing> thingList = storeCell.GetThingList(thing.Map); foreach (Thing t in thingList) { if (t.def == ThingDefOf.Hopper) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } } } } }
protected override Job TryGiveJob(Pawn pawn) { Predicate <Thing> validator = delegate(Thing t) { IntVec3 intVec; return(!t.IsForbidden(pawn) && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t, false) && pawn.carryTracker.MaxStackSpaceEver(t.def) > 0 && StoreUtility.TryFindBestBetterStoreCellFor(t, pawn, pawn.Map, HaulAIUtility.StoragePriorityAtFor(t.Position, t), pawn.Faction, out intVec, true)); }; Thing thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling(), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); if (thing != null) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } return(null); }
public static bool Prefix(Pawn pawn, Thing thing, ref Job __result) { StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(thing); if (StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out IntVec3 storeCell, true)) { SlotGroup slotGroup = StoreUtility.GetSlotGroup(storeCell, thing.Map); if (Limits.HasLimit(slotGroup.Settings)) { __result = HaulAIUtility.HaulToStorageJob(pawn, thing); return(false); } } return(true); }
// Token: 0x0600001D RID: 29 RVA: 0x00003124 File Offset: 0x00001324 public static void AYWashHaulJob(Thing t) { if (!t.Spawned) { return; } var tub = t.Position.GetFirstBuilding(t.Map); if (tub == null || tub.def.defName != "AYApparelWashingTub") { return; } var p = tub.InteractionCell.GetFirstPawn(t.Map); if (p == null) { return; } var jobs = p.jobs; JobDef jobDef; if (jobs == null) { jobDef = null; } else { var curJob = jobs.curJob; jobDef = curJob?.def; } if (jobDef != JobDefOf.DoBill) { return; } var newHaul = HaulAIUtility.HaulToStorageJob(p, t); if (newHaul != null) { p.jobs.jobQueue.EnqueueFirst(newHaul, JobTag.MiscWork); } }
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { Profiler.BeginSample("PawnCanAutomaticallyHaulFast"); Job result; if (!HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t, forced)) { Profiler.EndSample(); result = null; } else { Profiler.EndSample(); result = HaulAIUtility.HaulToStorageJob(pawn, t); } return(result); }
protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDespawnedNullOrForbidden(TargetIndex.A); this.FailOnDestroyedOrNull(TargetIndex.A); yield return(Toils_Reserve.Reserve(TargetIndex.A)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell)); yield return(Toils_General.WaitWith(TargetIndex.A, 200, true)); yield return(new Toil() { initAction = delegate() { Building_GrowerBase grower = TargetThingA as Building_GrowerBase; if (grower != null) { Pawn actor = GetActor(); Thing product = grower.ExtractProduct(actor); if (!product.Spawned) { GenPlace.TryPlaceThing(product, grower.InteractionCell, grower.Map, ThingPlaceMode.Near); } if (product is Pawn) { EndJobWith(JobCondition.Succeeded); } else { //job.SetTarget(TargetIndex.B, product); IntVec3 storeCell; IHaulDestination haulDestination; if (StoreUtility.TryFindBestBetterStorageFor(product, actor, product.Map, StoragePriority.Unstored, actor.Faction, out storeCell, out haulDestination, false)) { if (storeCell.IsValid || haulDestination != null) { actor.jobs.StartJob(HaulAIUtility.HaulToStorageJob(actor, product), JobCondition.Succeeded); } } } } } }); }
//pick up stuff until you can't anymore, //while you're up and about, pick up something and haul it //before you go out, empty your pockets public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false) { //bulky gear (power armor + minigun) so don't bother. if (MassUtility.GearMass(pawn) / MassUtility.Capacity(pawn) >= 0.8f) { return(null); } DesignationDef HaulUrgentlyDesignation = DefDatabase <DesignationDef> .GetNamed("HaulUrgentlyDesignation", false); //This WorkGiver gets hijacked by AllowTool and expects us to urgently haul corpses. if (ModCompatibilityCheck.AllowToolIsActive && thing is Corpse && pawn.Map.designationManager.DesignationOn(thing)?.def == HaulUrgentlyDesignation && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced)) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } if (!GoodThingToHaul(thing, pawn) || !HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced)) { return(null); } StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(thing); if (StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out IntVec3 storeCell, true)) { //since we've gone through all the effort of getting the loc, might as well use it. //Don't multi-haul food to hoppers. if (thing.def.IsNutritionGivingIngestible) { if (thing.def.ingestible.preferability == FoodPreferability.RawBad || thing.def.ingestible.preferability == FoodPreferability.RawTasty) { List <Thing> thingList = storeCell.GetThingList(thing.Map); for (int i = 0; i < thingList.Count; i++) { if (thingList[i].def == ThingDefOf.Hopper) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } } } } }
protected override Job TryGiveJob(Pawn pawn) { if (!pawn.story.WorkTagIsDisabled(WorkTags.Cleaning)) { Thing closestFilth = pawn.Map.listerFilthInHomeArea.FilthInHomeArea.RandomElement(); if (closestFilth != null && pawn.CanReserveAndReach(closestFilth, PathEndMode.Touch, Danger.Some)) { return(new Job(JobDefOf.Clean, closestFilth)); } } if (!pawn.story.WorkTagIsDisabled(WorkTags.Hauling)) { Thing thing = pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling().RandomElement(); if (thing != null && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing) && pawn.CanReserveAndReach(thing, PathEndMode.Touch, Danger.Some)) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } } return(null); }
public Toil CheckForOverencumbered() { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; Thing nextThing = curJob.targetA.Thing; //float usedBulkByPct = 1f; //float usedWeightByPct = 1f; //try //{ // ((Action)(() => // { // if (ModCompatibilityCheck.CombatExtendedIsActive) // { // CompInventory ceCompInventory = actor.GetComp<CompInventory>(); // usedWeightByPct = ceCompInventory.currentWeight / ceCompInventory.capacityWeight; // usedBulkByPct = ceCompInventory.currentBulk / ceCompInventory.capacityBulk; // } // }))(); //} //catch (TypeLoadException) { } if (!(MassUtility.EncumbrancePercent(actor) <= 0.9f /*|| usedBulkByPct >= 0.7f || usedWeightByPct >= 0.8f*/)) { Job haul = HaulAIUtility.HaulToStorageJob(actor, nextThing); if (haul?.TryMakePreToilReservations(actor, false) ?? false) { //note that HaulToStorageJob etc doesn't do opportunistic duplicate hauling for items in valid storage. REEEE actor.jobs.jobQueue.EnqueueFirst(haul, JobTag.Misc); EndJobWith(JobCondition.Succeeded); } } }; return(toil); }
protected override Job TryGiveTerminalJob(Pawn pawn) { if (pawn.outfits == null) { Log.ErrorOnce(pawn + " tried to run JobGiver_OptimizeApparel without an OutfitTracker", 5643897); return(null); } if (pawn.Faction != Faction.OfColony) { Log.ErrorOnce("Non-colonist " + pawn + " tried to optimize apparel.", 764323); return(null); } if (Find.TickManager.TicksGame < pawn.mindState.nextApparelOptimizeTick) { return(null); } Saveable_Pawn configurarion = MapComponent_AutoEquip.Get.GetCache(pawn); Outfit currentOutfit = pawn.outfits.CurrentOutfit; #region [ Wear Apparel ] if (configurarion.toWearApparel.Count > 0) { List <Thing> list = Find.ListerThings.ThingsInGroup(ThingRequestGroup.Apparel); if (list.Count > 0) { foreach (Apparel ap in list) { if (configurarion.toWearApparel.Contains(ap)) { if (pawn.CanReserveAndReach(ap, PathEndMode.OnCell, pawn.NormalMaxDanger(), 1)) { #if LOG && JOBS Log.Message("Pawn " + pawn + " wear apparel: " + ap); #endif configurarion.toWearApparel.Remove(ap); return(new Job(JobDefOf.Wear, ap)); } } } } } #endregion #region [ Drops unequiped ] for (int i = configurarion.toDropApparel.Count - 1; i >= 0; i--) { Apparel a = configurarion.toDropApparel[i]; configurarion.toDropApparel.Remove(a); #if LOG && JOBS Log.Message("Pawn " + pawn + " drop apparel: " + a); #endif if (pawn.apparel.WornApparel.Contains(a)) { Apparel t; if (pawn.apparel.TryDrop(a, out t)) { t.SetForbidden(false, true); Job job = HaulAIUtility.HaulToStorageJob(pawn, t); if (job != null) { return(job); } else { pawn.mindState.nextApparelOptimizeTick = Find.TickManager.TicksGame + 350; return(null); } } } } #endregion pawn.mindState.nextApparelOptimizeTick = Find.TickManager.TicksGame + 350; return(null); }
//reserve, goto, take, check for more. Branches off to "all over the place" protected override IEnumerable <Toil> MakeNewToils() { CompHauledToInventory takenToInventory = pawn.TryGetComp <CompHauledToInventory>(); HashSet <Thing> carriedThings = takenToInventory.GetHashSet(); DesignationDef HaulUrgentlyDesignation = DefDatabase <DesignationDef> .GetNamed("HaulUrgentlyDesignation", false); //Thanks to AlexTD for the more dynamic search range float searchForOthersRangeFraction = 0.5f; float distanceToOthers = 0f; Toil wait = Toils_General.Wait(2); Toil reserveTargetA = Toils_Reserve.Reserve(TargetIndex.A, 1, -1, null); Toil calculateExtraDistanceToGo = new Toil { initAction = () => { if (StoreUtility.TryFindStoreCellNearColonyDesperate(this.job.targetA.Thing, this.pawn, out IntVec3 storeLoc)) { distanceToOthers = (storeLoc - job.targetA.Thing.Position).LengthHorizontal * searchForOthersRangeFraction; } } }; yield return(calculateExtraDistanceToGo); Toil checkForOtherItemsToHaulToInventory = CheckForOtherItemsToHaulToInventory(reserveTargetA, TargetIndex.A, distanceToOthers, null); Toil checkForOtherItemsToUrgentlyHaulToInventory = CheckForOtherItemsToHaulToInventory(reserveTargetA, TargetIndex.A, distanceToOthers, (Thing x) => pawn.Map.designationManager.DesignationOn(x)?.def == HaulUrgentlyDesignation); yield return(reserveTargetA); Toil gotoThing = new Toil { initAction = () => { this.pawn.pather.StartPath(this.TargetThingA, PathEndMode.ClosestTouch); }, defaultCompleteMode = ToilCompleteMode.PatherArrival, }; gotoThing.FailOnDespawnedNullOrForbidden(TargetIndex.A); yield return(gotoThing); Toil takeThing = new Toil { initAction = () => { Pawn actor = this.pawn; Thing thing = actor.CurJob.GetTarget(TargetIndex.A).Thing; Toils_Haul.ErrorCheckForCarry(actor, thing); //get max we can pick up int num = Mathf.Min(thing.stackCount, MassUtility.CountToPickUpUntilOverEncumbered(actor, thing)); // yo dawg, I heard you like delegates so I put delegates in your delegate, so you can delegate your delegates. // because compilers don't respect IF statements in delegates and toils are fully iterated over as soon as the job starts. try { ((Action)(() => { if (ModCompatibilityCheck.CombatExtendedIsActive) { CombatExtended.CompInventory ceCompInventory = actor.GetComp <CombatExtended.CompInventory>(); ceCompInventory.CanFitInInventory(thing, out num, false, false); } }))(); } catch (TypeLoadException) { } //can't store more, so queue up hauling if we can + end the current job (smooth/instant transition) if (num <= 0) { Job haul = HaulAIUtility.HaulToStorageJob(actor, thing); if (haul?.TryMakePreToilReservations(actor) ?? false) { actor.jobs.jobQueue.EnqueueFirst(haul, new JobTag?(JobTag.Misc)); } actor.jobs.curDriver.JumpToToil(wait); } else { bool isUrgent = false; if (ModCompatibilityCheck.AllowToolIsActive) { //check BEFORE absorbing the thing, designation disappears when it's in inventory :^) if (pawn.Map.designationManager.DesignationOn(thing)?.def == HaulUrgentlyDesignation) { isUrgent = true; } } actor.inventory.GetDirectlyHeldThings().TryAdd(thing.SplitOff(num), true); takenToInventory.RegisterHauledItem(thing); try { ((Action)(() => { if (ModCompatibilityCheck.CombatExtendedIsActive) { CombatExtended.CompInventory ceCompInventory = actor.GetComp <CombatExtended.CompInventory>(); ceCompInventory.UpdateInventory(); } }))(); } catch (TypeLoadException) { } if (isUrgent) { actor.jobs.curDriver.JumpToToil(checkForOtherItemsToUrgentlyHaulToInventory); } } } }; yield return(takeThing); yield return(checkForOtherItemsToHaulToInventory); //we end the job in there, so only one of the checks for duplicates gets called. yield return(checkForOtherItemsToUrgentlyHaulToInventory); yield return(wait); }
protected override Job TryGiveJob(Pawn pawn) { Predicate <Thing> validator = (Thing t) => !t.IsForbidden(pawn) && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t); //Start my code Thing thing = null; List <Thing> things = ListerHaulables.ThingsPotentiallyNeedingHauling(); List <Thing> degrade = new List <Thing>(); List <Thing> undegrade = new List <Thing>(); foreach (Thing t in things) { if (t.GetStatValue(StatDefOf.DeteriorationRate) > 0) { degrade.Add(t); } else { undegrade.Add(t); } } //Loop through all haul areas in order foreach (Area a in AreaFinder.getHaulAreas()) { //Check if got degradable item thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, AreaFinder.searcher(a, degrade), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); if (thing != null) { break; } //Check if got undegradable item thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, AreaFinder.searcher(a, undegrade), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); if (thing != null) { break; } } if (thing == null) { thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, degrade, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); if (thing == null) { thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, undegrade, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); } } /* old 50 cell code * Thing thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, degrade, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 50f, validator, null); * if (thing == null) * { * thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, undegrade, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 50f, validator, null); * if (thing == null) * { * thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, degrade, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); * if (thing == null) * { * thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, undegrade, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null); * } * } * }*/ //End my code if (thing != null) { return(HaulAIUtility.HaulToStorageJob(pawn, thing)); } return(null); }
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { return(HaulAIUtility.HaulToStorageJob(pawn, t)); }
/// <summary> /// Tries to give the pawn a job related to picking up or dropping an item from their inventory. /// </summary> /// <param name="pawn">Pawn to which the job is given.</param> /// <returns>Job that the pawn was instructed to do, be it hauling a dropped Thing or going and getting a Thing.</returns> protected override Job TryGiveJob(Pawn pawn) { // Get inventory CompInventory inventory = pawn.TryGetComp <CompInventory>(); if (inventory == null) { return(null); } Loadout loadout = pawn.GetLoadout(); if (loadout != null) { ThingWithComps dropEq; if (pawn.GetExcessEquipment(out dropEq)) { ThingWithComps droppedEq; if (pawn.equipment.TryDropEquipment(pawn.equipment.Primary, out droppedEq, pawn.Position, false)) { if (droppedEq != null) { return(HaulAIUtility.HaulToStorageJob(pawn, droppedEq)); } Log.Error(string.Concat(pawn, " tried dropping ", dropEq, " from loadout but resulting thing is null")); } } Thing dropThing; int dropCount; if (pawn.GetExcessThing(out dropThing, out dropCount)) { Thing droppedThing; if (inventory.container.TryDrop(dropThing, pawn.Position, pawn.Map, ThingPlaceMode.Near, dropCount, out droppedThing)) { if (droppedThing != null) { return(HaulAIUtility.HaulToStorageJob(pawn, droppedThing)); } Log.Error(string.Concat(pawn, " tried dropping ", dropThing, " from loadout but resulting thing is null")); } } // Find missing items ItemPriority priority; Thing closestThing; int count; Pawn carriedBy; bool doEquip = false; LoadoutSlot prioritySlot = GetPrioritySlot(pawn, out priority, out closestThing, out count, out carriedBy); // moved logic to detect if should equip vs put in inventory here... if (closestThing != null) { if (closestThing.TryGetComp <CompEquippable>() != null && !(pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Violent)) && (pawn.health != null && pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) && (pawn.equipment == null || pawn.equipment.Primary == null || !loadout.Slots.Any(s => s.thingDef == pawn.equipment.Primary.def || (s.genericDef != null && s.countType == LoadoutCountType.pickupDrop && s.genericDef.lambda(pawn.equipment.Primary.def))))) { doEquip = true; } if (carriedBy == null) { // Equip gun if unarmed or current gun is not in loadout if (doEquip) { return(new Job(JobDefOf.Equip, closestThing)); } return(new Job(JobDefOf.TakeInventory, closestThing) { count = Mathf.Min(closestThing.stackCount, count) }); } else { return(new Job(CE_JobDefOf.TakeFromOther, closestThing, carriedBy, doEquip ? pawn : null) { count = doEquip ? 1 : Mathf.Min(closestThing.stackCount, count) }); } } } return(null); }
//regular Toils_Haul.CheckForGetOpportunityDuplicate isn't going to work for our purposes, since we're not carrying anything. //Carrying something yields weird results with unspawning errors when transfering to inventory, so we copy-past-- I mean, implement our own. public Toil CheckForOtherItemsToHaulToInventory(Toil getHaulTargetToil, TargetIndex haulableInd, float distanceToOthers, Predicate <Thing> extraValidator = null) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; IntVec3 storeCell = IntVec3.Invalid; Predicate <Thing> validator = (Thing t) => t.Spawned && HaulAIUtility.PawnCanAutomaticallyHaulFast(actor, t, false) && (!t.IsInValidBestStorage()) && !t.IsForbidden(actor) && !(t is Corpse) && (StoreUtility.TryFindBestBetterStoreCellFor(t, pawn, pawn.Map, (HaulAIUtility.StoragePriorityAtFor(t.Position, t)), actor.Faction, out storeCell, true)) && (extraValidator == null || extraValidator(t)) && actor.CanReserve(t, 1, -1, null, false); Thing thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableAlways), PathEndMode.ClosestTouch, TraverseParms.For(actor, Danger.Deadly, TraverseMode.ByPawn, false), Math.Max(distanceToOthers, 12f), validator, null, 0, -1, false, RegionType.Set_Passable, false); float usedBulkByPct = 1f; float usedWeightByPct = 1f; try { ((Action)(() => { if (ModCompatibilityCheck.CombatExtendedIsActive) { CombatExtended.CompInventory ceCompInventory = actor.GetComp <CombatExtended.CompInventory>(); usedWeightByPct = ceCompInventory.currentWeight / ceCompInventory.capacityWeight; usedBulkByPct = ceCompInventory.currentBulk / ceCompInventory.capacityBulk; } }))(); } catch (TypeLoadException) { } if (thing != null && (MassUtility.EncumbrancePercent(actor) <= 0.9f || usedBulkByPct >= 0.7f || usedWeightByPct >= 0.8f)) { curJob.SetTarget(haulableInd, thing); actor.Reserve(storeCell, this.job, 1, -1, null); actor.jobs.curDriver.JumpToToil(getHaulTargetToil); return; } if (thing != null) { Job haul = HaulAIUtility.HaulToStorageJob(actor, thing); if (haul?.TryMakePreToilReservations(actor) ?? false) { actor.jobs.jobQueue.EnqueueFirst(haul, new JobTag?(JobTag.Misc)); this.EndJobWith(JobCondition.Succeeded); } } if (thing == null) { Job job = new Job(PickUpAndHaulJobDefOf.UnloadYourHauledInventory); if (job.TryMakePreToilReservations(actor)) { actor.jobs.jobQueue.EnqueueFirst(job, new JobTag?(JobTag.Misc)); this.EndJobWith(JobCondition.Succeeded); } } }; return(toil); }
protected override Job TryGiveJob(Pawn pawn) { // Get inventory CompInventory inventory = pawn.TryGetComp <CompInventory>(); if (inventory == null) { return(null); } Loadout loadout = pawn.GetLoadout(); if (loadout != null) { // Find and drop excess items foreach (LoadoutSlot slot in loadout.Slots) { int numContained = inventory.container.TotalStackCountOfDef(slot.Def); // Add currently equipped gun if (pawn.equipment != null && pawn.equipment.Primary != null) { if (pawn.equipment.Primary.def == slot.Def) { numContained++; } } // Drop excess items if (numContained > slot.Count) { Thing thing = inventory.container.FirstOrDefault(x => x.def == slot.Def); if (thing != null) { Thing droppedThing; if (inventory.container.TryDrop(thing, pawn.Position, pawn.Map, ThingPlaceMode.Near, numContained - slot.Count, out droppedThing)) { if (droppedThing != null) { return(HaulAIUtility.HaulToStorageJob(pawn, droppedThing)); } Log.Error(pawn + " tried dropping " + thing + " from loadout but resulting thing is null"); } } } } // Try drop currently equipped weapon if (pawn.equipment != null && pawn.equipment.Primary != null && !loadout.Slots.Any(slot => slot.Def == pawn.equipment.Primary.def && slot.Count >= 1)) { ThingWithComps droppedEq; if (pawn.equipment.TryDropEquipment(pawn.equipment.Primary, out droppedEq, pawn.Position, false)) { return(HaulAIUtility.HaulToStorageJob(pawn, droppedEq)); } } // Find excess items in inventory that are not part of our loadout bool allowDropRaw = Find.TickManager.TicksGame > pawn.mindState?.lastInventoryRawFoodUseTick + ticksBeforeDropRaw; Thing thingToRemove = inventory.container.FirstOrDefault(t => (allowDropRaw || !t.def.IsNutritionGivingIngestible || t.def.ingestible.preferability > FoodPreferability.RawTasty) && !loadout.Slots.Any(s => s.Def == t.def)); if (thingToRemove != null) { Thing droppedThing; if (inventory.container.TryDrop(thingToRemove, pawn.Position, pawn.Map, ThingPlaceMode.Near, thingToRemove.stackCount, out droppedThing)) { return(HaulAIUtility.HaulToStorageJob(pawn, droppedThing)); } Log.Error(pawn + " tried dropping " + thingToRemove + " from inventory but resulting thing is null"); } // Find missing items ItemPriority priority; Thing closestThing; int count; LoadoutSlot prioritySlot = GetPrioritySlot(pawn, out priority, out closestThing, out count); if (closestThing != null) { // Equip gun if unarmed or current gun is not in loadout if (closestThing.TryGetComp <CompEquippable>() != null && (pawn.health != null && pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) && (pawn.equipment == null || pawn.equipment.Primary == null || !loadout.Slots.Any(s => s.Def == pawn.equipment.Primary.def))) { return(new Job(JobDefOf.Equip, closestThing)); } // Take items into inventory if needed int numContained = inventory.container.TotalStackCountOfDef(prioritySlot.Def); return(new Job(JobDefOf.TakeInventory, closestThing) { count = Mathf.Min(closestThing.stackCount, prioritySlot.Count - numContained, count) }); } } return(null); }
//get next, goto, take, check for more. Branches off to "all over the place" protected override IEnumerable <Toil> MakeNewToils() { CompHauledToInventory takenToInventory = pawn.TryGetComp <CompHauledToInventory>(); Toil wait = Toils_General.Wait(2); Toil nextTarget = Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A); //also does count yield return(nextTarget); //honestly the workgiver checks for encumbered, so until CE checks are in this is unnecessary //yield return CheckForOverencumbered();//Probably redundant without CE checks Toil gotoThing = new Toil { initAction = () => { pawn.pather.StartPath(TargetThingA, PathEndMode.ClosestTouch); }, defaultCompleteMode = ToilCompleteMode.PatherArrival }; gotoThing.FailOnDespawnedNullOrForbidden(TargetIndex.A); yield return(gotoThing); Toil takeThing = new Toil { initAction = () => { Pawn actor = pawn; Thing thing = actor.CurJob.GetTarget(TargetIndex.A).Thing; Toils_Haul.ErrorCheckForCarry(actor, thing); //get max we can pick up int countToPickUp = Mathf.Min(job.count, MassUtility.CountToPickUpUntilOverEncumbered(actor, thing)); Log.Message($"{actor} is hauling to inventory {thing}:{countToPickUp}"); // yo dawg, I heard you like delegates so I put delegates in your delegate, so you can delegate your delegates. // because compilers don't respect IF statements in delegates and toils are fully iterated over as soon as the job starts. try { ((Action)(() => { if (ModCompatibilityCheck.CombatExtendedIsActive) { //CombatExtended.CompInventory ceCompInventory = actor.GetComp<CombatExtended.CompInventory>(); //ceCompInventory.CanFitInInventory(thing, out countToPickUp); } }))(); } catch (TypeLoadException) { } if (countToPickUp > 0) { Thing splitThing = thing.SplitOff(countToPickUp); bool shouldMerge = takenToInventory.GetHashSet().Any(x => x.def == thing.def); actor.inventory.GetDirectlyHeldThings().TryAdd(splitThing, shouldMerge); takenToInventory.RegisterHauledItem(splitThing); try { ((Action)(() => { if (ModCompatibilityCheck.CombatExtendedIsActive) { //CombatExtended.CompInventory ceCompInventory = actor.GetComp<CombatExtended.CompInventory>(); //ceCompInventory.UpdateInventory(); } }))(); } catch (TypeLoadException) { } } //thing still remains, so queue up hauling if we can + end the current job (smooth/instant transition) //This will technically release the reservations in the queue, but what can you do if (thing.Spawned) { Job haul = HaulAIUtility.HaulToStorageJob(actor, thing); if (haul?.TryMakePreToilReservations(actor, false) ?? false) { actor.jobs.jobQueue.EnqueueFirst(haul, JobTag.Misc); } actor.jobs.curDriver.JumpToToil(wait); } } }; yield return(takeThing); yield return(Toils_Jump.JumpIf(nextTarget, () => !job.targetQueueA.NullOrEmpty())); //Find more to haul, in case things spawned while this was in progess yield return(new Toil { initAction = () => { List <Thing> haulables = pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling(); WorkGiver_HaulToInventory haulMoreWork = DefDatabase <WorkGiverDef> .AllDefsListForReading.First(wg => wg.Worker is WorkGiver_HaulToInventory).Worker as WorkGiver_HaulToInventory; Thing haulMoreThing = GenClosest.ClosestThing_Global(pawn.Position, haulables, 12, t => haulMoreWork.HasJobOnThing(pawn, t)); //WorkGiver_HaulToInventory found more work nearby if (haulMoreThing != null) { Log.Message($"{pawn} hauling again : {haulMoreThing}"); Job haulMoreJob = haulMoreWork.JobOnThing(pawn, haulMoreThing); if (haulMoreJob.TryMakePreToilReservations(pawn, false)) { pawn.jobs.jobQueue.EnqueueFirst(haulMoreJob, JobTag.Misc); EndJobWith(JobCondition.Succeeded); } } } }); //maintain cell reservations on the trip back //TODO: do that when we carry things //I guess that means TODO: implement carrying the rest of the items in this job instead of falling back on HaulToStorageJob yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.ClosestTouch)); yield return(new Toil //Queue next job { initAction = () => { Pawn actor = pawn; Job curJob = actor.jobs.curJob; LocalTargetInfo storeCell = curJob.targetB; Job unloadJob = new Job(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, storeCell); if (unloadJob.TryMakePreToilReservations(actor, false)) { actor.jobs.jobQueue.EnqueueFirst(unloadJob, JobTag.Misc); EndJobWith(JobCondition.Succeeded); //This will technically release the cell reservations in the queue, but what can you do } } }); yield return(wait); }
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { // give a vanilla haul job- it works just fine for our needs return(HaulAIUtility.HaulToStorageJob(pawn, t)); }