internal static bool CanShootTargetObb(Weapon weapon, MyEntity entity, Vector3D targetLinVel, Vector3D targetAccel) { var prediction = weapon.System.Values.HardPoint.AimLeadingPrediction; var trackingWeapon = weapon.TurretMode ? weapon : weapon.Comp.TrackingWeapon; Vector3D targetPos; if (Vector3D.IsZero(targetLinVel, 5E-03)) { targetLinVel = Vector3.Zero; } if (Vector3D.IsZero(targetAccel, 5E-03)) { targetAccel = Vector3.Zero; } var rotMatrix = Quaternion.CreateFromRotationMatrix(entity.PositionComp.WorldMatrix); var obb = new MyOrientedBoundingBoxD(entity.PositionComp.WorldAABB.Center, entity.PositionComp.LocalAABB.HalfExtents, rotMatrix); if (prediction != Prediction.Off && !weapon.ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon && weapon.ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed > 0) { targetPos = weapon.GetPredictedTargetPosition(obb.Center, targetLinVel, targetAccel); } else { targetPos = obb.Center; } obb.Center = targetPos; weapon.TargetBox = obb; var maxRangeSqr = obb.HalfExtent.AbsMax() + weapon.MaxTargetDistance; maxRangeSqr *= maxRangeSqr; double rangeToTarget; Vector3D.DistanceSquared(ref targetPos, ref weapon.MyPivotPos, out rangeToTarget); bool canTrack = false; if (rangeToTarget <= maxRangeSqr) { var targetDir = targetPos - weapon.MyPivotPos; if (weapon == trackingWeapon) { double checkAzimuth; double checkElevation; MathFuncs.GetRotationAngles(ref targetDir, ref weapon.WeaponConstMatrix, out checkAzimuth, out checkElevation); var azConstraint = Math.Min(weapon.MaxAzimuthRadians, Math.Max(weapon.MinAzimuthRadians, checkAzimuth)); var elConstraint = Math.Min(weapon.MaxElevationRadians, Math.Max(weapon.MinElevationRadians, checkElevation)); Vector3D constraintVector; Vector3D.CreateFromAzimuthAndElevation(azConstraint, elConstraint, out constraintVector); constraintVector = Vector3D.Rotate(constraintVector, weapon.WeaponConstMatrix); var testRay = new RayD(weapon.MyPivotPos, constraintVector); if (obb.Intersects(ref testRay) != null) { canTrack = true; } if (weapon.Comp.Debug) { weapon.LimitLine = new LineD(weapon.MyPivotPos, weapon.MyPivotPos + (constraintVector * weapon.ActiveAmmoDef.AmmoDef.Const.MaxTrajectory)); } } else { canTrack = MathFuncs.IsDotProductWithinTolerance(ref weapon.MyPivotDir, ref targetDir, weapon.AimingTolerance); } } return(canTrack); }
internal static bool CanShootTarget(Weapon weapon, Vector3D targetCenter, Vector3D targetLinVel, Vector3D targetAccel, out Vector3D targetPos) { var prediction = weapon.System.Values.HardPoint.AimLeadingPrediction; var trackingWeapon = weapon.TurretMode ? weapon : weapon.Comp.TrackingWeapon; if (Vector3D.IsZero(targetLinVel, 5E-03)) { targetLinVel = Vector3.Zero; } if (Vector3D.IsZero(targetAccel, 5E-03)) { targetAccel = Vector3.Zero; } if (prediction != Prediction.Off && !weapon.ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon && weapon.ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed > 0) { targetPos = weapon.GetPredictedTargetPosition(targetCenter, targetLinVel, targetAccel); } else { targetPos = targetCenter; } var targetDir = targetPos - weapon.MyPivotPos; double rangeToTarget; Vector3D.DistanceSquared(ref targetPos, ref weapon.MyPivotPos, out rangeToTarget); var inRange = rangeToTarget <= weapon.MaxTargetDistanceSqr; bool canTrack; if (weapon == trackingWeapon) { Vector3D currentVector; Vector3D.CreateFromAzimuthAndElevation(weapon.Azimuth, weapon.Elevation, out currentVector); currentVector = Vector3D.Rotate(currentVector, weapon.WeaponConstMatrix); var up = weapon.MyPivotUp; var left = Vector3D.Cross(up, currentVector); if (!Vector3D.IsUnit(ref left) && !Vector3D.IsZero(left)) { left.Normalize(); } var forward = Vector3D.Cross(left, up); var matrix = new MatrixD { Forward = forward, Left = left, Up = up, }; double desiredAzimuth; double desiredElevation; MathFuncs.GetRotationAngles(ref targetDir, ref matrix, out desiredAzimuth, out desiredElevation); var azConstraint = Math.Min(weapon.MaxAzimuthRadians, Math.Max(weapon.MinAzimuthRadians, desiredAzimuth)); var elConstraint = Math.Min(weapon.MaxElevationRadians, Math.Max(weapon.MinElevationRadians, desiredElevation)); var azConstrained = Math.Abs(elConstraint - desiredElevation) > 0.0000001; var elConstrained = Math.Abs(azConstraint - desiredAzimuth) > 0.0000001; canTrack = !azConstrained && !elConstrained; } else { canTrack = MathFuncs.IsDotProductWithinTolerance(ref weapon.MyPivotDir, ref targetDir, weapon.AimingTolerance); } return((inRange && canTrack) || weapon.Comp.TrackReticle); }
internal static bool TrackingTarget(Weapon weapon, Target target) { Vector3D targetPos; Vector3 targetLinVel = Vector3.Zero; Vector3 targetAccel = Vector3.Zero; var system = weapon.System; Vector3D targetCenter; var rayCheckTest = !weapon.Comp.Session.IsClient && weapon.Comp.State.Value.CurrentPlayerControl.ControlType == ControlType.None && weapon.ActiveAmmoDef.AmmoDef.Trajectory.Guidance == GuidanceType.None && (!weapon.Casting && weapon.Comp.Session.Tick - weapon.Comp.LastRayCastTick > 29 || weapon.System.Values.HardPoint.Other.MuzzleCheck && weapon.Comp.Session.Tick - weapon.LastMuzzleCheck > 29); if (rayCheckTest && !weapon.RayCheckTest()) { return(false); } if (weapon.Comp.TrackReticle) { targetCenter = weapon.Comp.Ai.DummyTarget.Position; } else if (target.IsProjectile) { if (target.Projectile == null) { Log.Line($"TrackingTarget: is projectile and it is null"); targetCenter = Vector3D.Zero; } else { targetCenter = target.Projectile.Position; } } else if (!target.IsFakeTarget) { if (target.Entity == null) { Log.Line($"TrackingTarget: is entity and it is null"); targetCenter = Vector3D.Zero; } else { targetCenter = target.Entity.PositionComp.WorldAABB.Center; } } else { targetCenter = Vector3D.Zero; } var needsPrediction = weapon.System.Prediction != Prediction.Off && (!weapon.ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon && weapon.ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed > 0); if (needsPrediction) { if (weapon.Comp.TrackReticle) { targetLinVel = weapon.Comp.Ai.DummyTarget.LinearVelocity; targetAccel = weapon.Comp.Ai.DummyTarget.Acceleration; } else { var topMostEnt = target.Entity?.GetTopMostParent(); if (target.Projectile != null) { targetLinVel = target.Projectile.Velocity; targetAccel = target.Projectile.AccelVelocity; } else if (topMostEnt?.Physics != null) { targetLinVel = topMostEnt.Physics.LinearVelocity; targetAccel = topMostEnt.Physics.LinearAcceleration; } } if (Vector3D.IsZero(targetLinVel, 5E-03)) { targetLinVel = Vector3.Zero; } if (Vector3D.IsZero(targetAccel, 5E-03)) { targetAccel = Vector3.Zero; } targetPos = weapon.GetPredictedTargetPosition(targetCenter, targetLinVel, targetAccel); } else { targetPos = targetCenter; } weapon.Target.TargetPos = targetPos; double rangeToTargetSqr; Vector3D.DistanceSquared(ref targetPos, ref weapon.MyPivotPos, out rangeToTargetSqr); var targetDir = targetPos - weapon.MyPivotPos; var locked = true; if (weapon.Comp.TrackReticle || rangeToTargetSqr <= weapon.MaxTargetDistanceSqr) { var maxAzimuthStep = system.AzStep; var maxElevationStep = system.ElStep; Vector3D currentVector; Vector3D.CreateFromAzimuthAndElevation(weapon.Azimuth, weapon.Elevation, out currentVector); currentVector = Vector3D.Rotate(currentVector, weapon.WeaponConstMatrix); var up = weapon.MyPivotUp; var left = Vector3D.Cross(up, currentVector); if (!Vector3D.IsUnit(ref left) && !Vector3D.IsZero(left)) { left.Normalize(); } var forward = Vector3D.Cross(left, up); var constraintMatrix = new MatrixD { Forward = forward, Left = left, Up = up, }; double desiredAzimuth; double desiredElevation; MathFuncs.GetRotationAngles(ref targetDir, ref constraintMatrix, out desiredAzimuth, out desiredElevation); var azConstraint = Math.Min(weapon.MaxAzimuthRadians, Math.Max(weapon.MinAzimuthRadians, desiredAzimuth)); var elConstraint = Math.Min(weapon.MaxElevationRadians, Math.Max(weapon.MinElevationRadians, desiredElevation)); var elConstrained = Math.Abs(elConstraint - desiredElevation) > 0.0000001; var azConstrained = Math.Abs(azConstraint - desiredAzimuth) > 0.0000001; weapon.Target.IsTracking = !azConstrained && !elConstrained; if (weapon.Target.IsTracking && weapon.Comp.State.Value.CurrentPlayerControl.ControlType != ControlType.Camera && !weapon.Comp.ResettingSubparts) { var oldAz = weapon.Azimuth; var oldEl = weapon.Elevation; var epsilon = target.IsProjectile ? 1E-06d : rangeToTargetSqr <= 640000 ? 1E-03d : rangeToTargetSqr <= 3240000 ? 1E-04d : 1E-05d; var az = weapon.Azimuth + MathHelperD.Clamp(desiredAzimuth, -maxAzimuthStep, maxAzimuthStep); var el = weapon.Elevation + MathHelperD.Clamp(desiredElevation - weapon.Elevation, -maxElevationStep, maxElevationStep); var azDiff = oldAz - az; var elDiff = oldEl - el; var azLocked = MyUtils.IsZero(azDiff, (float)epsilon); var elLocked = MyUtils.IsZero(elDiff, (float)epsilon); locked = azLocked && elLocked; var aim = !azLocked || !elLocked; if (aim) { if (!azLocked) { weapon.Azimuth = az; } if (!elLocked) { weapon.Elevation = el; } weapon.IsHome = false; weapon.AimBarrel(azDiff, elDiff, !azLocked, !elLocked); } } } else { weapon.Target.IsTracking = false; } if (weapon.Comp.State.Value.CurrentPlayerControl.ControlType == ControlType.Camera) { return(weapon.Target.IsTracking); } var isAligned = false; if (weapon.Target.IsTracking) { isAligned = locked || MathFuncs.IsDotProductWithinTolerance(ref weapon.MyPivotDir, ref targetDir, weapon.AimingTolerance); } var wasAligned = weapon.Target.IsAligned; weapon.Target.IsAligned = isAligned; var alignedChange = wasAligned != isAligned; if (alignedChange && isAligned) { if (weapon.System.DesignatorWeapon) { for (int i = 0; i < weapon.Comp.Platform.Weapons.Length; i++) { var w = weapon.Comp.Platform.Weapons[i]; w.Target.StateChange(false, Target.States.Expired); w.Target.CheckTick -= 240; } } } else if (alignedChange && !weapon.System.DelayCeaseFire) { weapon.StopShooting(); } weapon.Target.TargetLock = weapon.Target.IsTracking && weapon.Target.IsAligned; return(weapon.Target.IsTracking); }
internal static void LeadTarget(Weapon weapon, MyEntity target, out Vector3D targetPos, out bool couldHit, out bool willHit) { var vel = target.Physics.LinearVelocity; var accel = target.Physics.LinearAcceleration; var trackingWeapon = weapon.TurretMode || weapon.Comp.TrackingWeapon == null ? weapon : weapon.Comp.TrackingWeapon; var box = target.PositionComp.LocalAABB; var obb = new MyOrientedBoundingBoxD(box, target.PositionComp.WorldMatrixRef); var validEstimate = true; var advancedMode = weapon.ActiveAmmoDef.AmmoDef.Trajectory.AccelPerSec > 0 || weapon.Comp.Ai.InPlanetGravity && weapon.ActiveAmmoDef.AmmoDef.Const.FeelsGravity; if (!weapon.ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon && weapon.ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed > 0) { targetPos = TrajectoryEstimation(weapon, obb.Center, vel, accel, out validEstimate, true, advancedMode); } else { targetPos = obb.Center; } obb.Center = targetPos; weapon.TargetBox = obb; var obbAbsMax = obb.HalfExtent.AbsMax(); var maxRangeSqr = obbAbsMax + weapon.MaxTargetDistance; var minRangeSqr = obbAbsMax + weapon.MinTargetDistance; maxRangeSqr *= maxRangeSqr; minRangeSqr *= minRangeSqr; double rangeToTarget; Vector3D.DistanceSquared(ref targetPos, ref weapon.MyPivotPos, out rangeToTarget); couldHit = validEstimate && rangeToTarget <= maxRangeSqr && rangeToTarget >= minRangeSqr; bool canTrack = false; if (validEstimate && rangeToTarget <= maxRangeSqr && rangeToTarget >= minRangeSqr) { var targetDir = targetPos - weapon.MyPivotPos; if (weapon == trackingWeapon) { double checkAzimuth; double checkElevation; MathFuncs.GetRotationAngles(ref targetDir, ref weapon.WeaponConstMatrix, out checkAzimuth, out checkElevation); var azConstraint = Math.Min(weapon.MaxAzToleranceRadians, Math.Max(weapon.MinAzToleranceRadians, checkAzimuth)); var elConstraint = Math.Min(weapon.MaxElToleranceRadians, Math.Max(weapon.MinElToleranceRadians, checkElevation)); Vector3D constraintVector; Vector3D.CreateFromAzimuthAndElevation(azConstraint, elConstraint, out constraintVector); Vector3D.Rotate(ref constraintVector, ref weapon.WeaponConstMatrix, out constraintVector); var testRay = new RayD(ref weapon.MyPivotPos, ref constraintVector); if (obb.Intersects(ref testRay) != null) { canTrack = true; } if (weapon.Comp.Debug) { weapon.LimitLine = new LineD(weapon.MyPivotPos, weapon.MyPivotPos + (constraintVector * weapon.ActiveAmmoDef.AmmoDef.Const.MaxTrajectory)); } } else { canTrack = MathFuncs.IsDotProductWithinTolerance(ref weapon.MyPivotFwd, ref targetDir, weapon.AimingTolerance); } } willHit = canTrack; }