1333 lines
44 KiB
Plaintext
1333 lines
44 KiB
Plaintext
根据向量相似度分析,与 'Source, Toils_Haul, StartCarryThing, Toil' 最相关的代码定义如下:
|
|
|
|
---
|
|
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\Toils_Haul.txt`
|
|
|
|
```csharp
|
|
public class Toils_Haul
|
|
{
|
|
public static bool ErrorCheckForCarry(Pawn pawn, Thing haulThing, bool canTakeFromInventory = false)
|
|
{
|
|
if (!haulThing.SpawnedOrAnyParentSpawned || (!canTakeFromInventory && !haulThing.Spawned))
|
|
{
|
|
Log.Message(pawn?.ToString() + " tried to start carry " + haulThing?.ToString() + " which isn't spawned.");
|
|
pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
return true;
|
|
}
|
|
if (haulThing.stackCount == 0)
|
|
{
|
|
Log.Message(pawn?.ToString() + " tried to start carry " + haulThing?.ToString() + " which had stackcount 0.");
|
|
pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
return true;
|
|
}
|
|
if (pawn.jobs.curJob.count <= 0)
|
|
{
|
|
Log.Error("Invalid count: " + pawn.jobs.curJob.count + ", setting to 1. Job was " + pawn.jobs.curJob);
|
|
pawn.jobs.curJob.count = 1;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static Toil StartCarryThing(TargetIndex haulableInd, bool putRemainderInQueue = false, bool subtractNumTakenFromJobCount = false, bool failIfStackCountLessThanJobCount = false, bool reserve = true, bool canTakeFromInventory = false)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("StartCarryThing");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.jobs.curJob;
|
|
Thing thing = curJob.GetTarget(haulableInd).Thing;
|
|
if (!ErrorCheckForCarry(actor, thing, canTakeFromInventory))
|
|
{
|
|
if (curJob.count == 0)
|
|
{
|
|
throw new Exception($"StartCarryThing job had count = {curJob.count}. Job: {curJob}");
|
|
}
|
|
int num = actor.carryTracker.AvailableStackSpace(thing.def);
|
|
if (num <= 0)
|
|
{
|
|
int num2 = actor.carryTracker.MaxStackSpaceEver(thing.def);
|
|
int num3 = 0;
|
|
if (actor.carryTracker.CarriedThing != null)
|
|
{
|
|
num3 = actor.carryTracker.CarriedThing.stackCount;
|
|
}
|
|
throw new Exception($"StartCarryThing got availableStackSpace {num} (haulTarg {thing}, Job: {curJob}, maximum: {num2}, carrying: {num3})");
|
|
}
|
|
if (failIfStackCountLessThanJobCount && thing.stackCount < curJob.count)
|
|
{
|
|
actor.jobs.curDriver.EndJobWith(JobCondition.Incompletable);
|
|
}
|
|
else
|
|
{
|
|
int num4 = Mathf.Min(curJob.count, num, thing.stackCount);
|
|
if (num4 <= 0)
|
|
{
|
|
int num5 = actor.carryTracker.MaxStackSpaceEver(thing.def);
|
|
int num6 = 0;
|
|
if (actor.carryTracker.CarriedThing != null)
|
|
{
|
|
num6 = actor.carryTracker.CarriedThing.stackCount;
|
|
}
|
|
throw new Exception($"StartCarryThing zero or negative desiredNumToTake ({num4}), curJob.count: {curJob.count}, availableStackSpace: {num} (maximum: {num5}, carrying: {num6}), haulTarg.stackCount: {thing.stackCount}");
|
|
}
|
|
int stackCount = thing.stackCount;
|
|
int num7 = actor.carryTracker.TryStartCarry(thing, num4, reserve);
|
|
if (num7 == 0)
|
|
{
|
|
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
}
|
|
if (num7 < stackCount)
|
|
{
|
|
int num8 = curJob.count - num7;
|
|
if (putRemainderInQueue && num8 > 0)
|
|
{
|
|
curJob.GetTargetQueue(haulableInd).Insert(0, thing);
|
|
Job job = curJob;
|
|
if (job.countQueue == null)
|
|
{
|
|
job.countQueue = new List<int>();
|
|
}
|
|
curJob.countQueue.Insert(0, num8);
|
|
}
|
|
else if (actor.Map.reservationManager.ReservedBy(thing, actor, curJob))
|
|
{
|
|
actor.Map.reservationManager.Release(thing, actor, curJob);
|
|
}
|
|
}
|
|
if (subtractNumTakenFromJobCount)
|
|
{
|
|
curJob.count -= num7;
|
|
}
|
|
curJob.SetTarget(haulableInd, actor.carryTracker.CarriedThing);
|
|
actor.records.Increment(RecordDefOf.ThingsHauled);
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil StoreThingJob(TargetIndex thingIndex)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("StoreThingJob");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.CurJob;
|
|
Thing thing = curJob.GetTarget(thingIndex).Thing;
|
|
Job job = HaulAIUtility.HaulToStorageJob(actor, thing, curJob.playerForced);
|
|
if (job != null)
|
|
{
|
|
actor.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil DropCarriedThing()
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("DropCarriedThing");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Thing resultingThing;
|
|
if (actor.carryTracker.CarriedThing == null)
|
|
{
|
|
Log.Error(actor?.ToString() + " tried to drop carried thing but is not carrying anything.");
|
|
}
|
|
else if (!actor.carryTracker.TryDropCarriedThing(actor.Position, ThingPlaceMode.Direct, out resultingThing))
|
|
{
|
|
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil JumpIfAlsoCollectingNextTargetInQueue(Toil gotoGetTargetToil, TargetIndex ind)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("JumpIfAlsoCollectingNextTargetInQueue");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.jobs.curJob;
|
|
List<LocalTargetInfo> targetQueue = curJob.GetTargetQueue(ind);
|
|
if (!targetQueue.NullOrEmpty() && curJob.count > 0)
|
|
{
|
|
if (actor.carryTracker.CarriedThing == null)
|
|
{
|
|
Log.Error("JumpToAlsoCollectTargetInQueue run on " + actor?.ToString() + " who is not carrying something.");
|
|
}
|
|
else if (actor.carryTracker.AvailableStackSpace(actor.carryTracker.CarriedThing.def) > 0)
|
|
{
|
|
for (int i = 0; i < targetQueue.Count; i++)
|
|
{
|
|
if (!GenAI.CanUseItemForWork(actor, targetQueue[i].Thing))
|
|
{
|
|
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
break;
|
|
}
|
|
if (targetQueue[i].Thing.def == actor.carryTracker.CarriedThing.def)
|
|
{
|
|
curJob.SetTarget(ind, targetQueue[i].Thing);
|
|
targetQueue.RemoveAt(i);
|
|
actor.jobs.curDriver.JumpToToil(gotoGetTargetToil);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil CheckForGetOpportunityDuplicate(Toil getHaulTargetToil, TargetIndex haulableInd, TargetIndex storeCellInd, bool takeFromValidStorage = false, Predicate<Thing> extraValidator = null)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("CheckForGetOpportunityDuplicate");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.jobs.curJob;
|
|
if (actor.carryTracker.CarriedThing.def.stackLimit != 1 && !actor.carryTracker.Full && curJob.count > 0)
|
|
{
|
|
Thing thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableAlways), PathEndMode.ClosestTouch, TraverseParms.For(actor), 8f, DupeValidator);
|
|
if (thing != null)
|
|
{
|
|
curJob.SetTarget(haulableInd, thing);
|
|
actor.jobs.curDriver.JumpToToil(getHaulTargetToil);
|
|
}
|
|
}
|
|
bool DupeValidator(Thing t)
|
|
{
|
|
if (!t.Spawned)
|
|
{
|
|
return false;
|
|
}
|
|
if (t.def != actor.carryTracker.CarriedThing.def)
|
|
{
|
|
return false;
|
|
}
|
|
if (!t.CanStackWith(actor.carryTracker.CarriedThing))
|
|
{
|
|
return false;
|
|
}
|
|
if (t.IsForbidden(actor))
|
|
{
|
|
return false;
|
|
}
|
|
if (!t.IsSociallyProper(actor, forPrisoner: false, animalsCare: true))
|
|
{
|
|
return false;
|
|
}
|
|
if (takeFromValidStorage && storeCellInd != 0 && curJob.GetTarget(storeCellInd).Cell.TryGetSlotGroup(actor.Map, out var group) && t.TryGetValidStoragePriority(out var priority) && (int)priority >= (int)group.Settings.Priority)
|
|
{
|
|
return false;
|
|
}
|
|
if (storeCellInd != 0 && !curJob.GetTarget(storeCellInd).Cell.IsValidStorageFor(actor.Map, t))
|
|
{
|
|
return false;
|
|
}
|
|
if (!actor.CanReserve(t))
|
|
{
|
|
return false;
|
|
}
|
|
if (extraValidator != null && !extraValidator(t))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil CarryHauledThingToCell(TargetIndex squareIndex, PathEndMode pathEndMode = PathEndMode.ClosestTouch)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("CarryHauledThingToCell");
|
|
toil.initAction = delegate
|
|
{
|
|
IntVec3 cell3 = toil.actor.jobs.curJob.GetTarget(squareIndex).Cell;
|
|
toil.actor.pather.StartPath(cell3, pathEndMode);
|
|
};
|
|
toil.defaultCompleteMode = ToilCompleteMode.PatherArrival;
|
|
toil.AddEndCondition(delegate
|
|
{
|
|
Pawn actor2 = toil.actor;
|
|
IntVec3 cell2 = actor2.jobs.curJob.GetTarget(squareIndex).Cell;
|
|
CompPushable compPushable2 = actor2.carryTracker.CarriedThing.TryGetComp<CompPushable>();
|
|
if (compPushable2 != null)
|
|
{
|
|
Vector3 v = actor2.Position.ToVector3() + compPushable2.drawPos;
|
|
if (new IntVec3(v) == cell2)
|
|
{
|
|
return JobCondition.Succeeded;
|
|
}
|
|
}
|
|
return JobCondition.Ongoing;
|
|
});
|
|
toil.AddFailCondition(delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
IntVec3 cell = actor.jobs.curJob.GetTarget(squareIndex).Cell;
|
|
if (actor.carryTracker.CarriedThing == null)
|
|
{
|
|
return true;
|
|
}
|
|
if (actor.jobs.curJob.haulMode == HaulMode.ToCellStorage && !cell.IsValidStorageFor(actor.Map, actor.carryTracker.CarriedThing))
|
|
{
|
|
return true;
|
|
}
|
|
CompPushable compPushable = actor.carryTracker.CarriedThing.TryGetComp<CompPushable>();
|
|
return (compPushable != null && !compPushable.canBePushed) ? true : false;
|
|
});
|
|
return toil;
|
|
}
|
|
|
|
public static Toil PlaceCarriedThingInCellFacing(TargetIndex facingTargetInd)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("PlaceCarriedThingInCellFacing");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
if (actor.carryTracker.CarriedThing == null)
|
|
{
|
|
Log.Error(actor?.ToString() + " tried to place hauled thing in facing cell but is not hauling anything.");
|
|
}
|
|
else
|
|
{
|
|
LocalTargetInfo target = actor.CurJob.GetTarget(facingTargetInd);
|
|
IntVec3 intVec = ((!target.HasThing) ? target.Cell : target.Thing.OccupiedRect().ClosestCellTo(actor.Position));
|
|
IntVec3 dropLoc = actor.Position + Pawn_RotationTracker.RotFromAngleBiased((actor.Position - intVec).AngleFlat).FacingCell;
|
|
if (!actor.carryTracker.TryDropCarriedThing(dropLoc, ThingPlaceMode.Direct, out var _))
|
|
{
|
|
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil PlaceHauledThingInCell(TargetIndex cellInd, Toil nextToilOnPlaceFailOrIncomplete, bool storageMode, bool tryStoreInSameStorageIfSpotCantHoldWholeStack = false)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("PlaceHauledThingInCell");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.jobs.curJob;
|
|
IntVec3 cell = curJob.GetTarget(cellInd).Cell;
|
|
if (actor.carryTracker.CarriedThing == null)
|
|
{
|
|
Log.Error(actor?.ToString() + " tried to place hauled thing in cell but is not hauling anything.");
|
|
}
|
|
else
|
|
{
|
|
SlotGroup slotGroup = actor.Map.haulDestinationManager.SlotGroupAt(cell);
|
|
if (slotGroup != null && slotGroup.Settings.AllowedToAccept(actor.carryTracker.CarriedThing))
|
|
{
|
|
actor.Map.designationManager.TryRemoveDesignationOn(actor.carryTracker.CarriedThing, DesignationDefOf.Haul);
|
|
}
|
|
Action<Thing, int> placedAction = null;
|
|
if (curJob.def == JobDefOf.DoBill || curJob.def == JobDefOf.RecolorApparel || curJob.def == JobDefOf.RefuelAtomic || curJob.def == JobDefOf.RearmTurretAtomic)
|
|
{
|
|
placedAction = delegate(Thing th, int added)
|
|
{
|
|
HaulAIUtility.UpdateJobWithPlacedThings(curJob, th, added);
|
|
};
|
|
}
|
|
if (!actor.carryTracker.TryDropCarriedThing(cell, ThingPlaceMode.Direct, out var _, placedAction))
|
|
{
|
|
if (storageMode)
|
|
{
|
|
IntVec3 storeCell;
|
|
if (nextToilOnPlaceFailOrIncomplete != null && ((tryStoreInSameStorageIfSpotCantHoldWholeStack && StoreUtility.TryFindBestBetterStoreCellForIn(actor.carryTracker.CarriedThing, actor, actor.Map, StoragePriority.Unstored, actor.Faction, curJob.bill.GetSlotGroup(), out var foundCell)) || StoreUtility.TryFindBestBetterStoreCellFor(actor.carryTracker.CarriedThing, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out foundCell)))
|
|
{
|
|
if (actor.CanReserve(foundCell))
|
|
{
|
|
actor.Reserve(foundCell, actor.CurJob);
|
|
}
|
|
actor.CurJob.SetTarget(cellInd, foundCell);
|
|
actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete);
|
|
}
|
|
else if (HaulAIUtility.CanHaulAside(actor, actor.carryTracker.CarriedThing, out storeCell))
|
|
{
|
|
curJob.SetTarget(cellInd, storeCell);
|
|
curJob.count = int.MaxValue;
|
|
curJob.haulOpportunisticDuplicates = false;
|
|
curJob.haulMode = HaulMode.ToCellNonStorage;
|
|
if (nextToilOnPlaceFailOrIncomplete != null)
|
|
{
|
|
actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.Warning($"Incomplete haul for {actor}: Could not find anywhere to put {actor.carryTracker.CarriedThing} near {actor.Position}. Destroying. This should be very uncommon!");
|
|
actor.carryTracker.CarriedThing.Destroy();
|
|
}
|
|
}
|
|
else if (nextToilOnPlaceFailOrIncomplete != null)
|
|
{
|
|
actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil CarryHauledThingToContainer()
|
|
{
|
|
Toil gotoDest = ToilMaker.MakeToil("CarryHauledThingToContainer");
|
|
gotoDest.initAction = delegate
|
|
{
|
|
gotoDest.actor.pather.StartPath(gotoDest.actor.jobs.curJob.targetB.Thing, PathEndMode.Touch);
|
|
};
|
|
gotoDest.AddFailCondition(delegate
|
|
{
|
|
Thing thing = gotoDest.actor.jobs.curJob.targetB.Thing;
|
|
if (thing.Destroyed || (!gotoDest.actor.jobs.curJob.ignoreForbidden && thing.IsForbidden(gotoDest.actor)))
|
|
{
|
|
return true;
|
|
}
|
|
ThingOwner thingOwner = thing.TryGetInnerInteractableThingOwner();
|
|
return (thingOwner != null && !thingOwner.CanAcceptAnyOf(gotoDest.actor.carryTracker.CarriedThing)) ? true : false;
|
|
});
|
|
gotoDest.defaultCompleteMode = ToilCompleteMode.PatherArrival;
|
|
return gotoDest;
|
|
}
|
|
|
|
public static Toil DepositHauledThingInContainer(TargetIndex containerInd, TargetIndex reserveForContainerInd, Action onDeposited = null)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("DepositHauledThingInContainer");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.jobs.curJob;
|
|
if (actor.carryTracker.CarriedThing == null)
|
|
{
|
|
Log.Error(actor?.ToString() + " tried to place hauled thing in container but is not hauling anything.");
|
|
}
|
|
else
|
|
{
|
|
Thing thing = curJob.GetTarget(containerInd).Thing;
|
|
ThingOwner thingOwner = thing.TryGetInnerInteractableThingOwner();
|
|
if (thingOwner != null)
|
|
{
|
|
int num = actor.carryTracker.CarriedThing.stackCount;
|
|
if (thing is IHaulEnroute haulEnroute)
|
|
{
|
|
ThingDef def = actor.carryTracker.CarriedThing.def;
|
|
num = Mathf.Min(haulEnroute.GetSpaceRemainingWithEnroute(def, actor), num);
|
|
if (reserveForContainerInd != 0)
|
|
{
|
|
Thing thing2 = curJob.GetTarget(reserveForContainerInd).Thing;
|
|
if (!thing2.DestroyedOrNull() && thing2 != haulEnroute && thing2 is IHaulEnroute enroute)
|
|
{
|
|
int spaceRemainingWithEnroute = enroute.GetSpaceRemainingWithEnroute(def, actor);
|
|
num = Mathf.Min(num, actor.carryTracker.CarriedThing.stackCount - spaceRemainingWithEnroute);
|
|
}
|
|
}
|
|
}
|
|
Thing carriedThing = actor.carryTracker.CarriedThing;
|
|
int num2 = actor.carryTracker.innerContainer.TryTransferToContainer(carriedThing, thingOwner, num);
|
|
if (num2 != 0)
|
|
{
|
|
if (thing is IHaulEnroute container)
|
|
{
|
|
thing.Map.enrouteManager.ReleaseFor(container, actor);
|
|
}
|
|
if (thing is INotifyHauledTo notifyHauledTo)
|
|
{
|
|
notifyHauledTo.Notify_HauledTo(actor, carriedThing, num2);
|
|
}
|
|
if (thing is ThingWithComps thingWithComps)
|
|
{
|
|
foreach (ThingComp allComp in thingWithComps.AllComps)
|
|
{
|
|
if (allComp is INotifyHauledTo notifyHauledTo2)
|
|
{
|
|
notifyHauledTo2.Notify_HauledTo(actor, carriedThing, num2);
|
|
}
|
|
}
|
|
}
|
|
if (curJob.def == JobDefOf.DoBill)
|
|
{
|
|
HaulAIUtility.UpdateJobWithPlacedThings(curJob, carriedThing, num2);
|
|
}
|
|
onDeposited?.Invoke();
|
|
}
|
|
}
|
|
else if (curJob.GetTarget(containerInd).Thing.def.Minifiable)
|
|
{
|
|
actor.carryTracker.innerContainer.ClearAndDestroyContents();
|
|
}
|
|
else
|
|
{
|
|
Log.Error("Could not deposit hauled thing in container: " + curJob.GetTarget(containerInd).Thing);
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil JumpToCarryToNextContainerIfPossible(Toil carryToContainerToil, TargetIndex primaryTargetInd)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("JumpToCarryToNextContainerIfPossible");
|
|
toil.debugName = "Jump carry if possible";
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn actor = toil.actor;
|
|
Job curJob = actor.jobs.curJob;
|
|
if (actor.carryTracker.CarriedThing != null && curJob.targetQueueB != null && curJob.targetQueueB.Count > 0)
|
|
{
|
|
if (TryGetNextDestinationFromQueue(primaryTargetInd, TargetIndex.B, actor.carryTracker.CarriedThing.def, curJob, actor, out var nextTarget))
|
|
{
|
|
curJob.targetQueueB.RemoveAll((LocalTargetInfo target) => target.Thing == nextTarget);
|
|
curJob.targetB = nextTarget;
|
|
curJob.targetC = nextTarget;
|
|
actor.jobs.curDriver.JumpToToil(carryToContainerToil);
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static bool TryGetNextDestinationFromQueue(TargetIndex primaryIndex, TargetIndex destIndex, ThingDef stuff, Job job, Pawn actor, out Thing target)
|
|
{
|
|
Thing primaryTarget = job.GetTarget(primaryIndex).Thing;
|
|
target = null;
|
|
if (actor.carryTracker?.CarriedThing == null)
|
|
{
|
|
return false;
|
|
}
|
|
bool hasSpareItems = actor.carryTracker.CarriedThing.stackCount > 0;
|
|
if (primaryTarget != null && primaryTarget.Spawned && primaryTarget is IHaulEnroute enroute)
|
|
{
|
|
int spaceRemainingWithEnroute = enroute.GetSpaceRemainingWithEnroute(stuff, actor);
|
|
hasSpareItems = actor.carryTracker.CarriedThing.stackCount > spaceRemainingWithEnroute;
|
|
}
|
|
target = GenClosest.ClosestThing_Global_Reachable(actor.Position, actor.Map, from x in job.GetTargetQueue(destIndex)
|
|
select x.Thing, PathEndMode.Touch, TraverseParms.For(actor), 99999f, Validator);
|
|
return target != null;
|
|
bool Validator(Thing th)
|
|
{
|
|
if (!(th is IHaulEnroute enroute2))
|
|
{
|
|
return false;
|
|
}
|
|
if (enroute2.GetSpaceRemainingWithEnroute(stuff, actor) <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (th != primaryTarget && !hasSpareItems)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static Toil TakeToInventory(TargetIndex ind, int count)
|
|
{
|
|
return TakeToInventory(ind, count, null, null);
|
|
}
|
|
|
|
private static Toil TakeToInventory(TargetIndex ind, int? count, Func<int> countGetter, Func<Thing, int> countGetterPassingThing)
|
|
{
|
|
Toil takeThing = ToilMaker.MakeToil("TakeToInventory");
|
|
takeThing.initAction = delegate
|
|
{
|
|
Pawn actor = takeThing.actor;
|
|
Thing thing = actor.CurJob.GetTarget(ind).Thing;
|
|
if (!ErrorCheckForCarry(actor, thing))
|
|
{
|
|
int num = Mathf.Min(count ?? countGetterPassingThing?.Invoke(thing) ?? countGetter(), thing.stackCount);
|
|
if (actor.CurJob.checkEncumbrance)
|
|
{
|
|
num = Math.Min(num, MassUtility.CountToPickUpUntilOverEncumbered(actor, thing));
|
|
}
|
|
if (num <= 0)
|
|
{
|
|
actor.jobs.curDriver.ReadyForNextToil();
|
|
}
|
|
else
|
|
{
|
|
actor.inventory.GetDirectlyHeldThings().TryAdd(thing.SplitOff(num));
|
|
if (thing.def.ingestible != null && (int)thing.def.ingestible.preferability <= 5)
|
|
{
|
|
actor.mindState.lastInventoryRawFoodUseTick = Find.TickManager.TicksGame;
|
|
}
|
|
thing.def.soundPickup.PlayOneShot(new TargetInfo(actor.Position, actor.Map));
|
|
}
|
|
}
|
|
};
|
|
return takeThing;
|
|
}
|
|
|
|
public static Toil TakeToInventory(TargetIndex ind, Func<int> countGetter)
|
|
{
|
|
return TakeToInventory(ind, null, countGetter, null);
|
|
}
|
|
|
|
public static Toil TakeToInventory(TargetIndex ind, Func<Thing, int> countGetter)
|
|
{
|
|
return TakeToInventory(ind, null, null, countGetter);
|
|
}
|
|
|
|
public static Toil TakeFromOtherInventory(Thing item, ThingOwner taker, ThingOwner holder, int count = -1, TargetIndex indexToSet = TargetIndex.None)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("TakeFromOtherInventory");
|
|
toil.initAction = delegate
|
|
{
|
|
if (!holder.Contains(item))
|
|
{
|
|
toil.actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
}
|
|
else
|
|
{
|
|
count = ((count < 0) ? toil.actor.jobs.curJob.count : count);
|
|
holder.TryTransferToContainer(item, taker, Mathf.Min(item.stackCount, count), out var resultingTransferredItem);
|
|
if (resultingTransferredItem == null)
|
|
{
|
|
Log.Warning($"Taker {toil.actor.Label} unable to take count {count} of thing {item.Label} from holder's inventory");
|
|
toil.actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
|
}
|
|
else if (indexToSet != 0)
|
|
{
|
|
toil.actor.jobs.curJob.SetTarget(indexToSet, resultingTransferredItem);
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static Toil CheckItemCarriedByOtherPawn(Thing item, TargetIndex targetPawnIfCarried = TargetIndex.None, Toil jumpIfCarriedByOther = null)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("CheckItemCarriedByOtherPawn");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn pawn = (item?.ParentHolder as Pawn_InventoryTracker)?.pawn;
|
|
if (pawn != null && pawn != toil.actor)
|
|
{
|
|
if (targetPawnIfCarried != 0)
|
|
{
|
|
toil.actor.jobs.curJob.SetTarget(targetPawnIfCarried, pawn);
|
|
}
|
|
if (jumpIfCarriedByOther != null)
|
|
{
|
|
toil.actor.jobs.curDriver.JumpToToil(jumpIfCarriedByOther);
|
|
}
|
|
}
|
|
};
|
|
toil.defaultCompleteMode = ToilCompleteMode.Instant;
|
|
toil.atomicWithPrevious = true;
|
|
return toil;
|
|
}
|
|
}
|
|
```
|
|
---
|
|
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\JobDriver_HaulToContainer.txt`
|
|
**相似度:** 0.6036
|
|
|
|
```csharp
|
|
public class JobDriver_HaulToContainer : JobDriver, IBuildableDriver
|
|
{
|
|
private Effecter graveDigEffect;
|
|
|
|
protected const TargetIndex CarryThingIndex = TargetIndex.A;
|
|
|
|
public const TargetIndex DestIndex = TargetIndex.B;
|
|
|
|
protected const TargetIndex PrimaryDestIndex = TargetIndex.C;
|
|
|
|
protected const int DiggingEffectInterval = 80;
|
|
|
|
public Thing ThingToCarry => (Thing)job.GetTarget(TargetIndex.A);
|
|
|
|
public Thing Container => (Thing)job.GetTarget(TargetIndex.B);
|
|
|
|
public ThingDef ThingDef => ThingToCarry.def;
|
|
|
|
protected virtual int Duration
|
|
{
|
|
get
|
|
{
|
|
if (Container == null || !(Container is Building building))
|
|
{
|
|
return 0;
|
|
}
|
|
return building.HaulToContainerDuration(ThingToCarry);
|
|
}
|
|
}
|
|
|
|
protected virtual EffecterDef WorkEffecter => null;
|
|
|
|
protected virtual SoundDef WorkSustainer => null;
|
|
|
|
public bool TryGetBuildableRect(out CellRect rect)
|
|
{
|
|
if (Container is Blueprint)
|
|
{
|
|
rect = Container.OccupiedRect();
|
|
return true;
|
|
}
|
|
rect = default(CellRect);
|
|
return false;
|
|
}
|
|
|
|
public override string GetReport()
|
|
{
|
|
Thing thing = ((pawn.CurJob != job || pawn.carryTracker.CarriedThing == null) ? base.TargetThingA : pawn.carryTracker.CarriedThing);
|
|
if (thing == null || !job.targetB.HasThing)
|
|
{
|
|
return "ReportHaulingUnknown".Translate();
|
|
}
|
|
return ((job.GetTarget(TargetIndex.B).Thing is Building_Grave) ? "ReportHaulingToGrave" : "ReportHaulingTo").Translate(thing.Label, job.targetB.Thing.LabelShort.Named("DESTINATION"), thing.Named("THING"));
|
|
}
|
|
|
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
|
{
|
|
if (!pawn.Reserve(job.GetTarget(TargetIndex.A), job, 1, -1, null, errorOnFailed))
|
|
{
|
|
return false;
|
|
}
|
|
if (Container.Isnt<IHaulEnroute>())
|
|
{
|
|
if (!pawn.Reserve(job.GetTarget(TargetIndex.B), job, 1, 1, null, errorOnFailed))
|
|
{
|
|
return false;
|
|
}
|
|
pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.B), job);
|
|
}
|
|
UpdateEnrouteTrackers();
|
|
pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.A), job);
|
|
return true;
|
|
}
|
|
|
|
protected virtual void ModifyPrepareToil(Toil toil)
|
|
{
|
|
}
|
|
|
|
private bool TryReplaceWithFrame(TargetIndex index)
|
|
{
|
|
Thing thing = GetActor().jobs.curJob.GetTarget(index).Thing;
|
|
Building edifice = thing.Position.GetEdifice(pawn.Map);
|
|
if (edifice != null && thing is Blueprint_Build blueprint_Build && edifice is Frame frame && frame.BuildDef == blueprint_Build.BuildDef)
|
|
{
|
|
job.SetTarget(TargetIndex.B, frame);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected override IEnumerable<Toil> MakeNewToils()
|
|
{
|
|
this.FailOnDestroyedOrNull(TargetIndex.A);
|
|
this.FailOn(delegate
|
|
{
|
|
Thing thing = GetActor().jobs.curJob.GetTarget(TargetIndex.B).Thing;
|
|
Thing thing2 = GetActor().jobs.curJob.GetTarget(TargetIndex.C).Thing;
|
|
if (thing == null)
|
|
{
|
|
return true;
|
|
}
|
|
if (thing2 != null && thing2.Destroyed && !TryReplaceWithFrame(TargetIndex.C))
|
|
{
|
|
job.SetTarget(TargetIndex.C, null);
|
|
}
|
|
if (!thing.Spawned || (thing.Destroyed && !TryReplaceWithFrame(TargetIndex.B)))
|
|
{
|
|
if (job.targetQueueB.NullOrEmpty())
|
|
{
|
|
return true;
|
|
}
|
|
if (!Toils_Haul.TryGetNextDestinationFromQueue(TargetIndex.C, TargetIndex.B, ThingDef, job, pawn, out var nextTarget))
|
|
{
|
|
return true;
|
|
}
|
|
job.targetQueueB.RemoveAll((LocalTargetInfo target) => target.Thing == nextTarget);
|
|
job.targetB = nextTarget;
|
|
}
|
|
ThingOwner thingOwner = Container.TryGetInnerInteractableThingOwner();
|
|
if (thingOwner != null && !thingOwner.CanAcceptAnyOf(ThingToCarry))
|
|
{
|
|
return true;
|
|
}
|
|
return (Container is IHaulDestination haulDestination && !haulDestination.Accepts(ThingToCarry)) ? true : false;
|
|
});
|
|
this.FailOnForbidden(TargetIndex.B);
|
|
this.FailOn(() => EnterPortalUtility.WasLoadingCanceled(Container));
|
|
this.FailOn(() => TransporterUtility.WasLoadingCanceled(Container));
|
|
this.FailOn(() => CompBiosculpterPod.WasLoadingCanceled(Container));
|
|
this.FailOn(() => Building_SubcoreScanner.WasLoadingCancelled(Container));
|
|
Toil getToHaulTarget = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch, canGotoSpawnedParent: true).FailOn(() => ThingToCarry.ParentHolder is MinifiedThing).FailOnSelfAndParentsDespawnedOrNull(TargetIndex.A);
|
|
Toil uninstallIfMinifiable = Toils_Construct.UninstallIfMinifiable(TargetIndex.A).FailOnSomeonePhysicallyInteracting(TargetIndex.A).FailOn(() => ThingToCarry.ParentHolder is MinifiedThing)
|
|
.FailOnSelfAndParentsDespawnedOrNull(TargetIndex.A)
|
|
.FailOnDestroyedOrNull(TargetIndex.A);
|
|
Toil startCarryingThing = Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true, failIfStackCountLessThanJobCount: false, reserve: true, canTakeFromInventory: true);
|
|
Toil jumpIfAlsoCollectingNextTarget = Toils_Haul.JumpIfAlsoCollectingNextTargetInQueue(getToHaulTarget, TargetIndex.A);
|
|
Toil carryToContainer = Toils_Haul.CarryHauledThingToContainer();
|
|
yield return Toils_Jump.JumpIf(jumpIfAlsoCollectingNextTarget, () => pawn.IsCarryingThing(ThingToCarry));
|
|
yield return getToHaulTarget;
|
|
yield return uninstallIfMinifiable;
|
|
yield return startCarryingThing;
|
|
yield return jumpIfAlsoCollectingNextTarget;
|
|
yield return carryToContainer;
|
|
yield return Toils_Goto.MoveOffTargetBlueprint(TargetIndex.B);
|
|
Toil toil = Toils_General.Wait(Duration, TargetIndex.B);
|
|
toil.WithProgressBarToilDelay(TargetIndex.B);
|
|
EffecterDef workEffecter = WorkEffecter;
|
|
if (workEffecter != null)
|
|
{
|
|
toil.WithEffect(workEffecter, TargetIndex.B);
|
|
}
|
|
SoundDef workSustainer = WorkSustainer;
|
|
if (workSustainer != null)
|
|
{
|
|
toil.PlaySustainerOrSound(workSustainer);
|
|
}
|
|
Thing destThing = job.GetTarget(TargetIndex.B).Thing;
|
|
toil.tickIntervalAction = delegate(int delta)
|
|
{
|
|
if (pawn.IsHashIntervalTick(80, delta) && destThing is Building_Grave && graveDigEffect == null)
|
|
{
|
|
graveDigEffect = EffecterDefOf.BuryPawn.Spawn();
|
|
graveDigEffect.Trigger(destThing, destThing);
|
|
}
|
|
};
|
|
toil.tickAction = delegate
|
|
{
|
|
graveDigEffect?.EffectTick(destThing, destThing);
|
|
};
|
|
ModifyPrepareToil(toil);
|
|
yield return toil;
|
|
yield return Toils_Construct.MakeSolidThingFromBlueprintIfNecessary(TargetIndex.B, TargetIndex.C);
|
|
yield return Toils_Haul.DepositHauledThingInContainer(TargetIndex.B, TargetIndex.C);
|
|
yield return Toils_Haul.JumpToCarryToNextContainerIfPossible(carryToContainer, TargetIndex.C);
|
|
}
|
|
|
|
private void UpdateEnrouteTrackers()
|
|
{
|
|
int count = job.count;
|
|
TryReserveEnroute(base.TargetThingC, ref count);
|
|
if (base.TargetB != base.TargetC)
|
|
{
|
|
TryReserveEnroute(base.TargetThingB, ref count);
|
|
}
|
|
if (job.targetQueueB == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (LocalTargetInfo item in job.targetQueueB)
|
|
{
|
|
if (!base.TargetC.HasThing || !(item == base.TargetThingC))
|
|
{
|
|
TryReserveEnroute(item.Thing, ref count);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void TryReserveEnroute(Thing thing, ref int count)
|
|
{
|
|
if (thing is IHaulEnroute container && !thing.DestroyedOrNull())
|
|
{
|
|
UpdateTracker(container, ref count);
|
|
}
|
|
}
|
|
|
|
private void UpdateTracker(IHaulEnroute container, ref int count)
|
|
{
|
|
if (!ThingToCarry.DestroyedOrNull())
|
|
{
|
|
if (job.playerForced && container.GetSpaceRemainingWithEnroute(ThingDef) == 0)
|
|
{
|
|
container.Map.enrouteManager.InterruptEnroutePawns(container, pawn);
|
|
}
|
|
int num = Mathf.Min(count, container.GetSpaceRemainingWithEnroute(ThingDef));
|
|
if (num > 0)
|
|
{
|
|
container.Map.enrouteManager.AddEnroute(container, pawn, base.TargetThingA.def, num);
|
|
}
|
|
count -= num;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
---
|
|
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_PrepareCaravan_GatherItems.txt`
|
|
**相似度:** 0.5905
|
|
|
|
```csharp
|
|
public class JobDriver_PrepareCaravan_GatherItems : JobDriver
|
|
{
|
|
private int pickedUpFirstItemTicks = -1;
|
|
|
|
private int toilLoops;
|
|
|
|
private PrepareCaravanGatherState gatherState;
|
|
|
|
private const TargetIndex ToHaulInd = TargetIndex.A;
|
|
|
|
private const TargetIndex CarrierInd = TargetIndex.B;
|
|
|
|
private const int MaxTicksGatherItems = 7500;
|
|
|
|
private const int LoopBackstop = 500;
|
|
|
|
public Thing ToHaul => job.GetTarget(TargetIndex.A).Thing;
|
|
|
|
public Pawn Carrier => (Pawn)job.GetTarget(TargetIndex.B).Thing;
|
|
|
|
private List<TransferableOneWay> Transferables => ((LordJob_FormAndSendCaravan)job.lord.LordJob).transferables;
|
|
|
|
private TransferableOneWay Transferable
|
|
{
|
|
get
|
|
{
|
|
TransferableOneWay transferableOneWay = TransferableUtility.TransferableMatchingDesperate(ToHaul, Transferables, TransferAsOneMode.PodsOrCaravanPacking);
|
|
if (transferableOneWay != null)
|
|
{
|
|
return transferableOneWay;
|
|
}
|
|
throw new InvalidOperationException("Could not find any matching transferable.");
|
|
}
|
|
}
|
|
|
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
|
{
|
|
return pawn.Reserve(ToHaul, job, 1, -1, null, errorOnFailed);
|
|
}
|
|
|
|
protected override IEnumerable<Toil> MakeNewToils()
|
|
{
|
|
if (gatherState == PrepareCaravanGatherState.Unset)
|
|
{
|
|
gatherState = ((pawn.IsFormingCaravan() && (!MassUtility.IsOverEncumbered(pawn) || pawn.inventory.HasAnyUnpackedCaravanItems)) ? PrepareCaravanGatherState.Haul : PrepareCaravanGatherState.Carry);
|
|
}
|
|
if (gatherState == PrepareCaravanGatherState.Carry)
|
|
{
|
|
return MakeNewToilsCarry();
|
|
}
|
|
return MakeNewToilsHaulInInventory();
|
|
}
|
|
|
|
private IEnumerable<Toil> MakeNewToilsCarry()
|
|
{
|
|
this.FailOn(() => !base.Map.lordManager.lords.Contains(job.lord));
|
|
Toil reserve = Toils_Reserve.Reserve(TargetIndex.A).FailOnDestroyedOrNull(TargetIndex.A);
|
|
yield return reserve;
|
|
bool inInventory = HaulAIUtility.IsInHaulableInventory(ToHaul);
|
|
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch, inInventory);
|
|
yield return DetermineNumToHaul();
|
|
yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true, failIfStackCountLessThanJobCount: false, reserve: true, inInventory);
|
|
yield return AddCarriedThingToTransferables();
|
|
yield return Toils_Haul.CheckForGetOpportunityDuplicate(reserve, TargetIndex.A, TargetIndex.None, takeFromValidStorage: true, (Thing x) => Transferable.things.Contains(x));
|
|
Toil findCarrier = FindCarrier();
|
|
yield return findCarrier;
|
|
yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier);
|
|
yield return Toils_General.Wait(25).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier).WithProgressBarToilDelay(TargetIndex.B);
|
|
yield return PlaceTargetInCarrierInventory();
|
|
}
|
|
|
|
private IEnumerable<Toil> MakeNewToilsHaulInInventory()
|
|
{
|
|
this.FailOn(() => !base.Map.lordManager.lords.Contains(job.lord));
|
|
bool inInventory = HaulAIUtility.IsInHaulableInventory(ToHaul);
|
|
Toil reserve = Toils_Reserve.Reserve(TargetIndex.A).FailOnDestroyedOrNull(TargetIndex.A);
|
|
Toil findCarrier = FindCarrier();
|
|
yield return reserve;
|
|
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch, inInventory).JumpIf(IsFinishedCollectingItems, findCarrier);
|
|
yield return DetermineNumToHaul(findCarrier);
|
|
yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true, failIfStackCountLessThanJobCount: false, reserve: true, inInventory);
|
|
yield return AddCarriedThingToTransferables();
|
|
yield return Toils_General.Wait(25).WithProgressBarToilDelay(TargetIndex.B);
|
|
yield return HaulCaravanItemInInventory(reserve);
|
|
yield return findCarrier;
|
|
yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier);
|
|
yield return Toils_General.Wait(25).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier).WithProgressBarToilDelay(TargetIndex.B);
|
|
yield return AddHauledItemsToCarrier(findCarrier);
|
|
}
|
|
|
|
private Toil DetermineNumToHaul(Toil findCarrier = null)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("DetermineNumToHaul");
|
|
toil.initAction = delegate
|
|
{
|
|
int num = GatherItemsForCaravanUtility.CountLeftToTransfer(pawn, Transferable, job.lord);
|
|
if (pawn.carryTracker.CarriedThing != null)
|
|
{
|
|
num -= pawn.carryTracker.CarriedThing.stackCount;
|
|
}
|
|
if (num <= 0)
|
|
{
|
|
if (findCarrier == null || !pawn.inventory.HasAnyUnpackedCaravanItems)
|
|
{
|
|
pawn.jobs.EndCurrentJob(JobCondition.Succeeded);
|
|
}
|
|
else
|
|
{
|
|
pawn.jobs.curDriver.JumpToToil(findCarrier);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
job.count = num;
|
|
}
|
|
};
|
|
toil.defaultCompleteMode = ToilCompleteMode.Instant;
|
|
toil.atomicWithPrevious = true;
|
|
return toil;
|
|
}
|
|
|
|
private Toil AddCarriedThingToTransferables()
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("AddCarriedThingToTransferables");
|
|
toil.initAction = delegate
|
|
{
|
|
TransferableOneWay transferable = Transferable;
|
|
if (!transferable.things.Contains(pawn.carryTracker.CarriedThing))
|
|
{
|
|
transferable.things.Add(pawn.carryTracker.CarriedThing);
|
|
}
|
|
};
|
|
toil.defaultCompleteMode = ToilCompleteMode.Instant;
|
|
toil.atomicWithPrevious = true;
|
|
return toil;
|
|
}
|
|
|
|
private Toil FindCarrier()
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("FindCarrier");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn pawn = FindBestCarrier(onlyAnimals: true);
|
|
if (pawn == null)
|
|
{
|
|
bool flag = base.pawn.GetLord() == job.lord;
|
|
if (flag && !MassUtility.IsOverEncumbered(base.pawn))
|
|
{
|
|
pawn = base.pawn;
|
|
}
|
|
else
|
|
{
|
|
pawn = FindBestCarrier(onlyAnimals: false);
|
|
if (pawn == null)
|
|
{
|
|
if (flag)
|
|
{
|
|
pawn = base.pawn;
|
|
}
|
|
else
|
|
{
|
|
IEnumerable<Pawn> source = job.lord.ownedPawns.Where((Pawn x) => IsUsableCarrier(x, base.pawn, allowColonists: true));
|
|
if (!source.Any())
|
|
{
|
|
EndJobWith(JobCondition.Incompletable);
|
|
return;
|
|
}
|
|
pawn = source.RandomElement();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
job.SetTarget(TargetIndex.B, pawn);
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
private bool IsFinishedCollectingItems()
|
|
{
|
|
if (!MassUtility.IsOverEncumbered(pawn))
|
|
{
|
|
if (pickedUpFirstItemTicks > -1)
|
|
{
|
|
return Find.TickManager.TicksGame > pickedUpFirstItemTicks + 7500;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private Toil HaulCaravanItemInInventory(Toil reserve)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("HaulCaravanItemInInventory");
|
|
toil.initAction = delegate
|
|
{
|
|
if (pickedUpFirstItemTicks == -1)
|
|
{
|
|
pickedUpFirstItemTicks = Find.TickManager.TicksGame;
|
|
}
|
|
Transferable.AdjustTo(Mathf.Max(Transferable.CountToTransfer - pawn.carryTracker.CarriedThing.stackCount, 0));
|
|
pawn.inventory.AddHauledCaravanItem(pawn.carryTracker.CarriedThing);
|
|
if (!IsFinishedCollectingItems())
|
|
{
|
|
SetNewHaulTargetAndJumpToReserve(reserve);
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
private void SetNewHaulTargetAndJumpToReserve(Toil reserve)
|
|
{
|
|
if (CheckToilLoopBackstop())
|
|
{
|
|
Thing thing = GatherItemsForCaravanUtility.FindThingToHaul(pawn, pawn.GetLord());
|
|
if (thing != null)
|
|
{
|
|
job.SetTarget(TargetIndex.A, thing);
|
|
pawn.jobs.curDriver.JumpToToil(reserve);
|
|
}
|
|
}
|
|
}
|
|
|
|
private Toil AddHauledItemsToCarrier(Toil findCarrier)
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("AddHauledItemsToCarrier");
|
|
toil.initAction = delegate
|
|
{
|
|
if (Carrier == pawn)
|
|
{
|
|
pawn.inventory.ClearHaulingCaravanCache();
|
|
}
|
|
else
|
|
{
|
|
pawn.inventory.TransferCaravanItemsToCarrier(Carrier.inventory);
|
|
if (pawn.inventory.HasAnyUnpackedCaravanItems && CheckToilLoopBackstop())
|
|
{
|
|
pawn.jobs.curDriver.JumpToToil(findCarrier);
|
|
}
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
private bool CheckToilLoopBackstop()
|
|
{
|
|
if (++toilLoops > 500)
|
|
{
|
|
Log.Error("Prepare caravan gather items job for pawn " + pawn.Label + " looped through toils too many times");
|
|
EndJobWith(JobCondition.Errored);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private Toil PlaceTargetInCarrierInventory()
|
|
{
|
|
Toil toil = ToilMaker.MakeToil("PlaceTargetInCarrierInventory");
|
|
toil.initAction = delegate
|
|
{
|
|
Pawn_CarryTracker carryTracker = pawn.carryTracker;
|
|
Thing carriedThing = carryTracker.CarriedThing;
|
|
if (carryTracker.innerContainer.Count == 0)
|
|
{
|
|
carryTracker.pawn.Drawer.renderer.SetAllGraphicsDirty();
|
|
}
|
|
Transferable.AdjustTo(Mathf.Max(Transferable.CountToTransfer - carriedThing.stackCount, 0));
|
|
carryTracker.innerContainer.TryTransferToContainer(carriedThing, Carrier.inventory.innerContainer, carriedThing.stackCount, out var resultingTransferredItem);
|
|
CompForbiddable compForbiddable = resultingTransferredItem?.TryGetComp<CompForbiddable>();
|
|
if (compForbiddable != null)
|
|
{
|
|
compForbiddable.Forbidden = false;
|
|
}
|
|
};
|
|
return toil;
|
|
}
|
|
|
|
public static bool IsUsableCarrier(Pawn p, Pawn forPawn, bool allowColonists)
|
|
{
|
|
if (!p.IsFormingCaravan())
|
|
{
|
|
return false;
|
|
}
|
|
if (p == forPawn)
|
|
{
|
|
return true;
|
|
}
|
|
if (p.DestroyedOrNull() || !p.Spawned || p.inventory.UnloadEverything || !forPawn.CanReach(p, PathEndMode.Touch, Danger.Deadly))
|
|
{
|
|
return false;
|
|
}
|
|
if (allowColonists && p.IsColonist)
|
|
{
|
|
return true;
|
|
}
|
|
if ((p.RaceProps.packAnimal || p.HostFaction == Faction.OfPlayer) && !p.IsBurning() && !p.Downed)
|
|
{
|
|
return !MassUtility.IsOverEncumbered(p);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private float GetCarrierScore(Pawn p)
|
|
{
|
|
float lengthHorizontal = (p.Position - pawn.Position).LengthHorizontal;
|
|
float num = MassUtility.EncumbrancePercent(p);
|
|
return 1f - num - lengthHorizontal / 10f * 0.2f;
|
|
}
|
|
|
|
private Pawn FindBestCarrier(bool onlyAnimals)
|
|
{
|
|
Lord lord = job.lord;
|
|
Pawn pawn = null;
|
|
float num = 0f;
|
|
if (lord != null)
|
|
{
|
|
for (int i = 0; i < lord.ownedPawns.Count; i++)
|
|
{
|
|
Pawn pawn2 = lord.ownedPawns[i];
|
|
if (pawn2 != base.pawn && (!onlyAnimals || pawn2.RaceProps.Animal) && IsUsableCarrier(pawn2, base.pawn, allowColonists: false))
|
|
{
|
|
float carrierScore = GetCarrierScore(pawn2);
|
|
if (pawn == null || carrierScore > num)
|
|
{
|
|
pawn = pawn2;
|
|
num = carrierScore;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pawn;
|
|
}
|
|
|
|
public override void ExposeData()
|
|
{
|
|
base.ExposeData();
|
|
Scribe_Values.Look(ref pickedUpFirstItemTicks, "pickedUpFirstItemTicks", 0);
|
|
Scribe_Values.Look(ref toilLoops, "toilLoops", 0);
|
|
Scribe_Values.Look(ref gatherState, "gatherState", PrepareCaravanGatherState.Unset);
|
|
}
|
|
}
|
|
```
|
|
---
|
|
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_CarryToCryptosleepCasket.txt`
|
|
**相似度:** 0.5506
|
|
|
|
```csharp
|
|
public class JobDriver_CarryToCryptosleepCasket : JobDriver
|
|
{
|
|
private const TargetIndex TakeeInd = TargetIndex.A;
|
|
|
|
private const TargetIndex DropPodInd = TargetIndex.B;
|
|
|
|
protected Pawn Takee => (Pawn)job.GetTarget(TargetIndex.A).Thing;
|
|
|
|
protected Building_CryptosleepCasket DropPod => (Building_CryptosleepCasket)job.GetTarget(TargetIndex.B).Thing;
|
|
|
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
|
{
|
|
if (pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed))
|
|
{
|
|
return pawn.Reserve(DropPod, job, 1, -1, null, errorOnFailed);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected override IEnumerable<Toil> MakeNewToils()
|
|
{
|
|
this.FailOnDestroyedOrNull(TargetIndex.A);
|
|
this.FailOnDestroyedOrNull(TargetIndex.B);
|
|
this.FailOnAggroMentalState(TargetIndex.A);
|
|
this.FailOn(() => !DropPod.Accepts(Takee));
|
|
Toil goToTakee = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.OnCell).FailOnDestroyedNullOrForbidden(TargetIndex.A).FailOnDespawnedNullOrForbidden(TargetIndex.B)
|
|
.FailOn(() => DropPod.GetDirectlyHeldThings().Count > 0)
|
|
.FailOn(() => !pawn.CanReach(Takee, PathEndMode.OnCell, Danger.Deadly))
|
|
.FailOnSomeonePhysicallyInteracting(TargetIndex.A);
|
|
Toil startCarryingTakee = Toils_Haul.StartCarryThing(TargetIndex.A);
|
|
Toil goToThing = Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.InteractionCell);
|
|
yield return Toils_Jump.JumpIf(goToThing, () => pawn.IsCarryingPawn(Takee));
|
|
yield return goToTakee;
|
|
yield return startCarryingTakee;
|
|
yield return goToThing;
|
|
Toil toil = Toils_General.Wait(500, TargetIndex.B);
|
|
toil.FailOnCannotTouch(TargetIndex.B, PathEndMode.InteractionCell);
|
|
toil.WithProgressBarToilDelay(TargetIndex.B);
|
|
yield return toil;
|
|
Toil toil2 = ToilMaker.MakeToil("MakeNewToils");
|
|
toil2.initAction = delegate
|
|
{
|
|
DropPod.TryAcceptThing(Takee);
|
|
};
|
|
toil2.defaultCompleteMode = ToilCompleteMode.Instant;
|
|
yield return toil2;
|
|
}
|
|
|
|
public override object[] TaleParameters()
|
|
{
|
|
return new object[2] { pawn, Takee };
|
|
}
|
|
}
|
|
```
|
|
---
|
|
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\JobDriver_HaulToAtomizer.txt`
|
|
**相似度:** 0.5312
|
|
|
|
```csharp
|
|
public class JobDriver_HaulToAtomizer : JobDriver
|
|
{
|
|
private const TargetIndex AtomizerInd = TargetIndex.A;
|
|
|
|
private const TargetIndex WastepackInd = TargetIndex.B;
|
|
|
|
private const TargetIndex ChargerCellInd = TargetIndex.C;
|
|
|
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
|
{
|
|
pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.B), job);
|
|
return pawn.Reserve(job.GetTarget(TargetIndex.A), job, 1, -1, null, errorOnFailed);
|
|
}
|
|
|
|
protected override IEnumerable<Toil> MakeNewToils()
|
|
{
|
|
this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
|
AddEndCondition(() => (base.TargetThingA.TryGetComp<CompAtomizer>().SpaceLeft > 0) ? JobCondition.Ongoing : JobCondition.Succeeded);
|
|
Toil clearQueue = Toils_JobTransforms.ClearDespawnedNullOrForbiddenQueuedTargets(TargetIndex.B);
|
|
yield return clearQueue;
|
|
yield return Toils_JobTransforms.SucceedOnNoTargetInQueue(TargetIndex.B);
|
|
yield return Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.B);
|
|
yield return Toils_Reserve.Reserve(TargetIndex.B);
|
|
yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch).FailOnSomeonePhysicallyInteracting(TargetIndex.B);
|
|
yield return Toils_Haul.StartCarryThing(TargetIndex.B, putRemainderInQueue: false, subtractNumTakenFromJobCount: true);
|
|
yield return Toils_Haul.CheckForGetOpportunityDuplicate(clearQueue, TargetIndex.B, TargetIndex.None, takeFromValidStorage: true);
|
|
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell);
|
|
yield return Toils_Haul.DepositHauledThingInContainer(TargetIndex.A, TargetIndex.B);
|
|
yield return Toils_Jump.Jump(clearQueue);
|
|
}
|
|
}
|
|
```
|
|
---
|
|
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\JobDriver_PickupToHold.txt`
|
|
**相似度:** 0.5219
|
|
|
|
```csharp
|
|
public class JobDriver_PickupToHold : JobDriver
|
|
{
|
|
private const TargetIndex HeldItemInd = TargetIndex.A;
|
|
|
|
public static bool TryMakePreToilReservations(JobDriver driver, bool errorOnFailed)
|
|
{
|
|
driver.pawn.Map.pawnDestinationReservationManager.Reserve(driver.pawn, driver.job, driver.job.GetTarget(TargetIndex.A).Cell);
|
|
return driver.pawn.Reserve(driver.job.GetTarget(TargetIndex.A), driver.job, 1, -1, null, errorOnFailed);
|
|
}
|
|
|
|
public static IEnumerable<Toil> Toils(JobDriver driver, TargetIndex HeldItem = TargetIndex.A, bool subtractNumTakenFromJobCount = true)
|
|
{
|
|
driver.FailOn(() => !driver.GetActor().health.capacities.CapableOf(PawnCapacityDefOf.Manipulation));
|
|
driver.FailOnDestroyedOrNull(HeldItem);
|
|
driver.FailOnForbidden(HeldItem);
|
|
Toil end = Toils_General.Label();
|
|
yield return Toils_Jump.JumpIf(end, () => driver.GetActor().IsCarryingThing(driver.GetActor().CurJob.GetTarget(HeldItem).Thing));
|
|
yield return Toils_Goto.GotoThing(HeldItem, PathEndMode.ClosestTouch).FailOnSomeonePhysicallyInteracting(HeldItem);
|
|
yield return Toils_Haul.StartCarryThing(HeldItem, putRemainderInQueue: false, subtractNumTakenFromJobCount);
|
|
yield return end;
|
|
}
|
|
|
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
|
{
|
|
return TryMakePreToilReservations(this, errorOnFailed);
|
|
}
|
|
|
|
protected override IEnumerable<Toil> MakeNewToils()
|
|
{
|
|
return Toils(this);
|
|
}
|
|
}
|
|
``` |