Beispiel #1
0
        /// <summary>
        /// Handles activating aim mode at the start of the burst
        /// </summary>
        public override void WarmupComplete()
        {
            if (xpTicks <= 0)
            {
                xpTicks = Mathf.CeilToInt(verbProps.warmupTime * BaseXPMultiplyer);
            }

            if (this.ShouldAim && !this.isAiming)
            {
                float targetDist = (this.currentTarget.Cell - this.caster.Position).LengthHorizontal;
                int   aimTicks   = (int)Mathf.Lerp(aimTicksMin, aimTicksMax, (targetDist / 100));
                if (ShooterPawn != null)
                {
                    this.ShooterPawn.stances.SetStance(new Stance_Warmup(aimTicks, this.currentTarget, this));
                    this.isAiming = true;
                    return;
                }
                else
                {
                    Building_TurretGunCE turret = caster as Building_TurretGunCE;
                    if (turret != null)
                    {
                        turret.burstWarmupTicksLeft += aimTicks;
                        this.isAiming = true;
                        return;
                    }
                }
            }

            // Shooty stuff
            base.WarmupComplete();
            this.isAiming = false;
        }
 public void Unregister(Building_TurretGunCE t)
 {
     if (Turrets.Contains(t))
     {
         Turrets.Remove(t);
     }
 }
Beispiel #3
0
        public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (turret == null || (!forced && !turret.AllowAutomaticReload))
            {
                return(false);
            }

            if (!turret.NeedsReload ||
                !pawn.CanReserveAndReach(turret, PathEndMode.ClosestTouch, Danger.Deadly) ||
                turret.IsForbidden(pawn.Faction))
            {
                return(false);
            }
            if (!turret.CompAmmo.UseAmmo)
            {
                return(true);
            }
            Thing ammo = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map,
                                                          ThingRequest.ForDef(turret.CompAmmo.SelectedAmmo),
                                                          PathEndMode.ClosestTouch,
                                                          TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn),
                                                          80,
                                                          x => !x.IsForbidden(pawn) && pawn.CanReserve(x));

            return(ammo != null);
        }
        private Thing PawnClosestAmmo(Pawn pawn, Building_TurretGunCE turret, out bool fromInventory, bool forced = false)
        {
            var testAmmo = turret.nearestViableAmmo;

            int amount = turret.CompAmmo.Props.magazineSize;

            if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo)
            {
                amount -= turret.CompAmmo.CurMagCount;
            }

            if (testAmmo == null ||
                testAmmo.IsForbidden(pawn) ||
                !pawn.CanReserveAndReach(new LocalTargetInfo(testAmmo), PathEndMode.ClosestTouch, forced ? Danger.Deadly : pawn.NormalMaxDanger(),
                                         Mathf.Max(1, testAmmo.stackCount - amount), Mathf.Min(testAmmo.stackCount, amount), null, forced))
            {
                testAmmo      = turret.InventoryAmmo(pawn?.TryGetComp <CompInventory>());
                fromInventory = true;
            }
            else
            {
                fromInventory = false;
            }

            return(testAmmo);
        }
