Exemple #1
0
        public static bool trySwapToMoreAccurateRangedWeapon(Pawn pawn, LocalTargetInfo target, bool dropCurrent, bool skipManualUse, bool skipDangerous = true, bool skipEMP = true)
        {
            CompSidearmMemory pawnMemory = CompSidearmMemory.GetMemoryCompForPawn(pawn);

            if (pawn == null || pawn.Dead || pawnMemory == null || pawn.equipment == null || pawn.inventory == null)
            {
                return(false);
            }

            if (pawnMemory.IsCurrentWeaponForced(false))
            {
                return(false);
            }

            (ThingWithComps weapon, float dps, float averageSpeed)bestWeapon = GettersFilters.findBestRangedWeapon(pawn, target, skipManualUse, skipDangerous, skipEMP, true);

            if (bestWeapon.weapon == null)
            {
                return(false);
            }

            CellRect cellRect   = (!target.HasThing) ? CellRect.SingleCell(target.Cell) : target.Thing.OccupiedRect();
            float    range      = cellRect.ClosestDistSquaredTo(pawn.Position);
            float    currentDPS = StatCalculator.RangedDPS(pawn.equipment.Primary, Settings.SpeedSelectionBiasRanged, bestWeapon.averageSpeed, range);

            if (bestWeapon.dps < currentDPS + MiscUtils.ANTI_OSCILLATION_FACTOR)
            {
                return(false);
            }

            equipSpecificWeaponFromInventory(pawn, bestWeapon.weapon, dropCurrent, false);
            return(true);
        }
        // Verse.Verb
        // Token: 0x060022E2 RID: 8930 RVA: 0x000D4A4C File Offset: 0x000D2C4C
        public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            if (targ.HasThing && targ.Thing.Map != this.Caster.Map)
            {
                resultingLine = default(ShootLine);
                return(false);
            }
            if (this.verbProps.IsMeleeAttack || this.EffectiveRange <= 1.42f)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(ReachabilityImmediate.CanReachImmediate(root, targ, this.Caster.Map, PathEndMode.Touch, null));
            }
            CellRect cellRect = targ.HasThing ? targ.Thing.OccupiedRect() : CellRect.SingleCell(targ.Cell);
            float    num      = this.verbProps.EffectiveMinRange(targ, this.Caster);
            float    num2     = cellRect.ClosestDistSquaredTo(root);

            if (num2 > this.EffectiveRange * this.EffectiveRange || num2 < num * num)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(false);
            }
            if (!this.verbProps.requireLineOfSight)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(true);
            }
            if (this.CasterIsPawn)
            {
                if (this.CanHitFromCellIgnoringRange(root, targ, out IntVec3 dest))
                {
                    resultingLine = new ShootLine(root, dest);
                    return(true);
                }
                ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.Caster.Map, Verb_ShootCompMountedCE.tempLeanShootSources);
                for (int i = 0; i < Verb_ShootCompMountedCE.tempLeanShootSources.Count; i++)
                {
                    IntVec3 intVec = Verb_ShootCompMountedCE.tempLeanShootSources[i];
                    if (this.CanHitFromCellIgnoringRange(intVec, targ, out dest))
                    {
                        resultingLine = new ShootLine(intVec, dest);
                        return(true);
                    }
                }
            }
            else
            {
                IntVec2 size = new IntVec2(Caster.def.size.x + 1, Caster.def.size.z + 1);
                foreach (IntVec3 intVec2 in GenAdj.OccupiedRect(Caster.Position, Caster.Rotation, size))
                {
                    if (this.CanHitFromCellIgnoringRange(intVec2, targ, out IntVec3 dest))
                    {
                        resultingLine = new ShootLine(intVec2, dest);
                        return(true);
                    }
                }
            }
            resultingLine = new ShootLine(root, targ.Cell);
            return(false);
        }
