protected override IEnumerable <Toil> MakeNewToils() { yield return(Toils_General.Wait(10)); yield return(new Toil { initAction = delegate { Thing dropThing; int dropCount; if (!this.pawn.inventory.UnloadEverything || !this.pawn.GetAnythingForDrop(out dropThing, out dropCount)) { this.EndJobWith(JobCondition.Succeeded); } else { IntVec3 c; if (!StoreUtility.TryFindStoreCellNearColonyDesperate(dropThing, this.pawn, out c)) { this.pawn.inventory.innerContainer.TryDrop(dropThing, this.pawn.Position, this.pawn.Map, ThingPlaceMode.Near, dropCount, out dropThing); this.EndJobWith(JobCondition.Succeeded); } else { pawn.CurJob.SetTarget(TargetIndex.A, dropThing); pawn.CurJob.SetTarget(TargetIndex.B, c); amountToDrop = dropCount; } } } }); yield return(Toils_Reserve.Reserve(TargetIndex.B, 1)); yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.Touch)); yield return(new Toil { initAction = delegate { Thing thing = pawn.CurJob.GetTarget(TargetIndex.A).Thing; if (thing == null || !this.pawn.inventory.innerContainer.Contains(thing)) { this.EndJobWith(JobCondition.Incompletable); return; } if (!this.pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || !thing.def.EverStoreable) { this.pawn.inventory.innerContainer.TryDrop(thing, this.pawn.Position, this.pawn.Map, ThingPlaceMode.Near, amountToDrop, out thing); this.EndJobWith(JobCondition.Succeeded); } else { this.pawn.inventory.innerContainer.TryTransferToContainer(thing, this.pawn.carryTracker.innerContainer, amountToDrop, out thing); pawn.CurJob.count = amountToDrop; pawn.CurJob.SetTarget(TargetIndex.A, thing); } thing.SetForbidden(false, false); if (!this.pawn.HasAnythingForDrop()) { this.pawn.inventory.UnloadEverything = false; } } }); Toil carryToCell = Toils_Haul.CarryHauledThingToCell(TargetIndex.B); yield return(carryToCell); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, carryToCell, true)); }
/// <summary> /// Find spot, reserve spot, pull thing out of inventory, go to spot, drop stuff, repeat. /// </summary> /// <returns></returns> protected override IEnumerable <Toil> MakeNewToils() { CompHauledToInventory takenToInventory = pawn.TryGetComp <CompHauledToInventory>(); HashSet <Thing> carriedThing = takenToInventory.GetHashSet(); if (ModCompatibilityCheck.ExtendedStorageIsActive) { //ES takes at least ~10 ticks to move from the feeder to the stockpile, so workaround ahoy UnloadDuration = 20; } Toil wait = Toils_General.Wait(UnloadDuration); Toil celebrate = Toils_General.Wait(UnloadDuration); yield return(wait); Toil findSpot = new Toil { initAction = () => { ThingCount unloadableThing = FirstUnloadableThing(pawn); if (unloadableThing.Count == 0 && carriedThing.Count == 0) { this.EndJobWith(JobCondition.Succeeded); } if (unloadableThing.Count != 0) { //StoragePriority currentPriority = StoreUtility.StoragePriorityAtFor(pawn.Position, unloadableThing.Thing); if (!StoreUtility.TryFindStoreCellNearColonyDesperate(unloadableThing.Thing, this.pawn, out IntVec3 c)) { this.pawn.inventory.innerContainer.TryDrop(unloadableThing.Thing, ThingPlaceMode.Near, unloadableThing.Thing.stackCount, out Thing thing); this.EndJobWith(JobCondition.Succeeded); } else { this.job.SetTarget(TargetIndex.A, unloadableThing.Thing); this.job.SetTarget(TargetIndex.B, c); this.countToDrop = unloadableThing.Thing.stackCount; } } } }; yield return(findSpot); yield return(Toils_Reserve.Reserve(TargetIndex.B)); yield return(new Toil { initAction = delegate { Thing thing = this.job.GetTarget(TargetIndex.A).Thing; if (thing == null || !this.pawn.inventory.innerContainer.Contains(thing)) { carriedThing.Remove(thing); pawn.jobs.curDriver.JumpToToil(wait); return; } if (!this.pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || !thing.def.EverStorable(false)) { this.pawn.inventory.innerContainer.TryDrop(thing, ThingPlaceMode.Near, this.countToDrop, out thing); this.EndJobWith(JobCondition.Succeeded); carriedThing.Remove(thing); } else { this.pawn.inventory.innerContainer.TryTransferToContainer(thing, this.pawn.carryTracker.innerContainer, this.countToDrop, out thing); this.job.count = this.countToDrop; this.job.SetTarget(TargetIndex.A, thing); carriedThing.Remove(thing); } try { ((Action)(() => { if (ModCompatibilityCheck.CombatExtendedIsActive) { //CombatExtended.CompInventory ceCompInventory = pawn.GetComp<CombatExtended.CompInventory>(); //ceCompInventory.UpdateInventory(); } }))(); } catch (TypeLoadException) { } thing.SetForbidden(false, false); } }); Toil carryToCell = Toils_Haul.CarryHauledThingToCell(TargetIndex.B); yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.Touch)); yield return(carryToCell); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, carryToCell, true)); //If the original cell is full, PlaceHauledThingInCell will set a different TargetIndex resulting in errors on yield return Toils_Reserve.Release. //We still gotta release though, mostly because of Extended Storage. Toil releaseReservation = new Toil { initAction = () => { if (pawn.Map.reservationManager.ReservedBy(this.job.targetB, pawn, pawn.CurJob) && !ModCompatibilityCheck.HCSKIsActive) { pawn.Map.reservationManager.Release(this.job.targetB, pawn, pawn.CurJob); } } }; yield return(releaseReservation); yield return(Toils_Jump.Jump(wait)); yield return(celebrate); }
protected override IEnumerable <Toil> MakeNewToils() { yield return(Toils_General.Wait(10, TargetIndex.None)); yield return(new Toil { initAction = delegate() { Thing MarkedThing = CompUnloadChecker.getFirstMarked(pawn); if (MarkedThing == null) { EndJobWith(JobCondition.Succeeded); return; } // if (pawn.equipment.Contains(MarkedThing)) { Equipment = (ThingWithComps)MarkedThing; Apparel = null; } else { Apparel = pawn.apparel.Contains(MarkedThing) ? (Apparel)MarkedThing : null; Equipment = null; } ThingCount firstUnloadableThing = MarkedThing == null ? default(ThingCount) : new ThingCount(MarkedThing, MarkedThing.stackCount); IntVec3 c; if (!StoreUtility.TryFindStoreCellNearColonyDesperate(firstUnloadableThing.Thing, pawn, out c)) { Thing thing; pawn.inventory.innerContainer.TryDrop(firstUnloadableThing.Thing, ThingPlaceMode.Near, firstUnloadableThing.Count, out thing, null, null); EndJobWith(JobCondition.Succeeded); return; } job.SetTarget(TargetIndex.A, firstUnloadableThing.Thing); job.SetTarget(TargetIndex.B, c); countToDrop = firstUnloadableThing.Count; } }); yield return(Toils_Reserve.Reserve(TargetIndex.B, 1, -1, null)); yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.Touch).FailOnDestroyedOrNull(TargetIndex.A).FailOn(delegate() { return !stillUnloadable(pawn.CurJob.GetTarget(TargetIndex.A).Thing); })); //preintiating unequip-delay Toil unequip = new Toil { initAction = delegate() { if (Equipment != null) { pawn.equipment.TryTransferEquipmentToContainer(Equipment, pawn.inventory.innerContainer); } else if (Apparel != null) { ThingOwner <Apparel> a = Traverse.Create(pawn.apparel).Field("wornApparel").GetValue <ThingOwner <Apparel> >(); a.TryTransferToContainer(Apparel, pawn.inventory.innerContainer); } } }; //if equiped, wait unequipping time Toil wait = new Toil(); wait.initAction = delegate() { ticker = 0; duration = Apparel != null?Apparel.GetStatValue(StatDefOf.EquipDelay, true) * 60f : Equipment != null ? 30 : 0; pawn.pather.StopDead(); }; wait.tickAction = delegate() { if (ticker >= duration) { ReadyForNextToil(); } ticker++; }; wait.defaultCompleteMode = ToilCompleteMode.Never; wait.WithProgressBar(TargetIndex.A, () => ticker / duration); //unequip to inventory yield return(wait); yield return(unequip); //hold in hands yield return(new Toil { initAction = delegate() { Thing thing = job.GetTarget(TargetIndex.A).Thing; CompUnloadChecker c = thing.TryGetComp <CompUnloadChecker>(); if (c == null || !c.ShouldUnload) { EndJobWith(JobCondition.Incompletable); return; } if (thing == null || !pawn.inventory.innerContainer.Contains(thing)) { EndJobWith(JobCondition.Incompletable); return; } if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || !thing.def.EverStorable(false)) { pawn.inventory.innerContainer.TryDrop(thing, ThingPlaceMode.Near, countToDrop, out thing, null, null); EndJobWith(JobCondition.Succeeded); } else { pawn.inventory.innerContainer.TryTransferToContainer(thing, pawn.carryTracker.innerContainer, countToDrop, out thing, true); job.count = countToDrop; job.SetTarget(TargetIndex.A, thing); } thing.SetForbidden(false, false); } }); Toil carryToCell = Toils_Haul.CarryHauledThingToCell(TargetIndex.B).FailOnDestroyedOrNull(TargetIndex.A).FailOn(delegate() { return(!stillUnloadable(pawn.CurJob.GetTarget(TargetIndex.A).Thing)); }); yield return(carryToCell); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, carryToCell, true)); yield break; }
//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); }