Beispiel #5
0
        public override Job JobOnThing(Pawn pawn, Thing t)
        {
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (turret == null)
            {
                return(null);
            }

            Thing ammo = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map,
                                                          ThingRequest.ForDef(turret.compAmmo.selectedAmmo),
                                                          PathEndMode.ClosestTouch,
                                                          TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn),
                                                          80,
                                                          x => !x.IsForbidden(pawn) && pawn.CanReserve(x));

            if (ammo == null)
            {
                return(null);
            }
            int amountNeeded = turret.compAmmo.Props.magazineSize;

            if (turret.compAmmo.currentAmmo == turret.compAmmo.selectedAmmo)
            {
                amountNeeded -= turret.compAmmo.curMagCount;
            }
            return(new Job(DefDatabase <JobDef> .GetNamed("ReloadTurret"), t, ammo)
            {
                count = Mathf.Min(amountNeeded, ammo.stackCount)
            });
        }
        private float GetThingPriority(Pawn pawn, Thing t, bool forced = false)
        {
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (pawn == null)
            {
                //Log.Message("Checking " + turret.ThingID + ", found pawn == null");
                return(0f);
            }
            if (turret == null || turret.IsForbidden(pawn) || !Checks(pawn, turret, forced))
            {
                return(0f);
            }

            if (!turret.Active)
            {
                return(1f);
            }
            if (turret.EmptyMagazine)
            {
                return(9f);
            }
            if (turret.AutoReloadableMagazine)
            {
                return(5f);
            }
            return(1f);
        }
        private bool Checks(Pawn pawn, Building_TurretGunCE turret, bool forced)
        {
            //WorkTagIsDisabled check inherent to WorkGiver_Scanner
            //MissingRequiredCapacity check inherent to WorkGiver_Scanner
            if (turret.isReloading)
            {
                //Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret is already reloading");
                return(false);  //Turret is already reloading
            }
            if (turret.FullMagazine)
            {
                // Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret doesn't need reload");
                return(false);  //Turret doesn't need reload
            }
            //if (!forced && !turret.AllowAutomaticReload) return false;  //Turret doesn't need auto-reload and isn't forced to reload
            if (turret.IsBurning())
            {
                // Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret on fire");
                return(false);   //Turret on fire
            }
            if (turret.Faction != pawn.Faction && (turret.Faction != null && pawn.Faction != null && turret.Faction.RelationKindWith(pawn.Faction) != FactionRelationKind.Ally))
            {
                // Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": non-allied turret");
                return(false);     //Allies reload turrets
            }
            if ((turret.MannableComp?.ManningPawn != pawn) && !pawn.CanReserveAndReach(turret, PathEndMode.ClosestTouch, forced ? Danger.Deadly : pawn.NormalMaxDanger(), GenClosestAmmo.pawnsPerTurret))
            {
                //Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret unreachable");
                return(false);    //Pawn cannot reach turret
            }

            return(true);
        }
 public void Register(Building_TurretGunCE t)
 {
     if (!Turrets.Contains(t))
     {
         Turrets.Add(t);
     }
 }
        //Checks before called (ONLY when in SCANNER):
        // - PawnCanUseWorkGiver(pawn, this)
        //      - nonColonistCanDo || isColonist
        //      - !WorkTagIsDisabled(def.workTags)
        //      - !ShouldSkip(pawn, false)
        //      - MissingRequiredCapacity(pawn) == null
        // - !t.IsForbidden(pawn)
        // - this.PotentialWorkThingRequest.Accepts(t),
        /// <summary>
        /// Called after HasJobOnThing by WorkGiver_Scanner, or by Building_TurretGunCE when turret tryReload with manningPawn
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="t"></param>
        /// <param name="forced"></param>
        /// <returns></returns>
        public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            var priority = GetThingPriority(pawn, t, forced);

            if (priority == 0f)
            {
                return(null);
            }

            //Do not check for NeedsReload etc. -- if forced, treat as if NeedsReload && AllowAutomaticReload

            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (!turret.CompAmmo.UseAmmo)
            {
                return(new Job(CE_JobDefOf.ReloadTurret, t, null));
            }

            int amountNeeded = turret.CompAmmo.Props.magazineSize;

            if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo)
            {
                amountNeeded -= turret.CompAmmo.CurMagCount;
            }

            turret.UpdateNearbyAmmo();

            var ammo = PawnClosestAmmo(pawn, turret, out bool fromInventory, forced);

            if (ammo == null)
            {
                return(null);
            }

            // Update selected ammo if necessary
            if (ammo.def != turret.CompAmmo.SelectedAmmo)    //New option can fill magazine completely (and is otherwise closer)
            {
                if ((priority >= 9f || ammo.stackCount >= amountNeeded))
                {
                    turret.CompAmmo.SelectedAmmo = ammo.def as AmmoDef;
                }
                else
                {
                    return(null);
                }
            }

            if (fromInventory && !pawn.TryGetComp <CompInventory>().container.TryDrop(ammo, pawn.Position, pawn.Map, ThingPlaceMode.Direct, Mathf.Min(ammo.stackCount, amountNeeded), out ammo))
            {
                Log.ErrorOnce("Found optimal ammo (" + ammo.LabelCap + "), but could not drop from " + pawn.LabelCap, 8164528);
                return(null);
            }

            return(new Job(CE_JobDefOf.ReloadTurret, t, ammo)
            {
                count = Mathf.Min(amountNeeded, ammo.stackCount)
            });
        }
