예제 #1
0
        /// <summary>
        /// Get all available targets ordered by weight
        /// </summary>
        /// <param name="rawTargets"></param>
        /// <param name="searcher"></param>
        /// <returns></returns>
        public static List <Pair <IAttackTarget, float> > GetAvailableShootingTargetsByScore(List <IAttackTarget> rawTargets, VehiclePawn searcher)
        {
            List <Pair <IAttackTarget, float> > availableShootingTargets = new List <Pair <IAttackTarget, float> >();
            List <float> tmpTargetScores     = new List <float>();
            List <bool>  tmpCanShootAtTarget = new List <bool>();

            if (rawTargets.Count == 0)
            {
                return(availableShootingTargets);
            }
            tmpTargetScores.Clear();
            tmpCanShootAtTarget.Clear();
            float         num          = 0f;
            IAttackTarget attackTarget = null;

            for (int i = 0; i < rawTargets.Count; i++)
            {
                tmpTargetScores.Add(float.MinValue);
                tmpCanShootAtTarget.Add(false);
                if (rawTargets[i] != searcher)
                {
                    bool flag = VehicleTurret.TryFindShootLineFromTo(searcher.Position, new LocalTargetInfo(rawTargets[i].Thing), out ShootLine shootLine);
                    tmpCanShootAtTarget[i] = flag;
                    if (flag)
                    {
                        float shootingTargetScore = GetShootingTargetScore(rawTargets[i], searcher);
                        tmpTargetScores[i] = shootingTargetScore;
                        if (attackTarget == null || shootingTargetScore > num)
                        {
                            attackTarget = rawTargets[i];
                            num          = shootingTargetScore;
                        }
                    }
                }
            }
            if (num < 1f)
            {
                if (attackTarget != null)
                {
                    availableShootingTargets.Add(new Pair <IAttackTarget, float>(attackTarget, 1f));
                }
            }
            else
            {
                float num2 = num - 30f;
                for (int j = 0; j < rawTargets.Count; j++)
                {
                    if (rawTargets[j] != searcher && tmpCanShootAtTarget[j])
                    {
                        float num3 = tmpTargetScores[j];
                        if (num3 >= num2)
                        {
                            float second = Mathf.InverseLerp(num - 30f, num, num3);
                            availableShootingTargets.Add(new Pair <IAttackTarget, float>(rawTargets[j], second));
                        }
                    }
                }
            }
            return(availableShootingTargets);
        }
예제 #2
0
        protected virtual Vector3 Target(VehicleTurret turret)
        {
            int     shots         = shotsFromTurret[turret];
            float   distFromStart = StrafeAreaDistance * shots / turret.MaxShotsCurrentFireMode;
            Vector3 target        = start.ToVector3Shifted().PointFromAngle(distFromStart, angle);

            Pair <float, float> turretLoc = RenderHelper.TurretDrawOffset(angle, turret.turretRenderLocation.x, turret.turretRenderLocation.y, out Pair <float, float> renderOffsets, 0, turret.attachedTo);

            return(new Vector3(target.x + turretLoc.First + renderOffsets.First, target.y + turret.drawLayer, target.z + turretLoc.Second + renderOffsets.Second));
        }
예제 #3
0
 public CannonUpgrade(CannonUpgrade reference, VehiclePawn parent) : base(reference, parent)
 {
     cannonUpgrades = reference.cannonUpgrades;
     foreach (KeyValuePair <VehicleTurret, VehicleRole> cu in cannonUpgrades)
     {
         VehicleTurret  newTurret = CompCannons.CreateTurret(parent, cu.Key);
         VehicleHandler handler   = new VehicleHandler(parent, cu.Value);
         cannonsUnlocked.Add(newTurret, handler);
     }
 }
예제 #4
0
 public override void StopTargeting()
 {
     if (actionWhenFinished != null)
     {
         Action action = actionWhenFinished;
         actionWhenFinished = null;
         action();
     }
     Cannon = null;
     action = null;
 }