Exemple #3
0
        public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            if (targ.HasThing && targ.Thing.Map != caster.Map)
            {
                resultingLine = default(ShootLine);
                return(false);
            }
            if (verbProps.range <= ShootTuning.MeleeRange) // If this verb has a MAX range up to melee range (NOT a MIN RANGE!)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(ReachabilityImmediate.CanReachImmediate(root, targ, caster.Map, PathEndMode.Touch, null));
            }
            CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect();
            float    num      = cellRect.ClosestDistSquaredTo(root);

            if (num > verbProps.range * verbProps.range || num < verbProps.minRange * verbProps.minRange)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(false);
            }
            //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile
            if (Projectile.projectile.flyOverhead)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(true);
            }

            // First check current cell for early opt-out
            IntVec3 dest;
            var     shotSource = root.ToVector3Shifted();

            shotSource.y = ShotHeight;
            if (CanHitFromCellIgnoringRange(shotSource, targ, out dest))
            {
                resultingLine = new ShootLine(root, dest);
                return(true);
            }
            // For pawns, calculate possible lean locations
            if (CasterIsPawn)
            {
                // Next check lean sources
                ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), caster.Map, tempLeanShootSources);
                foreach (var leanLoc in tempLeanShootSources)
                {
                    var leanOffset = (leanLoc - root).ToVector3() * 0.5f;

                    if (CanHitFromCellIgnoringRange(shotSource + leanOffset, targ, out dest))
                    {
                        resultingLine = new ShootLine(leanLoc, dest);
                        return(true);
                    }
                }
            }

            resultingLine = new ShootLine(root, targ.Cell);
            return(false);
        }