Beispiel #10
0
        public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (turret == null || turret.CompAmmo == null)
            {
                return(null);
            }

            if (!turret.CompAmmo.UseAmmo)
            {
                return(new Job(CE_JobDefOf.ReloadTurret, t, null));
            }

            // Iterate through all possible ammo types for NPC's to find whichever is available, starting with currently selected
            Thing ammo      = null;
            var   ammoTypes = turret.CompAmmo.Props.ammoSet.ammoTypes.Select(l => l.ammo).ToList();
            var   index     = ammoTypes.IndexOf(turret.CompAmmo.SelectedAmmo);

            for (int i = 0; i < ammoTypes.Count; i++)
            {
                index = (index + i) % ammoTypes.Count;
                ammo  = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map,
                                                         ThingRequest.ForDef(ammoTypes[index]),
                                                         PathEndMode.ClosestTouch,
                                                         TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn),
                                                         80,
                                                         x => !x.IsForbidden(pawn) && pawn.CanReserve(x));
                if (ammo != null || pawn.Faction == Faction.OfPlayer)
                {
                    break;
                }
            }
            if (ammo == null)
            {
                return(null);
            }

            // Update selected ammo if necessary
            if (ammo.def != turret.CompAmmo.SelectedAmmo)
            {
                turret.CompAmmo.SelectedAmmo = ammo.def as AmmoDef;
            }

            // Create the actual job
            int amountNeeded = turret.CompAmmo.Props.magazineSize;

            if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo)
            {
                amountNeeded -= turret.CompAmmo.CurMagCount;
            }
            return(new Job(DefDatabase <JobDef> .GetNamed("ReloadTurret"), t, ammo)
            {
                count = Mathf.Min(amountNeeded, ammo.stackCount)
            });
        }
Beispiel #11
0
        public override bool HasJobOnThing(Pawn pawn, Thing t)
        {
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (turret == null || !turret.allowAutomaticReload)
            {
                return(false);
            }
            return(HasJobOnThingForced(pawn, t));
        }
        private void InitTurret()
        {
            Building_TurretGunCE turret = parent as Building_TurretGunCE;

            if (turret != null && turret.gun == null)
            {
                gun        = (Thing)ThingMaker.MakeThing(parent.def.building.turretGunDef);
                turret.gun = gun;
            }
        }
        protected override IEnumerable <Toil> MakeNewToils()
        {
            if (pawn.Faction != Faction.OfPlayer)
            {
                TargetThingB.SetForbidden(false, false);
                this.FailOnDestroyedOrNull(TargetIndex.A);
                this.FailOnDestroyedOrNull(TargetIndex.B);
            }
            else
            {
                this.FailOnDestroyedNullOrForbidden(TargetIndex.A);
                this.FailOnDestroyedNullOrForbidden(TargetIndex.B);
            }

            // Haul ammo
            yield return(Toils_Reserve.Reserve(TargetIndex.A, 1));

            yield return(Toils_Reserve.Reserve(TargetIndex.B, 1));

            yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch));

            yield return(Toils_Haul.StartCarryThing(TargetIndex.B));

            yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch));

            yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.A, null, false));

            // Wait in place
            Toil waitToil = new Toil();

            waitToil.initAction = delegate
            {
                waitToil.actor.pather.StopDead();
                compReloader.TryStartReload();
            };
            waitToil.defaultCompleteMode = ToilCompleteMode.Delay;
            waitToil.defaultDuration     = Mathf.CeilToInt(compReloader.Props.reloadTicks / pawn.GetStatValue(CE_StatDefOf.ReloadSpeed));
            yield return(waitToil.WithProgressBarToilDelay(TargetIndex.A));

            //Actual reloader
            Toil reloadToil = new Toil();

            reloadToil.defaultCompleteMode = ToilCompleteMode.Instant;
            reloadToil.initAction          = delegate
            {
                Building_TurretGunCE turret = TargetThingA as Building_TurretGunCE;
                if (compReloader != null && turret.compAmmo != null)
                {
                    compReloader.LoadAmmo(TargetThingB);
                }
            };
            reloadToil.EndOnDespawnedOrNull(TargetIndex.B);
            yield return(reloadToil);
        }