예제 #5
0
 public void BeginTargeting(TargetingParameters targetParams, Action <LocalTargetInfo> action, VehicleTurret cannon, Action actionWhenFinished = null, Texture2D mouseAttachment = null)
 {
     this.action       = action;
     this.targetParams = targetParams;
     vehicle           = cannon.vehicle;
     Cannon            = cannon;
     Cannon.SetTarget(LocalTargetInfo.Invalid);
     this.actionWhenFinished = actionWhenFinished;
     this.mouseAttachment    = mouseAttachment;
     map = cannon.vehicle.Map;
 }
예제 #6
0
 public void Notify_TurretRecoil(VehicleTurret turret, float angle)
 {
     if (!turret.Recoils)
     {
         return;
     }
     targetRecoil  = turret.turretDef.recoil.distanceTotal;
     recoilStep    = turret.turretDef.recoil.distancePerTick;
     curRecoil     = 0;
     recoilingBack = true;
     Angle         = angle;
 }
예제 #7
0
        protected virtual Vector3 TurretLocation(VehicleTurret turret)
        {
            float locationRotation = 0f;

            if (turret.attachedTo != null)
            {
                locationRotation = turret.attachedTo.TurretRotation;
            }
            Vector3             calcPosition = DistanceAtMin;
            Pair <float, float> turretLoc    = RenderHelper.TurretDrawOffset(angle, turret.turretRenderLocation.x, turret.turretRenderLocation.y, out Pair <float, float> renderOffsets, locationRotation, turret.attachedTo);

            return(new Vector3(calcPosition.x + turretLoc.First + renderOffsets.First, calcPosition.y + turret.drawLayer, calcPosition.z + turretLoc.Second + renderOffsets.Second));
        }
예제 #8
0
 /// <summary>
 /// Find best attack target for VehicleTurret
 /// </summary>
 /// <seealso cref="BestAttackTarget(VehicleTurret, TargetScanFlags, Predicate{Thing}, float, float, IntVec3, float, bool, bool)"/>
 /// <param name="cannon"></param>
 /// <param name="restrictedAngle"></param>
 /// <param name="param"></param>
 public static LocalTargetInfo GetCannonTarget(this VehicleTurret cannon, float restrictedAngle = 0f, TargetingParameters param = null)
 {
     if (cannon.vehicle.CompCannons != null && cannon.vehicle.CompCannons.WeaponStatusOnline && cannon.vehicle.Faction != null)             //add fire at will option
     {
         TargetScanFlags targetScanFlags = TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable;
         Thing           thing           = (Thing)BestAttackTarget(cannon, targetScanFlags, null, 0f, 9999f, default(IntVec3), float.MaxValue, false, false);
         if (thing != null)
         {
             return(new LocalTargetInfo(thing));
         }
     }
     return(LocalTargetInfo.Invalid);
 }
예제 #9
0
 public void Notify_TurretRecoil(VehicleTurret turret, float angle)
 {
     if (turret.turretDef.vehicleRecoil is null)
     {
         return;
     }
     targetRecoil = turret.turretDef.vehicleRecoil.distanceTotal;
     recoilStep   = turret.turretDef.vehicleRecoil.distancePerTick;
     speedMultiplierPostRecoil = turret.turretDef.vehicleRecoil.speedMultiplierPostRecoil;
     curRecoil     = 0;
     recoilingBack = true;
     Angle         = angle;
 }
