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);
            }
Exemple #3
0
            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);
            }
Exemple #4
0
        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);
        }
Exemple #5
0
            // "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);
                                    }
                                }
                            }