Beispiel #14
0
        //Checks before called (ONLY when in SCANNER):
        // - PawnCanUseWorkGiver(pawn, this)
        //      - nonColonistCanDo || isColonist
        //      - !WorkTagIsDisabled(def.workTags)
        //      - !ShouldSkip(pawn, false)
        //      - MissingRequiredCapacity(pawn) == null
        // - !t.IsForbidden(pawn)
        // - this.PotentialWorkThingRequest.Accepts(t),
        /// <summary>
        /// Called after HasJobOnThing by WorkGiver_Scanner, or by Building_TurretGunCE when turret tryReload with manningPawn
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="t"></param>
        /// <param name="forced"></param>
        /// <returns></returns>
        public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (turret == null)
            {
                CELogger.Error($"{pawn} tried to make a reload job on a {t} which isn't a turret. This should never be reached.");
            }

            // NOTE: The removal of the code that used to be here disables reloading turrets directly from one's inventory.
            // The player would need to drop the ammo the pawn is holding first.

            return(JobGiverUtils_Reload.MakeReloadJob(pawn, turret));
        }
Beispiel #15
0
        //Checks before called (ONLY when in SCANNER):
        // - PawnCanUseWorkGiver(pawn, this)
        //      - nonColonistCanDo || isColonist
        //      - !WorkTagIsDisabled(def.workTags)
        //      - !ShouldSkip(pawn, false)
        //      - MissingRequiredCapacity(pawn) == null
        // - !t.IsForbidden(pawn)
        // - this.PotentialWorkThingRequest.Accepts(t),
        /// <summary>
        /// Called after HasJobOnThing by WorkGiver_Scanner, or by Building_TurretGunCE when turret tryReload with manningPawn
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="t"></param>
        /// <param name="forced"></param>
        /// <returns></returns>
        public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            //Do not check for NeedsReload etc. -- if forced, treat as if NeedsReload && AllowAutomaticReload

            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (!turret.CompAmmo.UseAmmo)
            {
                return(JobGiverUtils_Reload.MakeReloadJobNoAmmo(turret));
            }

            // NOTE: The removal of the code that used to be here disables reloading turrets directly from one's inventory.
            // The player would need to drop the ammo the pawn is holding first.

            return(JobGiverUtils_Reload.MakeReloadJob(pawn, turret));
        }
Beispiel #16
0
        private float GetThingPriority(Pawn pawn, Thing t, bool forced = false)
        {
            CELogger.Message($"pawn: {pawn}. t: {t}. forced: {forced}");
            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (!turret.Active)
            {
                return(1f);
            }
            if (turret.EmptyMagazine)
            {
                return(9f);
            }
            if (turret.AutoReloadableMagazine)
            {
                return(5f);
            }
            return(1f);
        }