예제 #10
0
        protected virtual void FireTurret(VehicleTurret turret)
        {
            float   horizontalOffset = turret.turretDef.projectileShifting.NotNullAndAny() ? turret.turretDef.projectileShifting[turret.CurrentTurretFiring] : 0;
            Vector3 launchPos        = TurretLocation(turret) + new Vector3(horizontalOffset, 1f, turret.turretDef.projectileOffset);

            Vector3 targetPos = Target(turret);
            float   range     = Vector3.Distance(TurretLocation(turret), targetPos);
            IntVec3 target    = targetPos.ToIntVec3() + GenRadial.RadialPattern[Rand.Range(0, GenRadial.NumCellsInRadius(turret.CurrentFireMode.spreadRadius * (range / turret.turretDef.maxRange)))];

            if (turret.CurrentTurretFiring >= turret.turretDef.projectileShifting.Count)
            {
                turret.CurrentTurretFiring = 0;
            }

            ThingDef projectile;

            if (turret.turretDef.ammunition != null && !turret.turretDef.genericAmmo)
            {
                projectile = turret.loadedAmmo?.projectileWhenLoaded;
            }
            else
            {
                projectile = turret.turretDef.projectile;
            }
            try
            {
                float speedTicksPerTile = projectile.projectile.SpeedTilesPerTick;
                if (turret.turretDef.projectileSpeed > 0)
                {
                    speedTicksPerTile = turret.turretDef.projectileSpeed;
                }
                ProjectileSkyfaller projectile2 = ProjectileSkyfallerMaker.WrapProjectile(ProjectileSkyfallerDefOf.ProjectileSkyfaller,
                                                                                          projectile, this, launchPos, target.ToVector3Shifted(), speedTicksPerTile); //REDO - RANDOMIZE TARGETED CELLS
                GenSpawn.Spawn(projectile2, target.ClampInsideMap(Map), Map);
                if (turret.turretDef.ammunition != null)
                {
                    turret.ConsumeShellChambered();
                }
                if (turret.turretDef.cannonSound != null)
                {
                    turret.turretDef.cannonSound.PlayOneShot(new TargetInfo(Position, Map, false));
                }
                turret.PostTurretFire();
            }
            catch (Exception ex)
            {
                Log.Error($"Exception when firing Cannon: {turret.turretDef.LabelCap} on Pawn: {vehicle.LabelCap}. Exception: {ex.Message}");
            }
        }
예제 #11
0
 public void RemoveCannons(List <VehicleTurret> cannonList)
 {
     if (cannonList.NullOrEmpty())
     {
         return;
     }
     foreach (VehicleTurret cannon in cannonList)
     {
         VehicleTurret resultingHandler = cannons.FirstOrDefault(c => c.key == cannon.key);
         if (resultingHandler is null)
         {
             Log.Error($"Unable to locate {cannon.key} in cannonList for removal. Is Key missing on upgraded cannon?");
         }
         cannons.Remove(resultingHandler);
     }
 }
예제 #12
0
        public VehicleTurret(VehiclePawn vehicle, VehicleTurret reference)
        {
            this.vehicle = vehicle;

            uniqueID  = Find.UniqueIDsManager.GetNextThingID();
            turretDef = reference.turretDef;

            turretRenderOffset   = reference.turretRenderOffset;
            turretRenderLocation = reference.turretRenderLocation;
            defaultAngleRotated  = reference.defaultAngleRotated;

            aimPieOffset    = reference.aimPieOffset;
            angleRestricted = reference.angleRestricted;

            drawLayer = reference.drawLayer;

            gizmoLabel = reference.gizmoLabel;

            key       = reference.key;
            parentKey = reference.parentKey;
            groupKey  = reference.groupKey;

            targetPersists  = reference.targetPersists;
            autoTargeting   = reference.autoTargeting;
            manualTargeting = reference.manualTargeting;

            currentFireMode    = 0;
            currentFireIcon    = OverheatIcons.FirstOrDefault();
            ticksSinceLastShot = 0;

            childCannons = new List <VehicleTurret>();
            if (!string.IsNullOrEmpty(parentKey))
            {
                foreach (VehicleTurret cannon in vehicle.CompCannons.Cannons.Where(c => c.key == parentKey))
                {
                    attachedTo = cannon;
                    cannon.childCannons.Add(this);
                }
            }

            ResolveCannonGraphics(vehicle);
            rTracker = new Turret_RecoilTracker(this);

            restrictedTheta = (int)Math.Abs(angleRestricted.x - (angleRestricted.y + 360)).ClampAngle();

            ResetCannonAngle();
        }