Exemple #4
0
        public static (ThingWithComps weapon, float dps, float averageSpeed) findBestRangedWeapon(Pawn pawn, LocalTargetInfo?target = null, bool skipDangerous = true, bool includeEquipped = true)
        {
            if (pawn == null || pawn.Dead || pawn.equipment == null || pawn.inventory == null)
            {
                return(null, -1, 0);
            }

            IEnumerable <ThingWithComps> options = pawn.getCarriedWeapons(includeEquipped).Where(t =>
            {
                return(t.def.IsRangedWeapon);
            });

            if (options.Count() == 0)
            {
                return(null, -1, 0);
            }

            float averageSpeed = AverageSpeedRanged(options);

            if (target.HasValue)
            {
                //TODO: handle DPS vs. armor?
                CellRect cellRect = (!target.Value.HasThing) ? CellRect.SingleCell(target.Value.Cell) : target.Value.Thing.OccupiedRect();
                float    range    = cellRect.ClosestDistSquaredTo(pawn.Position);
                (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed);
                foreach (ThingWithComps candidate in options)
                {
                    float dps = StatCalculator.RangedDPS(candidate, SpeedSelectionBiasRanged.Value, averageSpeed, range);
                    if (dps > best.dps)
                    {
                        best = (candidate, dps, averageSpeed);
                    }
                }
                return(best);
            }
            else
            {
                (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed);
                foreach (ThingWithComps candidate in options)
                {
                    float dps = StatCalculator.RangedDPSAverage(candidate, SpeedSelectionBiasRanged.Value, averageSpeed);
                    if (dps > best.dps)
                    {
                        best = (candidate, dps, averageSpeed);
                    }
                }
                return(best);
            }
        }
        private static void StanceTick(Stance_Warmup __instance)
        {
            if (SimpleSidearms.RangedCombatAutoSwitch == false)
            {
                return;
            }
            Pawn pawn = __instance.stanceTracker.pawn;

            if (SwapControlsHandler.GetHandlerForPawn(pawn).currentWeaponLocked)
            {
                return;
            }
            if (IsHunting(pawn))
            {
                return;
            }
            if (!SimpleSidearms.CEOverride && !(__instance.verb is Verb_Shoot))
            {
                return;
            }
            if (SimpleSidearms.CEOverride && !(CERangedVerb.IsAssignableFrom(__instance.verb.GetType())))
            {
                return;
            }
            float statValue = pawn.GetStatValue(StatDefOf.AimingDelayFactor, true);
            int   ticks     = (__instance.verb.verbProps.warmupTime * statValue).SecondsToTicks();

            if (__instance.ticksLeft / (float)ticks < 1f - SimpleSidearms.RangedCombatAutoSwitchMaxWarmup.Value)
            {
                return;
            }

            LocalTargetInfo targ = __instance.focusTarg;

            if (pawn.inventory.innerContainer.Any((Thing x) => x.def.IsRangedWeapon))
            {
                CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect();
                float    range    = cellRect.ClosestDistSquaredTo(pawn.Position);
                WeaponAssingment.trySwapToMoreAccurateRangedWeapon(pawn, MiscUtils.shouldDrop(DroppingModeEnum.Range), range, pawn.IsColonistPlayerControlled);
            }
            else
            {
            }
        }
        /*
         * public bool CanSeeTarget(LocalTargetInfo targ)
         * {
         *  var glow = targ.Thing.Map.glowGrid.GameGlowAt(targ.Cell);
         *  var glowmultiplier = Mathf.Lerp(1, 5, Mathf.Clamp(glow * 5f, 0f, 1f));
         *
         *  float lengthToTarget = Mathf.Abs((targ.Cell - caster.Position).LengthHorizontal);
         *  if (targ.Thing.Map.glowGrid.GameGlowAt(targ.Cell) <= 0.2f)
         *  {
         *      Log.Message("target: " + targ.Thing +  " glow: " + glow.ToString() + " glowmult: " + glowmultiplier.ToString());
         *      if (lengthToTarget > glowmultiplier)
         *      {
         *          Log.Message("cant see: " + targ.Thing.ToString());
         *          return false;
         *      }
         *  }
         *  return true;
         * }
         */

        public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            //    Log.Message("root: " + root.ToString() + " target: " + targ.Thing.ToString() + " pos: " + targ.Cell.ToString());
            if (targ.HasThing && targ.Thing.Map != this.caster.Map)
            {
                resultingLine = default(ShootLine);
                //        Log.Message("shootline false: 1" + " line: " + resultingLine.ToString());
                return(false);
            }
            //    Log.Message("effminrange: " + this.verbProps.EffectiveMinRange(targ, this.caster).ToString() + " meleerange: " + ShootTuning.MeleeRange);

            if (this.verbProps.IsMeleeAttack)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                var ri = ReachabilityImmediate.CanReachImmediate(root, targ, this.caster.Map, PathEndMode.Touch, null);
                //        Log.Message("ri: " + ri.ToString() + " line: " + resultingLine.ToString());
                return(ri);
            }

            CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect();
            float    num      = cellRect.ClosestDistSquaredTo(root);

            if (num > this.verbProps.range * this.verbProps.range || num < this.verbProps.minRange * this.verbProps.minRange)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                //        Log.Message("shootline false: 2" + " line: " + resultingLine.ToString());
                return(false);
            }

            //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile
            if (Projectile.projectile.flyOverhead)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                //        Log.Message("shootline true: 3" + " line: " + resultingLine.ToString());
                return(true);
            }

            if (this.CasterIsPawn)
            {
                IntVec3 dest;
                ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.caster.Map, tempLeanShootSources);

                if (tempLeanShootSources.Count < 2)
                {
                    if (this.CanHitFromCellIgnoringRange(root, root, targ, out dest))
                    {
                        resultingLine = new ShootLine(root, dest);
                        //              Log.Message("shootline true: 4" + " line: " + resultingLine.ToString());
                        return(true);
                    }
                }

                if (tempLeanShootSources.Count >= 2)
                {
                    int bestZ    = 0;
                    int bestX    = 0;
                    int cachedbz = -1;
                    int cachedbx = -1;

                    //    Log.Message("pawn: " + CasterPawn.ToString() + " pawn pos: " + root.ToString() + " target: " + targ.Thing.ToString() + " target pos: " + targ.Cell.ToString());
                    foreach (var bsp in tempLeanShootSources)
                    {
                        var bz = Mathf.Abs(bsp.z - targ.Cell.z);
                        if (cachedbz < 0 || (bz < cachedbz))
                        {
                            cachedbz = bz;
                            bestZ    = bsp.z;
                        }

                        var bx = Mathf.Abs(bsp.x - targ.Cell.x);
                        if (cachedbx < 0 || (bx < cachedbx))
                        {
                            cachedbx = bx;
                            bestX    = bsp.x;
                        }
                    }
                    bestshootposition = new IntVec3(bestX, root.y, bestZ);
                    //    Log.Message("bestshootposition: " + bestshootposition.ToString());

                    if (this.CanHitFromCellIgnoringRange(bestshootposition, root, targ, out dest))
                    {
                        resultingLine = new ShootLine(bestshootposition, dest);
                        //        Log.Message("shootline true: 5" + " line: " + resultingLine.ToString());
                        return(true);
                    }
                }
                else
                {
                    for (int i = 0; i < tempLeanShootSources.Count; i++)
                    {
                        IntVec3 intVec = tempLeanShootSources[i];
                        if (this.CanHitFromCellIgnoringRange(intVec, root, targ, out dest))
                        {
                            resultingLine = new ShootLine(intVec, dest);
                            //            Log.Message("shootline true: 6" + " line: " + resultingLine.ToString());
                            return(true);
                        }
                    }
                }
            }
            else
            {
                CellRect.CellRectIterator iterator = this.caster.OccupiedRect().GetIterator();
                while (!iterator.Done())
                {
                    IntVec3 current = iterator.Current;
                    IntVec3 dest;
                    if (this.CanHitFromCellIgnoringRange(current, root, targ, out dest))
                    {
                        resultingLine = new ShootLine(current, dest);
                        //            Log.Message("shootline true: 7: " + " line: " + resultingLine.ToString());
                        return(true);
                    }
                    iterator.MoveNext();
                }
            }
            resultingLine = new ShootLine(root, targ.Cell);
            //    Log.Message("shootline false: 8" + " line: " + resultingLine.ToString());
            return(false);
        }