Beispiel #17
0
        /// <summary>
        /// Called as a scanner
        /// </summary>
        /// <param name="pawn">Never null</param>
        /// <param name="t">Can be non-turret</param>
        /// <param name="forced">Generally not true</param>
        /// <returns></returns>

        public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            // Should never happen anymore, as only TurretGunCEs should be returned from PotentialWorkThingsGlobal
            if (!(t is Building_TurretGunCE))
            {
                return(false);
            }

            var priority = GetThingPriority(pawn, t, forced);

            CELogger.Message($"Priority check completed. Got {priority}");

            Building_TurretGunCE turret = t as Building_TurretGunCE;

            CELogger.Message($"Turret uses ammo? {turret.CompAmmo.UseAmmo}");

            CELogger.Message($"Total magazine size: {turret.CompAmmo.Props.magazineSize}. Needed: {turret.CompAmmo.MissingToFullMagazine}");

            return(JobGiverUtils_Reload.CanReload(pawn, turret, forced));
        }
        /// <summary>
        /// Called as a scanner
        /// </summary>
        /// <param name="pawn">Never null</param>
        /// <param name="t">Can be non-turret</param>
        /// <param name="forced">Generally not true</param>
        /// <returns></returns>

        /*public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
         * {
         *    Building_TurretGunCE turret = t as Building_TurretGunCE;
         *    if (turret == null || !Checks(pawn, turret, forced))  return false;
         *
         *    if (!turret.CompAmmo.UseAmmo)
         *        return true;
         *
         *    turret.UpdateNearbyAmmo();
         *
         *    Thing ammo = turret.nearestViableAmmo;
         *
         *    int amountNeeded = turret.CompAmmo.Props.magazineSize;
         *    if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) amountNeeded -= turret.CompAmmo.CurMagCount;
         *
         *    if (ammo == null || ammo.IsForbidden(pawn) || !pawn.CanReserveAndReach(new LocalTargetInfo(ammo), PathEndMode.ClosestTouch, pawn.NormalMaxDanger(), Mathf.Max(1, ammo.stackCount - amountNeeded), amountNeeded, null, forced))
         *    {
         *        ammo = turret.InventoryAmmo(pawn.TryGetComp<CompInventory>());
         *    }
         *
         *    return ammo != null;
         * }*/

        public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            var priority = GetThingPriority(pawn, t, forced);

            if (priority == 0f)
            {
                return(false);
            }

            Building_TurretGunCE turret = t as Building_TurretGunCE;

            if (!turret.CompAmmo.UseAmmo)
            {
                return(true);
            }

            int amountNeeded = turret.CompAmmo.Props.magazineSize;

            if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo)
            {
                amountNeeded -= turret.CompAmmo.CurMagCount;
            }

            turret.UpdateNearbyAmmo();
            Thing ammo = PawnClosestAmmo(pawn, turret, out bool _, forced);

            if (ammo == null)
            {
                return(false);
            }

            // Update selected ammo if necessary
            if (ammo.def != turret.CompAmmo.SelectedAmmo &&
                priority < 9f && ammo.stackCount < amountNeeded)       //New option can fill magazine completely (and is otherwise closer)
            {
                return(false);
            }

            return(true);
        }
