Example #1
0
        public MissileCA(MissileCAInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;

            pos            = args.Source;
            hFacing        = args.Facing.Facing;
            gravity        = new WVec(0, 0, -info.Gravity);
            targetPosition = args.PassiveTarget;
            var limit = info.RangeLimit != WDist.Zero ? info.RangeLimit : args.Weapon.Range;

            rangeLimit     = new WDist(Util.ApplyPercentageModifiers(limit.Length, args.RangeModifiers));
            minLaunchSpeed = info.MinimumLaunchSpeed.Length > -1 ? info.MinimumLaunchSpeed.Length : info.Speed.Length;
            maxLaunchSpeed = info.MaximumLaunchSpeed.Length > -1 ? info.MaximumLaunchSpeed.Length : info.Speed.Length;
            maxSpeed       = info.Speed.Length;
            minLaunchAngle = info.MinimumLaunchAngle;
            maxLaunchAngle = info.MaximumLaunchAngle;

            var world = args.SourceActor.World;

            if (world.SharedRandom.Next(100) <= info.LockOnProbability)
            {
                lockOn = true;
            }

            var inaccuracy = lockOn && info.LockOnInaccuracy.Length > -1 ? info.LockOnInaccuracy.Length : info.Inaccuracy.Length;

            if (inaccuracy > 0)
            {
                var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args);
                offset = WVec.FromPDF(world.SharedRandom, 2) * maxInaccuracyOffset / 1024;
            }

            DetermineLaunchSpeedAndAngle(world, out speed, out vFacing);

            velocity = new WVec(0, -speed, 0)
                       .Rotate(new WRot(WAngle.FromFacing(vFacing), WAngle.Zero, WAngle.Zero))
                       .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(hFacing)));

            if (!string.IsNullOrEmpty(info.Image))
            {
                anim = new Animation(world, info.Image, () => renderFacing);
                anim.PlayRepeating(info.Sequences.Random(world.SharedRandom));
            }

            if (info.ContrailLength > 0)
            {
                var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
                contrail = new ContrailRenderable(world, color, info.ContrailWidth, info.ContrailLength, info.ContrailDelay, info.ContrailZOffset);
            }

            trailPalette = info.TrailPalette;
            if (info.TrailUsePlayerPalette)
            {
                trailPalette += args.SourceActor.Owner.InternalName;
            }
        }
Example #2
0
        WVec HomingTick(World world, WVec tarDistVec, int relTarHorDist)
        {
            int predClfHgt  = 0;
            int predClfDist = 0;
            int lastHtChg   = 0;
            int lastHt      = 0;

            if (info.TerrainHeightAware)
            {
                InclineLookahead(world, relTarHorDist, out predClfHgt, out predClfDist, out lastHtChg, out lastHt);
            }

            // Height difference between the incline height and missile height
            var diffClfMslHgt = predClfHgt - pos.Z;

            // Get underestimate of distance from target in next tick
            var nxtRelTarHorDist = (relTarHorDist - speed - info.Acceleration.Length).Clamp(0, relTarHorDist);

            // Target height relative to the missile
            var relTarHgt = tarDistVec.Z;

            // Compute which direction the projectile should be facing
            var velVec         = tarDistVec + predVel;
            var desiredHFacing = velVec.HorizontalLengthSquared != 0 ? velVec.Yaw.Facing : hFacing;

            var delta = Util.NormalizeFacing(hFacing - desiredHFacing);

            if (allowPassBy && delta > 64 && delta < 192)
            {
                desiredHFacing = (desiredHFacing + 128) & 0xFF;
                targetPassedBy = true;
            }
            else
            {
                targetPassedBy = false;
            }

            var desiredVFacing = HomingInnerTick(predClfDist, diffClfMslHgt, relTarHorDist, lastHtChg, lastHt,
                                                 nxtRelTarHorDist, relTarHgt, vFacing, targetPassedBy);

            // The target has been passed by
            if (tarDistVec.HorizontalLength < speed * WAngle.FromFacing(vFacing).Cos() / 1024)
            {
                targetPassedBy = true;
            }

            // Check whether the homing mechanism is jammed
            var jammed = info.Jammable && world.ActorsWithTrait <JamsMissiles>().Any(JammedBy);

            if (jammed)
            {
                desiredHFacing = hFacing + world.SharedRandom.Next(-info.JammedDiversionRange, info.JammedDiversionRange + 1);
                desiredVFacing = vFacing + world.SharedRandom.Next(-info.JammedDiversionRange, info.JammedDiversionRange + 1);
            }
            else if (!args.GuidedTarget.IsValidFor(args.SourceActor))
            {
                desiredHFacing = hFacing;
            }

            // Compute new direction the projectile will be facing
            hFacing = Util.TickFacing(hFacing, desiredHFacing, info.HorizontalRateOfTurn.Facing);
            vFacing = Util.TickFacing(vFacing, desiredVFacing, info.VerticalRateOfTurn.Facing);

            // Compute the projectile's guided displacement
            return(new WVec(0, -1024 * speed, 0)
                   .Rotate(new WRot(WAngle.FromFacing(vFacing), WAngle.Zero, WAngle.Zero))
                   .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(hFacing)))
                   / 1024);
        }