Exemple #7
0
        public static bool TryFindShootLineFromTo(Verb __instance, ref bool __result, IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            if (targ.HasThing && targ.Thing.Map != __instance.caster.Map)
            {
                resultingLine = default;
                __result      = false;
                return(false);
            }

            if (__instance.verbProps.IsMeleeAttack || __instance.verbProps.range <= 1.42f)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                __result      = ReachabilityImmediate.CanReachImmediate(root, targ, __instance.caster.Map, PathEndMode.Touch, null);
                return(false);
            }

            CellRect cellRect = targ.HasThing ? targ.Thing.OccupiedRect() : CellRect.SingleCell(targ.Cell);
            float    num      = __instance.verbProps.EffectiveMinRange(targ, __instance.caster);
            float    num2     = cellRect.ClosestDistSquaredTo(root);

            if (num2 > __instance.verbProps.range * __instance.verbProps.range || num2 < num * num)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                __result      = false;
                return(false);
            }

            if (!__instance.verbProps.requireLineOfSight)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                __result      = true;
                return(false);
            }

            IntVec3 goodDest;

            if (__instance.CasterIsPawn)
            {
                if (CanHitFromCellIgnoringRange2(__instance, root, targ, out goodDest))
                {
                    resultingLine = new ShootLine(root, goodDest);
                    __result      = true;
                    return(false);
                }
                List <IntVec3> tempLeanShootSources = new List <IntVec3>();                           //ADDED
                ShootLeanUtility.LeanShootingSourcesFromTo(
                    root, cellRect.ClosestCellTo(root), __instance.caster.Map, tempLeanShootSources); //CHANGED tempLeanShootSources
                for (int i = 0; i < tempLeanShootSources.Count; i++)                                  //CHANGED tempLeanShootSources
                {
                    IntVec3 intVec = tempLeanShootSources[i];                                         //CHANGED tempLeanShootSources
                    if (CanHitFromCellIgnoringRange2(__instance, intVec, targ, out goodDest))
                    {
                        resultingLine = new ShootLine(intVec, goodDest);
                        __result      = true;
                        return(false);
                    }
                }
            }
            else
            {
                foreach (IntVec3 item in __instance.caster.OccupiedRect())
                {
                    if (CanHitFromCellIgnoringRange2(__instance, item, targ, out goodDest))
                    {
                        resultingLine = new ShootLine(item, goodDest);
                        __result      = true;
                        return(false);
                    }
                }
            }

            resultingLine = new ShootLine(root, targ.Cell);
            __result      = false;
            return(false);
        }