예제 #13
0
 public void AddCannons(List <VehicleTurret> cannonList)
 {
     if (cannonList.NullOrEmpty())
     {
         return;
     }
     foreach (VehicleTurret cannon in cannonList)
     {
         VehicleTurret newTurret = CreateTurret(Vehicle, cannon);
         if (cannons.NotNullAndAny(x => x.turretRenderLocation == newTurret.turretRenderLocation && newTurret.attachedTo != x && x.attachedTo != newTurret))
         {
             cannons.FindAll(x => x.turretRenderLocation == newTurret.turretRenderLocation).ForEach(y => y.TryRemoveShell());
             cannons.RemoveAll(x => x.turretRenderLocation == newTurret.turretRenderLocation);
         }
         cannons.Add(newTurret);
     }
 }
예제 #14
0
 protected virtual void TurretTick()
 {
     if (!turrets.NullOrEmpty())
     {
         for (int i = 0; i < turrets.Count; i++)
         {
             CompCannons.TurretData turretData = turrets[i];
             VehicleTurret          turret     = turretData.turret;
             if (!turret.HasAmmo && !DebugSettings.godMode)
             {
                 turrets.Remove(turretData);
                 shotsFired = turrets.NullOrEmpty();
                 continue;
             }
             if (turret.OnCooldown)
             {
                 turret.SetTarget(LocalTargetInfo.Invalid);
                 turrets.Remove(turretData);
                 shotsFired = turrets.NullOrEmpty();
                 continue;
             }
             turrets[i].turret.AlignToTargetRestricted();
             if (turrets[i].ticksTillShot <= 0)
             {
                 FireTurret(turret);
                 int shotsIncrement = shotsFromTurret[turret] + 1;
                 shotsFromTurret[turret] = shotsIncrement;
                 turret.CurrentTurretFiring++;
                 turretData.shots--;
                 turretData.ticksTillShot = turret.TicksPerShot;
                 if (turret.OnCooldown || turretData.shots == 0 || (turret.turretDef.ammunition != null && turret.shellCount <= 0))
                 {
                     turret.SetTarget(LocalTargetInfo.Invalid);
                     turrets.RemoveAll(t => t.turret == turret);
                     shotsFired = turrets.NullOrEmpty();
                     continue;
                 }
             }
             else
             {
                 turretData.ticksTillShot--;
             }
             turrets[i] = turretData;
         }
     }
 }
예제 #15
0
        public static bool TargetMeetsRequirements(VehicleTurret cannon, LocalTargetInfo obj)
        {
            float distance = (cannon.TurretLocation.ToIntVec3() - obj.Cell).LengthHorizontal;
            bool  los      = false;

            if (obj.HasThing)
            {
                if (!obj.Thing.Spawned || obj.Thing.Destroyed)
                {
                    return(false);
                }
                los = GenSight.LineOfSightToThing(cannon.TurretLocation.ToIntVec3(), obj.Thing, cannon.vehicle.Map);
            }
            else
            {
                los = GenSight.LineOfSight(cannon.TurretLocation.ToIntVec3(), obj.Cell, cannon.vehicle.Map);
            }
            bool result = (distance >= cannon.MinRange && (distance < cannon.MaxRange || cannon.MaxRange <= -1)) &&
                          cannon.AngleBetween(obj.CenterVector3) && ((cannon.loadedAmmo?.projectileWhenLoaded?.projectile?.flyOverhead ?? false) || los);

            return(result);
        }
예제 #16
0
 public Turret_RecoilTracker(VehicleTurret turret)
 {
     this.turret = turret;
 }