Beispiel #19
0
        /// <summary>
        /// Called as a scanner
        /// </summary>
        /// <param name="pawn">Never null</param>
        /// <param name="t">Can be non-turret</param>
        /// <param name="forced">Generally not true</param>
        /// <returns></returns>

        public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
        {
            if (!(t is Building_TurretGunCE))
            {
                return(false);
            }
            var priority = GetThingPriority(pawn, t, forced);

            CELogger.Message($"Priority check completed. Got {priority}");

            Building_TurretGunCE turret = t as Building_TurretGunCE;

            CELogger.Message($"Turret uses ammo? {turret.CompAmmo.UseAmmo}");
            if (!turret.CompAmmo.UseAmmo)
            {
                return(true);
            }

            CELogger.Message($"Total magazine size: {turret.CompAmmo.Props.magazineSize}. Needed: {turret.CompAmmo.MissingToFullMagazine}");

            return(JobGiverUtils_Reload.CanReload(pawn, turret, forced));
        }
        public bool EnoughAmmoAround(Building_TurretGunCE turret)
        {
            //Prevent ammo being dropped as a result of the turret being reloaded at the time
            if (turret.isReloading || turret.FullMagazine)
            {
                return(true);
            }

            var ammoComp = turret.CompAmmo;

            int num  = GenRadial.NumCellsInRadius(20f);
            int num2 = ammoComp.CurMagCount;
            int num3 = Mathf.CeilToInt((float)ammoComp.Props.magazineSize / 6f);

            for (int i = 0; i < num; i++)
            {
                IntVec3 c = parent.Position + GenRadial.RadialPattern[i];
                if (c.InBounds(parent.Map))
                {
                    List <Thing> thingList = c.GetThingList(parent.Map);
                    for (int j = 0; j < thingList.Count; j++)
                    {
                        if ((ammoComp != null && ammoComp.CurrentAmmo == thingList[j].def))
                        {
                            num2 += thingList[j].stackCount;

                            if (num2 > num3)
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
        public Pawn BestNonJobUser(IEnumerable <Pawn> pawns, Building_TurretGunCE turret, out bool fromInventory, bool forced = false)
        {
            fromInventory = false;

            if (!pawns.Any())
            {
                return(null);
            }

            //Cut a significant portion of pawns
            pawns = pawns.Where(p => !ShouldSkip(p) && !p.Downed && !p.Dead && p.Spawned && (p.mindState?.Active ?? true) &&
                                (!p.mindState?.mentalStateHandler?.InMentalState ?? true) && !turret.IsForbidden(p) &&
                                (turret.Faction == p.Faction || turret.Faction?.RelationKindWith(p.Faction) == FactionRelationKind.Ally) &&
                                p.CanReserveAndReach(new LocalTargetInfo(turret), PathEndMode.InteractionCell, forced ? Danger.Deadly : p.NormalMaxDanger(), GenClosestAmmo.pawnsPerTurret, -1, null, forced));

            //No pawns remaining => quit
            if (!pawns.Any())
            {
                return(null);
            }

            //If no ammo is used, minimize distance
            if (!turret.CompAmmo?.UseAmmo ?? true)
            {
                return(pawns.MinBy(x => x.Position.DistanceTo(turret.Position)));
            }

            //ELSE: ammo is used, pawns remain
            turret.UpdateNearbyAmmo(forced);
            var hasNearbyAmmo = turret.nearestViableAmmo != null;

            int amount = turret.CompAmmo.Props.magazineSize;

            if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo)
            {
                amount -= turret.CompAmmo.CurMagCount;
            }

            if (hasNearbyAmmo)
            {
                pawns = pawns.OrderBy(x => x.Position.DistanceTo(turret.Position));
            }

            var  bestNonInventoryDistance = 9999f;
            Pawn bestPawn        = null;
            var  minimumDistance = hasNearbyAmmo ? turret.Position.DistanceTo(turret.nearestViableAmmo.Position) : 0f;

            //Sort through ASCENDING DISTANCE TO TURRET -- e.g, inventory ammo is preferred
            foreach (var p in pawns)
            {
                if (PawnClosestAmmo(p, turret, out fromInventory, forced) == null)
                {
                    continue;
                }

                if (fromInventory)
                {
                    if (p.Position.DistanceTo(turret.Position) < bestNonInventoryDistance + minimumDistance)
                    {
                        return(p);
                    }
                }
                else if (hasNearbyAmmo)
                {
                    var dist = p.Position.DistanceTo(turret.nearestViableAmmo.Position);

                    if (dist < bestNonInventoryDistance)
                    {
                        bestNonInventoryDistance = dist;
                        bestPawn = p;
                    }
                }
            }

            fromInventory = false;
            return(bestPawn);
        }