public static Job HaulBeforeCarry(Pawn pawn, IntVec3 dest, Thing th) { if (th.IsInValidStorage()) { return(null); } if (!StoreUtility.TryFindBestBetterStoreCellFor(th, pawn, pawn.Map, StoragePriority.Unstored, pawn.Faction, out var storeCell, false)) { return(null); } var supplyFromHereDist = th.Position.DistanceTo(dest); var supplyFromStoreDist = storeCell.DistanceTo(dest); Debug.WriteLine($"Carry from here: {supplyFromHereDist}; carry from store: {supplyFromStoreDist}"); // [KV] Infinite Storage https://steamcommunity.com/sharedfiles/filedetails/?id=1233893175 // infinite storage has an interaction spot 1 tile away from itself if (supplyFromStoreDist + 1 < supplyFromHereDist) { Debug.WriteLine($"'{pawn}' prefixed job with storage haul for '{th.Label}' because '{storeCell.GetSlotGroup(pawn.Map)}' is closer to original destination '{dest}'."); return(PuahJob(pawn, dest, th, storeCell) ?? HaulAIUtility.HaulToCellStorageJob(pawn, th, storeCell, false)); } return(null); }
static Job TryHaulStage(Pawn pawn, IntVec3 jobCell, ProximityCheck proximityCheck) { foreach (var thing in pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling()) { if (thingProximityStage.TryGetValue(thing, out var proximityStage) && proximityStage == ProximityStage.Fail) { continue; } var newProximityStage = CanHaul(proximityStage, pawn, thing, jobCell, proximityCheck, out var storeCell); Debug.WriteLine($"{pawn} for {thing} proximity stage: {proximityStage} -> {newProximityStage}"); thingProximityStage.SetOrAdd(thing, newProximityStage); if (newProximityStage != ProximityStage.Success) { continue; } if (DebugViewSettings.drawOpportunisticJobs) { Log.Message("Opportunistic job spawned"); pawn.Map.debugDrawer.FlashLine(pawn.Position, thing.Position, 600, SimpleColor.Red); pawn.Map.debugDrawer.FlashLine(thing.Position, storeCell, 600, SimpleColor.Green); pawn.Map.debugDrawer.FlashLine(storeCell, jobCell, 600, SimpleColor.Blue); } pawnHaulToCell.SetOrAdd(pawn, true); return(PuahJob(pawn, jobCell, thing, storeCell) ?? HaulAIUtility.HaulToCellStorageJob(pawn, thing, storeCell, false)); } return(null); }
static Job TryHaulStage(Pawn pawn, IntVec3 jobCell, ProximityCheck proximityCheck) { foreach (var thing in pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling()) { if (thingProximityStage.TryGetValue(thing, out var proximityStage) && proximityStage == ProximityStage.Fail) { continue; } var newProximityStage = CanHaul(proximityStage, pawn, thing, jobCell, proximityCheck, out var storeCell); // Debug.WriteLine($"{pawn} for {thing} proximity stage: {proximityStage} -> {newProximityStage}"); thingProximityStage.SetOrAdd(thing, newProximityStage); if (newProximityStage != ProximityStage.Success) { continue; } #if RELEASE if (DebugViewSettings.drawOpportunisticJobs) { #endif pawn.Map.debugDrawer.FlashLine(pawn.Position, jobCell, 600, SimpleColor.Red); pawn.Map.debugDrawer.FlashLine(pawn.Position, thing.Position, 600, SimpleColor.Green); pawn.Map.debugDrawer.FlashLine(thing.Position, storeCell, 600, SimpleColor.Green); pawn.Map.debugDrawer.FlashLine(storeCell, jobCell, 600, SimpleColor.Green); #if RELEASE } #endif var haulTracker = HaulTracker.CreateAndAdd(SpecialHaulType.Opportunity, pawn, jobCell); return(PuahJob(haulTracker, pawn, thing, storeCell) ?? HaulAIUtility.HaulToCellStorageJob(pawn, thing, storeCell, false)); } return(null); }
public static Job HopperFillFoodJob(Pawn pawn, ISlotGroupParent hopperSgp) { Building building = (Building)hopperSgp; if (!pawn.CanReserveAndReach(building.Position, PathEndMode.Touch, pawn.NormalMaxDanger())) { return(null); } ThingDef thingDef = null; Thing firstItem = building.Position.GetFirstItem(building.Map); if (firstItem != null) { if (!Building_NutrientPasteDispenser.IsAcceptableFeedstock(firstItem.def)) { if (firstItem.IsForbidden(pawn)) { return(null); } return(HaulAIUtility.HaulAsideJobFor(pawn, firstItem)); } thingDef = firstItem.def; } List <Thing> list = (thingDef != null) ? pawn.Map.listerThings.ThingsOfDef(thingDef) : pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.FoodSourceNotPlantOrTree); bool flag = false; for (int i = 0; i < list.Count; i++) { Thing thing = list[i]; if (thing.def.IsNutritionGivingIngestible && (thing.def.ingestible.preferability == FoodPreferability.RawBad || thing.def.ingestible.preferability == FoodPreferability.RawTasty) && HaulAIUtility.PawnCanAutomaticallyHaul(pawn, thing, forced: false) && pawn.Map.haulDestinationManager.SlotGroupAt(building.Position).Settings.AllowedToAccept(thing)) { StoragePriority storagePriority = StoreUtility.CurrentStoragePriorityOf(thing); if ((int)storagePriority >= (int)hopperSgp.GetSlotGroup().Settings.Priority) { flag = true; JobFailReason.Is(TheOnlyAvailableFoodIsInStorageOfHigherPriorityTrans); } else { Job job = HaulAIUtility.HaulToCellStorageJob(pawn, thing, building.Position, fitInStoreCell: true); if (job != null) { return(job); } } } } if (!flag) { JobFailReason.Is(NoFoodToFillHopperTrans); } return(null); }
// "Optimize hauling" public static Job HaulBeforeCarry(Pawn pawn, IntVec3 destCell, Thing thing) { if (thing.ParentHolder is Pawn_InventoryTracker) { return(null); } if (!JooStoreUtility.TryFindBestBetterStoreCellFor_ClosestToDestCell( thing, destCell, pawn, pawn.Map, StoreUtility.CurrentStoragePriorityOf(thing), pawn.Faction, out var storeCell, true)) { return(null); } var supplyFromHereDist = thing.Position.DistanceTo(destCell); var supplyFromStoreDist = storeCell.DistanceTo(destCell); // Debug.WriteLine($"Carry from here: {supplyFromHereDist}; carry from store: {supplyFromStoreDist}"); // [KV] Infinite Storage https://steamcommunity.com/sharedfiles/filedetails/?id=1233893175 // infinite storage has an interaction spot 1 tile away from itself if (supplyFromStoreDist + 1 < supplyFromHereDist) { // Debug.WriteLine( // $"'{pawn}' prefixed job with haul for '{thing.Label}' because '{storeCell.GetSlotGroup(pawn.Map)}' is closer to original destination '{destCell}'."); #if RELEASE if (DebugViewSettings.drawOpportunisticJobs) { #endif pawn.Map.debugDrawer.FlashLine(pawn.Position, thing.Position, 600, SimpleColor.White); // unchanged pawn.Map.debugDrawer.FlashLine(thing.Position, destCell, 600, SimpleColor.Magenta); pawn.Map.debugDrawer.FlashLine(thing.Position, storeCell, 600, SimpleColor.Cyan); pawn.Map.debugDrawer.FlashLine(storeCell, destCell, 600, SimpleColor.Cyan); #if RELEASE } #endif var haulTracker = HaulTracker.CreateAndAdd(SpecialHaulType.HaulBeforeCarry, pawn, destCell); return(PuahJob(haulTracker, pawn, thing, storeCell) ?? HaulAIUtility.HaulToCellStorageJob(pawn, thing, storeCell, false)); } return(null); }
private Toil Collect() { return(new Toil() { initAction = delegate { // Increment the record for how many cells this pawn has mined since this counts as mining // TODO: B19 - change to quarry m3 pawn.records.Increment(RecordDefOf.CellsMined); // Start with None to act as a fallback. Rubble will be returned with this parameter ResourceRequest req = ResourceRequest.None; // Use the mineModeToggle to determine the request req = (ResourceRequest)(((int)Quarry.mineModeToggle) + 1); MoteType mote = MoteType.None; int stackCount = 1; // Get the resource from the quarry ThingDef def = Quarry.GiveResources(req, out mote, out bool singleSpawn, out bool eventTriggered); // If something went wrong, bail out if (def == null || def.thingClass == null) { Log.Warning("Quarry:: Tried to quarry mineable ore, but the ore given was null."); mote = MoteType.None; singleSpawn = true; // This shouldn't happen at all, but if it does let's add a little reward instead of just giving rubble def = ThingDefOf.ChunkSlagSteel; } Thing haulableResult = ThingMaker.MakeThing(def); if (!singleSpawn && def != ThingDefOf.ComponentIndustrial) { int sub = (int)(def.BaseMarketValue / 2f); sub = Mathf.Clamp(sub, 0, 10); stackCount += Mathf.Min(Rand.RangeInclusive(15 - sub, 40 - (sub * 2)), def.stackLimit - 1); } if (def == ThingDefOf.ComponentIndustrial) { stackCount += Random.Range(0, 1); } haulableResult.stackCount = stackCount; if (stackCount >= 30) { mote = MoteType.LargeVein; } bool usesQuality = false; // Adjust quality for items that use it if (haulableResult.TryGetComp <CompQuality>() != null) { usesQuality = true; haulableResult.TryGetComp <CompQuality>().SetQuality(QualityUtility.GenerateQualityTraderItem(), ArtGenerationContext.Outsider); } // Adjust hitpoints, this was just mined from under the ground after all if (def.useHitPoints && !def.thingCategories.Contains(QuarryDefOf.StoneChunks) && def != ThingDefOf.ComponentIndustrial) { float minHpThresh = 0.25f; if (usesQuality) { minHpThresh = Mathf.Clamp((float)haulableResult.TryGetComp <CompQuality>().Quality / 10f, 0.1f, 0.7f); } int hp = Mathf.RoundToInt(Rand.Range(minHpThresh, 1f) * haulableResult.MaxHitPoints); hp = Mathf.Max(1, hp); haulableResult.HitPoints = hp; } // Place the resource near the pawn GenPlace.TryPlaceThing(haulableResult, pawn.Position, Map, ThingPlaceMode.Near); // If the resource had a mote, throw it if (mote == MoteType.LargeVein) { MoteMaker.ThrowText(haulableResult.DrawPos, Map, Static.TextMote_LargeVein, Color.green, 3f); } else if (mote == MoteType.Failure) { MoteMaker.ThrowText(haulableResult.DrawPos, Map, Static.TextMote_MiningFailed, Color.red, 3f); } // If the sinkhole event was triggered, damage the pawn and end this job // Even if the sinkhole doesn't incapacitate the pawn, they will probably want to seek medical attention if (eventTriggered) { NamedArgument pawnName = new NamedArgument(0, pawn.NameShortColored); Messages.Message("QRY_MessageSinkhole".Translate(pawnName), pawn, MessageTypeDefOf.NegativeEvent); DamageInfo dInfo = new DamageInfo(DamageDefOf.Crush, 9, category: DamageInfo.SourceCategory.Collapse); dInfo.SetBodyRegion(BodyPartHeight.Bottom, BodyPartDepth.Inside); pawn.TakeDamage(dInfo); EndJobWith(JobCondition.Succeeded); } else { // Prevent the colonists from trying to haul rubble, which just makes them visit the platform if (def == ThingDefOf.Filth_RubbleRock) { EndJobWith(JobCondition.Succeeded); } else { // If this is a chunk or slag, mark it as haulable if allowed to if (def.designateHaulable && Quarry.autoHaul) { Map.designationManager.AddDesignation(new Designation(haulableResult, DesignationDefOf.Haul)); } // Try to find a suitable storage spot for the resource, removing it from the quarry // If there are no platforms with free space, or if the resource is a chunk, try to haul it to a storage area if (Quarry.autoHaul) { if (!def.thingCategories.Contains(QuarryDefOf.StoneChunks) && Quarry.HasConnectedPlatform && Quarry.TryFindBestPlatformCell(haulableResult, pawn, Map, pawn.Faction, out IntVec3 c)) { job.SetTarget(TargetIndex.B, haulableResult); job.count = haulableResult.stackCount; job.SetTarget(TargetIndex.C, c); } else { StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(haulableResult); Job result; if (!StoreUtility.TryFindBestBetterStorageFor(haulableResult, pawn, Map, currentPriority, pawn.Faction, out c, out IHaulDestination haulDestination, true)) { JobFailReason.Is("NoEmptyPlaceLower".Translate(), null); } else if (haulDestination is ISlotGroupParent) { result = HaulAIUtility.HaulToCellStorageJob(pawn, haulableResult, c, false); } else { job.SetTarget(TargetIndex.B, haulableResult); job.count = haulableResult.stackCount; job.SetTarget(TargetIndex.C, c); } } }