예제 #17
0
        /// <summary>
        /// Best attack target for VehicleTurret
        /// </summary>
        /// <param name="cannon"></param>
        /// <param name="flags"></param>
        /// <param name="validator"></param>
        /// <param name="minDist"></param>
        /// <param name="maxDist"></param>
        /// <param name="locus"></param>
        /// <param name="maxTravelRadiusFromLocus"></param>
        /// <param name="canBash"></param>
        /// <param name="canTakeTargetsCloserThanEffectiveMinRange"></param>
        /// <returns></returns>
        public static IAttackTarget BestAttackTarget(VehicleTurret cannon, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = 3.4028235E+38f, bool canBash = false, bool canTakeTargetsCloserThanEffectiveMinRange = true)
        {
            VehiclePawn searcherPawn = cannon.vehicle;

            float minDistSquared              = minDist * minDist;
            float num                         = maxTravelRadiusFromLocus + cannon.MaxRange;
            float maxLocusDistSquared         = num * num;
            Func <IntVec3, bool> losValidator = null;

            if ((flags & TargetScanFlags.LOSBlockableByGas) != TargetScanFlags.None)
            {
                losValidator = delegate(IntVec3 vec3)
                {
                    Gas gas = vec3.GetGas(searcherPawn.Map);
                    return(gas == null || !gas.def.gas.blockTurretTracking);
                };
            }
            Predicate <IAttackTarget> innerValidator = delegate(IAttackTarget t)
            {
                Thing thing = t.Thing;
                if (t == searcherPawn)
                {
                    return(false);
                }
                if (minDistSquared > 0f && (float)(searcherPawn.Position - thing.Position).LengthHorizontalSquared < minDistSquared)
                {
                    return(false);
                }
                if (!canTakeTargetsCloserThanEffectiveMinRange)
                {
                    float num2 = cannon.MinRange;
                    if (num2 > 0f && (float)(cannon.vehicle.Position - thing.Position).LengthHorizontalSquared < num2 * num2)
                    {
                        return(false);
                    }
                }
                if (maxTravelRadiusFromLocus < 9999f && (thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared)
                {
                    return(false);
                }
                if (!searcherPawn.HostileTo(thing))
                {
                    return(false);
                }
                if (validator != null && !validator(thing))
                {
                    return(false);
                }
                if ((flags & TargetScanFlags.NeedLOSToAll) != TargetScanFlags.None)
                {
                    if (losValidator != null && (!losValidator(searcherPawn.Position) || !losValidator(thing.Position)))
                    {
                        return(false);
                    }
                    if (!searcherPawn.CanSee(thing, losValidator))
                    {
                        if (t is Pawn)
                        {
                            if ((flags & TargetScanFlags.NeedLOSToPawns) != TargetScanFlags.None)
                            {
                                return(false);
                            }
                        }
                        else if ((flags & TargetScanFlags.NeedLOSToNonPawns) != TargetScanFlags.None)
                        {
                            return(false);
                        }
                    }
                }
                if (((flags & TargetScanFlags.NeedThreat) != TargetScanFlags.None || (flags & TargetScanFlags.NeedAutoTargetable) != TargetScanFlags.None) && t.ThreatDisabled(searcherPawn))
                {
                    return(false);
                }
                if ((flags & TargetScanFlags.NeedAutoTargetable) != TargetScanFlags.None && !AttackTargetFinder.IsAutoTargetable(t))
                {
                    return(false);
                }
                if ((flags & TargetScanFlags.NeedActiveThreat) != TargetScanFlags.None && !GenHostility.IsActiveThreatTo(t, searcherPawn.Faction))
                {
                    return(false);
                }
                Pawn pawn = t as Pawn;
                if ((flags & TargetScanFlags.NeedNonBurning) != TargetScanFlags.None && thing.IsBurning())
                {
                    return(false);
                }

                if (thing.def.size.x == 1 && thing.def.size.z == 1)
                {
                    if (thing.Position.Fogged(thing.Map))
                    {
                        return(false);
                    }
                }
                else
                {
                    bool flag2 = false;
                    using (CellRect.Enumerator enumerator = thing.OccupiedRect().GetEnumerator())
                    {
                        while (enumerator.MoveNext())
                        {
                            if (!enumerator.Current.Fogged(thing.Map))
                            {
                                flag2 = true;
                                break;
                            }
                        }
                    }
                    if (!flag2)
                    {
                        return(false);
                    }
                }
                return(true);
            };

            List <IAttackTarget> tmpTargets = new List <IAttackTarget>();

            tmpTargets.AddRange(searcherPawn.Map.attackTargetsCache.GetPotentialTargetsFor(searcherPawn));

            bool flag = false;

            for (int i = 0; i < tmpTargets.Count; i++)
            {
                IAttackTarget attackTarget = tmpTargets[i];
                if (attackTarget.Thing.Position.InHorDistOf(searcherPawn.Position, maxDist) && innerValidator(attackTarget) && VehicleTurret.TryFindShootLineFromTo(searcherPawn.Position, new LocalTargetInfo(attackTarget.Thing), out ShootLine resultingLine))
                {
                    flag = true;
                    break;
                }
            }
            IAttackTarget result;

            if (flag)
            {
                tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherPawn.Position, maxDist) || !innerValidator(x));
                result = GetRandomShootingTargetByScore(tmpTargets, searcherPawn);
            }
            else
            {
                Predicate <Thing> validator2;
                if ((flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) != TargetScanFlags.None && (flags & TargetScanFlags.NeedReachable) == TargetScanFlags.None)
                {
                    validator2 = ((Thing t) => innerValidator((IAttackTarget)t) && VehicleTurret.TryFindShootLineFromTo(searcherPawn.Position, new LocalTargetInfo(t), out ShootLine resultingLine));
                }
                else
                {
                    validator2 = ((Thing t) => innerValidator((IAttackTarget)t));
                }
                result = (IAttackTarget)GenClosest.ClosestThing_Global(searcherPawn.Position, tmpTargets, maxDist, validator2, null);
            }
            tmpTargets.Clear();
            return(result);
        }