Exemple #8
0
        public static (ThingWithComps weapon, float dps, float averageSpeed) findBestRangedWeapon(Pawn pawn, LocalTargetInfo?target = null, bool skipManualUse = true, bool skipDangerous = true, bool skipEMP = true, bool includeEquipped = true)
        {
            if (pawn == null || pawn.Dead || pawn.equipment == null || pawn.inventory == null)
            {
                return(null, -1, 0);
            }

            IEnumerable <ThingWithComps> options = pawn.getCarriedWeapons(includeEquipped).Where(t => t.def.IsRangedWeapon);

            if (!Settings.AllowBlockedWeaponUse)
            {
                options = options.Where(t => StatCalculator.canUseSidearmInstance(t, pawn, out _));
            }

            options = options.Where(t => !pawn.IsColonistPlayerControlled || !isManualUse(t));

            if (skipManualUse)
            {
                options = options.Where(t => (!isManualUse(t)));
            }
            if (skipDangerous)
            {
                options = options.Where(t => (!isDangerousWeapon(t)));
            }
            if (skipEMP)
            {
                options = options.Where(t => !isEMPWeapon(t));
            }

            if (options.Count() == 0)
            {
                return(null, -1, 0);
            }

            float averageSpeed = AverageSpeedRanged(options);

            if (target.HasValue)
            {
                CellRect cellRect       = (!target.Value.HasThing) ? CellRect.SingleCell(target.Value.Cell) : target.Value.Thing.OccupiedRect();
                float    targetDistance = cellRect.ClosestDistSquaredTo(pawn.Position);

                options = options.Where(t =>
                {
                    VerbProperties atkProps = (t.GetComp <CompEquippable>())?.PrimaryVerb?.verbProps;
                    if (atkProps == null)
                    {
                        return(false);
                    }
                    return(atkProps.range >= targetDistance);
                });

                if (options.Count() == 0)
                {
                    return(null, -1, 0);
                }

                //TODO: handle DPS vs. armor?
                (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed);
                foreach (ThingWithComps candidate in options)
                {
                    float dps = StatCalculator.RangedDPS(candidate, Settings.SpeedSelectionBiasRanged, averageSpeed, targetDistance);
                    if (dps > best.dps)
                    {
                        best = (candidate, dps, averageSpeed);
                    }
                }
                return(best);
            }
            else
            {
                (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed);
                foreach (ThingWithComps candidate in options)
                {
                    float dps = StatCalculator.RangedDPSAverage(candidate, Settings.SpeedSelectionBiasRanged, averageSpeed);
                    if (dps > best.dps)
                    {
                        best = (candidate, dps, averageSpeed);
                    }
                }
                return(best);
            }
        }
