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; } }
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); }