예제 #18
0
 /// <summary>
 /// Calculate VehicleTurret draw offset
 /// </summary>
 /// <param name="vehicle"></param>
 /// <param name="xOffset"></param>
 /// <param name="yOffset"></param>
 /// <param name="rotationOffset"></param>
 /// <param name="turretRotation"></param>
 /// <param name="attachedTo"></param>
 public static Pair <float, float> TurretDrawOffset(float angle, float xOffset, float yOffset, out Pair <float, float> rotationOffset, float turretRotation = 0, VehicleTurret attachedTo = null)
 {
     rotationOffset = new Pair <float, float>(0, 0);
     if (attachedTo != null)
     {
         return(Ext_Math.RotatePointClockwise(attachedTo.turretRenderLocation.x + xOffset, attachedTo.turretRenderLocation.y + yOffset, turretRotation));
     }
     return(Ext_Math.RotatePointClockwise(xOffset, yOffset, angle));
 }
예제 #19
0
        /// <summary>
        /// Calculate VehicleTurret draw offset given <paramref name="rot"/>
        /// </summary>
        /// <param name="rot"></param>
        /// <param name="xOffset"></param>
        /// <param name="yOffset"></param>
        /// <param name="rotationOffset"></param>
        /// <param name="turretRotation"></param>
        /// <param name="attachedTo"></param>
        /// <returns></returns>
        public static Pair <float, float> ShipDrawOffset(Rot8 rot, float xOffset, float yOffset, out Pair <float, float> rotationOffset, float turretRotation = 0, VehicleTurret attachedTo = null)
        {
            rotationOffset = new Pair <float, float>(0, 0);
            if (attachedTo != null)
            {
                return(Ext_Math.RotatePointClockwise(attachedTo.turretRenderLocation.x + xOffset, attachedTo.turretRenderLocation.y + yOffset, turretRotation));
            }

            return(rot.AsInt switch
            {
                //North
                0 => new Pair <float, float>(xOffset, yOffset),
                //East
                1 => new Pair <float, float>(yOffset, -xOffset),
                //South
                2 => new Pair <float, float>(-xOffset, -yOffset),
                //West
                3 => new Pair <float, float>(-yOffset, xOffset),
                //NorthEast
                4 => Ext_Math.RotatePointClockwise(yOffset, -xOffset, 45f),
                //SouthEast
                5 => Ext_Math.RotatePointCounterClockwise(yOffset, -xOffset, 45f),
                //SouthWest
                6 => Ext_Math.RotatePointClockwise(-yOffset, xOffset, 45f),
                //NorthWest
                7 => Ext_Math.RotatePointCounterClockwise(-yOffset, xOffset, 45f),
                //Default
                _ => throw new ArgumentOutOfRangeException("VehicleRotation is not within bounds. RotationInt must be between 0 and 7 for each lateral, longitudinal, and diagonal direction.")
            });