Exemple #9
0
        public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            if (targ.HasThing && targ.Thing.Map != this.caster.Map)
            {
                resultingLine = default(ShootLine);
                return(false);
            }
            if (this.verbProps.range <= ShootTuning.MeleeRange) // If this verb has a MAX range up to melee range (NOT a MIN RANGE!)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(ReachabilityImmediate.CanReachImmediate(root, targ, this.caster.Map, PathEndMode.Touch, null));
            }
            CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect();
            float    num      = cellRect.ClosestDistSquaredTo(root);

            if (num > this.verbProps.range * this.verbProps.range || num < this.verbProps.minRange * this.verbProps.minRange)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(false);
            }
            //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile
            if (Projectile.projectile.flyOverhead)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(true);
            }
            if (this.CasterIsPawn)
            {
                IntVec3 dest;
                if (this.CanHitFromCellIgnoringRange(root, targ, out dest))
                {
                    resultingLine = new ShootLine(root, dest);
                    return(true);
                }
                ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.caster.Map, tempLeanShootSources);
                for (int i = 0; i < tempLeanShootSources.Count; i++)
                {
                    IntVec3 intVec = tempLeanShootSources[i];
                    if (this.CanHitFromCellIgnoringRange(intVec, targ, out dest))
                    {
                        resultingLine = new ShootLine(intVec, dest);
                        return(true);
                    }
                }
            }
            else
            {
                CellRect.CellRectIterator iterator = this.caster.OccupiedRect().GetIterator();
                while (!iterator.Done())
                {
                    IntVec3 current = iterator.Current;
                    IntVec3 dest;
                    if (this.CanHitFromCellIgnoringRange(current, targ, out dest))
                    {
                        resultingLine = new ShootLine(current, dest);
                        return(true);
                    }
                    iterator.MoveNext();
                }
            }
            resultingLine = new ShootLine(root, targ.Cell);

            return(false);
        }
        public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            //	Log.Message("Verb_MeleeAttackDamage_Polearm TryFindShootLineFromTo");
            if (targ.HasThing && targ.Thing.Map != this.caster.Map)
            {
                resultingLine = default(ShootLine);
                return(false);
            }

            /*
             * if (this.verbProps.IsMeleeAttack || this.EffectiveRange <= 1.42f)
             * {
             *      resultingLine = new ShootLine(root, targ.Cell);
             *
             *      return this.CanReachImmediate(root, targ, this.caster.Map, PathEndMode.Touch, null);
             * }
             */
            CellRect cellRect = targ.HasThing ? targ.Thing.OccupiedRect() : CellRect.SingleCell(targ.Cell);
            float    num      = this.verbProps.EffectiveMinRange(targ, this.caster);
            float    num2     = cellRect.ClosestDistSquaredTo(root);

            if (num2 > this.EffectiveRange * this.EffectiveRange || num2 < num * num)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(false);
            }
            if (!this.verbProps.requireLineOfSight)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(true);
            }
            if (this.CasterIsPawn)
            {
                if (this.CanHitFromCellIgnoringRange(root, targ, out IntVec3 dest))
                {
                    resultingLine = new ShootLine(root, dest);
                    return(true);
                }
                ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.caster.Map, Verb_MeleeAttackDamage_Polearm.tempLeanShootSources);
                for (int i = 0; i < Verb_MeleeAttackDamage_Polearm.tempLeanShootSources.Count; i++)
                {
                    IntVec3 intVec = Verb_MeleeAttackDamage_Polearm.tempLeanShootSources[i];
                    if (this.CanHitFromCellIgnoringRange(intVec, targ, out dest))
                    {
                        resultingLine = new ShootLine(intVec, dest);
                        return(true);
                    }
                }
            }
            else
            {
                foreach (IntVec3 intVec2 in this.caster.OccupiedRect())
                {
                    if (this.CanHitFromCellIgnoringRange(intVec2, targ, out IntVec3 dest))
                    {
                        resultingLine = new ShootLine(intVec2, dest);
                        return(true);
                    }
                }
            }
            resultingLine = new ShootLine(root, targ.Cell);
            return(false);
        }
        public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine)
        {
            if (targ.HasThing && targ.Thing.Map != caster.Map)
            {
                resultingLine = default(ShootLine);
                return(false);
            }
            if (verbProps.range <= ShootTuning.MeleeRange) // If this verb has a MAX range up to melee range (NOT a MIN RANGE!)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(ReachabilityImmediate.CanReachImmediate(root, targ, caster.Map, PathEndMode.Touch, null));
            }
            CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect();
            float    num      = cellRect.ClosestDistSquaredTo(root);

            if (num > verbProps.range * verbProps.range || num < verbProps.minRange * verbProps.minRange)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(false);
            }
            //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile
            if (Projectile.projectile.flyOverhead)
            {
                resultingLine = new ShootLine(root, targ.Cell);
                return(true);
            }

            // First check current cell for early opt-out
            IntVec3 dest;
            var     shotSource = root.ToVector3Shifted();

            shotSource.y = ShotHeight;

            // Adjust for multi-tile turrets
            if (caster.def.building?.IsTurret ?? false)
            {
                shotSource = ShotSource;
            }

            if (CanHitFromCellIgnoringRange(shotSource, targ, out dest))
            {
                resultingLine = new ShootLine(root, dest);
                return(true);
            }

            // For pawns, calculate possible lean locations
            if (CasterIsPawn)
            {
                ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), caster.Map, tempLeanShootSources);
                foreach (var leanLoc in tempLeanShootSources.OrderBy(c => c.DistanceTo(targ.Cell)))
                {
                    var leanOffset = (leanLoc - root).ToVector3() * 0.51f;  //using exactly 0.5f makes it always round up, which causes issues if offset is negative, when adding leanOffset to shotSource. Setting to 0.51f to fix.
                    if (CanHitFromCellIgnoringRange(shotSource + leanOffset, targ, out dest))
                    {
                        resultingLine = new ShootLine(leanLoc, dest);
                        return(true);
                    }
                }
            }

            resultingLine = new ShootLine(root, targ.Cell);
            return(false);
        }