Exemple #1
0
 public bool InterceptTarget(DetectedUnit targetDet)
 {
     if (targetDet != null && !targetDet.IsMarkedForDeletion)
     {
         TargetDetectedUnit = targetDet;
         if(targetDet.RefersToUnit != null)
         {
             TargetUnitClassId = targetDet.RefersToUnit.UnitClass.Id;
         }
         MovementOrder = null;
         //var wp = new Waypoint(targetDet);
         //if (MovementOrder == null)
         //{
         //    MovementOrder = new MovementOrder(wp);
         //}
         //else
         //{
         //    MovementOrder.ClearAllWaypoints();
         //    //MovementOrder.AddWaypoint(wp);
         //}
         ReCalculateEta();
         SetDirty(GameConstants.DirtyStatus.UnitChanged);
         GameManager.Instance.Log.LogDebug(
             string.Format("MissileUnit->InterceptTarget. Missile {0} set to intercept target {1}", ToShortString(), targetDet));
         return true;
     }
     return false;
 }
Exemple #2
0
 public void AddUnit(DetectedUnit detectedUnit)
 {
     if (!DetectedUnits.Exists(u => u.Id == detectedUnit.Id))
     {
         DetectedUnits.Add(detectedUnit);
         detectedUnit.DetectedGroupId = this.Id;
         SetDirty(GameConstants.DirtyStatus.UnitChanged);
     }
 }
Exemple #3
0
        public List <EngagementStatus> GetAllWeaponEngagementStatuses(string weaponClassId,
                                                                      DetectedUnit detectedUnit, bool primaryWeaponOnly)
        {
            var statuses       = _units.Select(u => u.GetBestAvailableWeapon(weaponClassId, detectedUnit, primaryWeaponOnly)).Where(status => status != null).ToList();
            var statusesSorted = from s in statuses
                                 orderby s.Score descending
                                 select s;

            return(statusesSorted.ToList());
        }
Exemple #4
0
        public bool RemoveUnit(DetectedUnit detectedUnit)
        {
            bool result = DetectedUnits.Remove(detectedUnit);

            if (result)
            {
                detectedUnit.DetectedGroupId = string.Empty;
                SetDirty(GameConstants.DirtyStatus.UnitChanged);
            }
            return(result);
        }
Exemple #5
0
        public override bool AttemptDetectUnit(BaseUnit unit, double distanceM)
        {
            // CZ etc: http://www.fas.org/man/dod-101/navy/docs/es310/SNR_PROP/snr_prop.htm
            //calculate blind zone:
            if (!IsAbleToDetectUnit(unit, distanceM))
            {
                return(false);
            }
            double bearingDegSensor   = GetCurrentSensorBearingDeg();
            double bearingDegToTarget = MapHelper.CalculateCombinedBearingDeg(bearingDegSensor,
                                                                              MapHelper.CalculateBearingDegrees(OwnerUnit.Position.Coordinate, unit.Position.Coordinate));

            //needs to distinguish sensors: dipping, hull mounted, towed, etc:
            switch (this.SensorClass.SonarType) //accounting for baffle arcs ie blind zones
            {
            case GameConstants.SonarType.HullMountedBow:
                if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 150, 210))
                {
                    return(false);
                }
                break;

            case GameConstants.SonarType.HullMountedKeel:
                if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 135, 225))
                {
                    return(false);
                }

                break;

            case GameConstants.SonarType.HullMountedFlankArray:     //assumes both starbord and port
                if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 330, 30))
                {
                    return(false);
                }
                if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 150, 210))
                {
                    return(false);
                }

                break;

            case GameConstants.SonarType.DippingOrSonobuoy: //no bafflezones
                if (OwnerUnit.ActualSpeedKph > 30)          //these sonars do not operate if moving
                {
                    return(false);
                }
                break;

            case GameConstants.SonarType.TowedArray:
                if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 315, 45))     //MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 135, 225))
                {
                    return(false);
                }
                if (OwnerUnit.ActualSpeedKph > GameConstants.DEFAULT_SLOW_SPEED)     //do not operate above 15 kph
                {
                    return(false);
                }
                break;

            default:
                break;
            }
            double noiseLevelTargetPercent   = unit.GetCurrentNoiseLevelPercentage();
            double noiseLevelPlatformPercent = OwnerUnit.GetCurrentNoiseLevelPercentage();
            double detectionRangeM           = 0;
            int    currentSeaState           = 0;
            var    weather = unit.GetWeatherSystem();

            if (weather != null)
            {
                currentSeaState = weather.SeaState;
            }
            double sensorDepthM = (double)OwnerUnit.Position.HeightOverSeaLevelM - unit.UnitClass.DraftM;
            double targetDepthM = (double)unit.Position.HeightOverSeaLevelM;

            if (this.SensorClass.IsVariableDepthSensor && this.IsDeployedIntermediateDepth && sensorDepthM < GameConstants.DEFAULT_DEPTH_THERMAL_LAYER_M)
            {
                sensorDepthM = GameConstants.DEFAULT_DEPTH_THERMAL_LAYER_M - 10;
            }
            TerrainLineSummary terrainLineSummary = GetTerrainHeightSummaryToTarget(unit);

            if (sensorDepthM < terrainLineSummary.MaxHeightM && targetDepthM < terrainLineSummary.MaxHeightM)
            {
                return(false); //higher terrain between objects - cannot detect
            }
            if (this.IsActive)
            {
                detectionRangeM = this.SensorClass.SonarActiveReferenceRangeM;
                if (OwnerUnit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M ||
                    unit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M)
                {
                    if (currentSeaState > 8)
                    {
                        detectionRangeM *= 0.1;
                    }
                    else if (currentSeaState > 6)
                    {
                        detectionRangeM *= 0.25;
                    }
                    else if (currentSeaState > 4)
                    {
                        detectionRangeM *= 0.5;
                    }
                }
                CurrentEffectiveActiveDetectionRangeM = detectionRangeM;
                if (terrainLineSummary.MaxHeightBehindM > targetDepthM)
                {
                    detectionRangeM *= 0.5;
                }
                if (unit.UnitClass.IsSonarShielded)
                {
                    detectionRangeM *= 0.5;
                }

                detectionRangeM = (detectionRangeM / noiseLevelPlatformPercent) * 100.0; //hmm
                double detectionStrength = detectionRangeM / distanceM;
                if (IsOnDifferentSidesOfThermalLayer(unit.Position))                     //TODO: Calculate angle to layer and calculate detection based on it
                {
                    detectionStrength *= 0.5;
                }
                if (detectionStrength > 1)
                {
                    DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM,
                                                                        0, 0); //check!
                    return(detect != null);
                }

                //unit.UnitClass.IsSonarShielded
                //remember, cannot identify
            }
            else //passive detection
            {
                detectionRangeM = this.SensorClass.SonarPassiveReferenceRangeM;
                if (unit.HasActiveSonar)
                {
                    noiseLevelTargetPercent = 800;
                }
                detectionRangeM = (detectionRangeM / noiseLevelPlatformPercent) * 100.0; //hmm

                if (distanceM > detectionRangeM)
                {
                    return(false);
                }
                if (sensorDepthM <= GameConstants.DEFAULT_DEPTH_THERMAL_LAYER_M &&
                    unit.Position.HeightOverSeaLevelM >= GameConstants.DEPTH_PERISCOPE_MIN_M)    //sound channels
                {
                    detectionRangeM *= 3.0;
                }
                if (OwnerUnit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M ||
                    unit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M)
                {
                    if (currentSeaState > 8)
                    {
                        detectionRangeM *= 0.1;
                    }
                    else if (currentSeaState > 6)
                    {
                        detectionRangeM *= 0.25;
                    }
                    else if (currentSeaState > 4)
                    {
                        detectionRangeM *= 0.5;
                    }
                    else if (currentSeaState > 2)
                    {
                        detectionRangeM *= 0.8;
                    }
                }
                if (terrainLineSummary.MaxHeightBehindM > targetDepthM)
                {
                    detectionRangeM *= 0.5;
                }
                CurrentEffectivePassiveDetectionRangeM = detectionRangeM;
                detectionRangeM *= noiseLevelTargetPercent / 100.0;
                double detectionStrength = detectionRangeM / distanceM;
                if (IsOnDifferentSidesOfThermalLayer(unit.Position))
                {
                    detectionStrength *= 0.5;
                }
                if (detectionStrength > 1)
                {
                    DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM,
                                                                        0, 0); //check!
                    return(detect != null);
                }

                //can identify, but not fix
            }
            return(false);
            //return base.AttemptDetectUnit(unit, distanceM);
        }
Exemple #6
0
        //ESM detection calculator: http://www.y1pwe.co.uk/AppletCD/Prop2.htm

        public override bool AttemptDetectUnit(BaseUnit unit, double distanceM)
        {
            if (!IsAbleToDetectUnit(unit, distanceM))
            {
                return(false);
            }
            if ((double)OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M ||
                (double)unit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M)    //under sea level
            {
                return(false);
            }
            //TODO: Take into account over-the horizon capabilities of some radars
            double sensorHeightOverSeaLevelM = (double)OwnerUnit.Position.HeightOverSeaLevelM
                                               + OwnerUnit.UnitClass.HeightM;
            double targetMaxHeightOverSeaLevelM = (double)unit.Position.HeightOverSeaLevelM + unit.UnitClass.HeightM;
            double LineOfSightM = MapHelper.CalculateMaxRadarLineOfSightM(sensorHeightOverSeaLevelM, targetMaxHeightOverSeaLevelM);

            TerrainLineSummary terrainLineSummary = null;

            if (IsActive)
            {
                if (distanceM <= LineOfSightM)
                {
                    GameConstants.DirectionCardinalPoints direction =
                        MapHelper.CalculateBearingDegrees(OwnerUnit.Position.Coordinate,
                                                          unit.Position.Coordinate).ToCardinalMark();
                    double targetApparentSizeArcSec = unit.CalculateRadarCorrectedSizeArcSec(direction, distanceM);
                    double minDetectableSizeArcSec  = SensorClass.MinimumTargetSurfaceSizeArcSec;
                    double degradationPercent       = 0;
                    if (targetMaxHeightOverSeaLevelM > 90)
                    {
                        minDetectableSizeArcSec = SensorClass.MinimumTargetAirSizeArcSec;
                    }
                    else
                    {
                        degradationPercent = GameManager.Instance.GetRadarDegradationFromSeaStatePercent(
                            OwnerUnit.GetEffectiveSeaState());
                    }

                    terrainLineSummary = GetTerrainHeightSummaryToTarget(unit);

                    if (sensorHeightOverSeaLevelM < GameConstants.MAX_HEIGHT_TERRAIN_M)
                    {
                        if (sensorHeightOverSeaLevelM < terrainLineSummary.MaxHeightM && targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM)
                        {
                            return(false); //no radar detection through terrain
                        }
                        if (targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM * 1.2 && terrainLineSummary.HeightVarianceM > 0)
                        {
                            degradationPercent += 10;
                        }
                    }
                    if (targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightBehindM)
                    {
                        degradationPercent += 75;
                    }
                    if (OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M ||
                        unit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M)    //only if any below cloud cover
                    {
                        degradationPercent += GameManager.Instance.GetRadarDegradationFromWeatherPercent(
                            unit.GetWeatherSystem());
                    }
                    degradationPercent += OwnerUnit.GetDegradationFromJammingPercent(this.SensorClass.SensorType);
                    if (unit.UnitClass.UnitType == GameConstants.UnitType.Missile && unit.Position.HeightOverSeaLevelM < 20)
                    {
                        degradationPercent += 40; //make sea skimming missiles much harder to detect
                    }
                    if (degradationPercent > 100)
                    {
                        degradationPercent = 100;
                    }
                    var degradationFactor = (1.0 - (degradationPercent / 100.0));
                    if (degradationFactor < 0.001)
                    {
                        degradationFactor = 0.001;
                    }
                    minDetectableSizeArcSec = minDetectableSizeArcSec * degradationFactor;
                    if (targetApparentSizeArcSec >= minDetectableSizeArcSec)
                    {
                        double       detectionStrength = targetApparentSizeArcSec / minDetectableSizeArcSec; //(SensorClass.MaxRangeM - DistanceM) / SensorClass.MaxRangeM;
                        DetectedUnit detect            = CreateOrUpdateDetectionReport(unit, detectionStrength,
                                                                                       distanceM, targetApparentSizeArcSec, minDetectableSizeArcSec);
                        if (detect != null)
                        {
                            return(true);
                        }
                    }
                }
            } //Even if active detection attempt has been made and failed, test for esm (passive)
            if (SensorClass.IsEsmDetector)
            {
                GameConstants.EsmRadiationLevel esmRad = unit.GetCurrentEsmRadiation();
                if (esmRad == GameConstants.EsmRadiationLevel.EsmNone)
                {
                    return(false);
                }
                else
                {
                    LineOfSightM = (LineOfSightM * SensorClass.EsmDetectionOverHorizonPercent) / 100.0;
                    if (esmRad == GameConstants.EsmRadiationLevel.EsmLow)
                    {
                        LineOfSightM *= 0.1;
                    }
                    else if (esmRad == GameConstants.EsmRadiationLevel.EsmMedium)
                    {
                        LineOfSightM *= 0.25;
                    }
                    if (sensorHeightOverSeaLevelM < GameConstants.MAX_HEIGHT_TERRAIN_M)
                    {
                        // Get terrain summary if not already gotten
                        if (terrainLineSummary == null)
                        {
                            terrainLineSummary = GetTerrainHeightSummaryToTarget(unit);
                        }

                        if (sensorHeightOverSeaLevelM < terrainLineSummary.MaxHeightM && targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM)
                        {
                            return(false); //no radar detection through terrain
                        }
                        if (targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM * 1.2 && terrainLineSummary.HeightVarianceM > 0)
                        {
                            LineOfSightM *= 0.75;
                        }
                    }
                    if (unit.UnitClass.UnitType == GameConstants.UnitType.Missile && unit.Position.HeightOverSeaLevelM < 20) //sea skimmers
                    {
                        LineOfSightM *= 0.25;
                    }
                    var degrJammingPercent = OwnerUnit.GetDegradationFromJammingPercent(this.SensorClass.SensorType);
                    LineOfSightM *= (100.0 - degrJammingPercent);

                    if (distanceM <= LineOfSightM)
                    {
                        DetectedUnit detect = CreateOrUpdateDetectionReport(unit, (LineOfSightM / distanceM),
                                                                            distanceM, 3600, 60);
                        return(detect != null);
                    }
                }
            }
            return(false);
        }
Exemple #7
0
        public virtual DetectedUnit CreateOrUpdateDetectionReport(BaseUnit unit,
                                                                  double detectionStrength, double distanceM, double targetApparentSizeArcSec, double minDetectableSizeArcSec)
        {
            DetectedUnit       detect = OwnerPlayer.DetectedUnits.Find(d => d.RefersToUnit.Id == unit.Id);
            DetectedUnitSensor sensor;

            if (detect != null) //detected previously
            {
                detect.IsMarkedForDeletion = false;
                sensor = detect.AddOrUpdateSensor(unit, this, detectionStrength, distanceM,
                                                  targetApparentSizeArcSec, minDetectableSizeArcSec);
                detect.DetectedGameWorldTimeSec = GameManager.Instance.Game.GameWorldTimeSec;
                if (!unit.Position.Equals(detect.Position))
                {
                    detect.SetDirty(GameConstants.DirtyStatus.PositionOnlyChanged);
                    if (detect.IsFixed)
                    {
                        detect.Position = unit.Position.Clone(); //TODO: Add uncertainty if applicable
                    }
                }
                if (unit.DirtySetting == GameConstants.DirtyStatus.UnitChanged)
                {
                    detect.SetDirty(GameConstants.DirtyStatus.UnitChanged);
                }

                if (detectionStrength >= SensorClass.IdentifyDetectionStrength &&
                    !detect.IsFixed && !detect.IsIdentified)
                {
                    detect.IsFixed      = true;
                    detect.IsIdentified = true;
                    detect.SetDirty(GameConstants.DirtyStatus.UnitChanged);
                    if (this.OwnerPlayer.IsEnemy(unit.OwnerPlayer))
                    {
                        detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Foe;
                    }
                    else if (OwnerPlayer.IsAlly(unit.OwnerPlayer))
                    {
                        detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Friend;
                    }
                    GameManager.Instance.Log.LogDebug("CreateOrUpdateDetectionReport: UPDATE: " + detect.ToLongString());
                }
                if (detect.IsIdentified)
                {
                    if (this.OwnerPlayer.IsEnemy(unit.OwnerPlayer))
                    {
                        detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Foe;
                    }
                    else if (OwnerPlayer.IsAlly(unit.OwnerPlayer))
                    {
                        detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Friend;
                    }
                    //detect.SetDirty(GameConstants.DirtyStatus.UnitChanged);
                }
                if (OwnerPlayer.AIHandler != null && detect.DirtySetting == GameConstants.DirtyStatus.UnitChanged)
                {
                    OwnerPlayer.AIHandler.DetectionUpdated(detect);
                }
                return(detect); //otherwise unchanged
            }
            //NEW DETECTION:
            detect             = new DetectedUnit();
            detect.OwnerPlayer = this.OwnerPlayer;

            detect.ThreatClassification = GameConstants.ThreatClassification.U_Undecided;
            sensor = detect.AddOrUpdateSensor(unit, this, detectionStrength, distanceM,
                                              targetApparentSizeArcSec, minDetectableSizeArcSec);
            if (!unit.UnitClass.CanBeTargeted)
            {
                detect.CanBeTargeted = false;
            }
            if (detect.IsIdentified)
            {
                if (this.OwnerPlayer.IsEnemy(unit.OwnerPlayer))
                {
                    detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Foe;
                }
                else
                {
                    if (this.OwnerPlayer.IsAlly(unit.OwnerPlayer))
                    {
                        detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Friend;
                    }
                }
            }
            if (detect.FriendOrFoeClassification == GameConstants.FriendOrFoe.Undetermined)
            {
                if (detect.RefersToUnit != null && detect.RefersToUnit.UnitClass.IsMissileOrTorpedo) //missiles assumed hostile
                {
                    if (!this.OwnerPlayer.IsAlly(unit.OwnerPlayer))
                    {
                        detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Foe;
                    }
                }
                if (detect.FriendOrFoeClassification == GameConstants.FriendOrFoe.Undetermined &&
                    !detect.IsIdentified &&
                    OwnerPlayer.IsAllUnknownContactsHostile)
                {
                    detect.FriendOrFoeClassification = GameConstants.FriendOrFoe.Foe;
                }
            }
            GameManager.Instance.Log.LogDebug(string.Format(
                                                  "CreateOrUpdateDetectionReport NEW Player: {0}: Detection {1} ",
                                                  OwnerPlayer.ToString(), detect.ToLongString()));

            if (!this.SensorClass.IsTargetingSensorOnly)
            {
                OwnerPlayer.DetectedUnits.Add(detect);
            }
            detect.SetDetectedGroup();
            if (OwnerPlayer.AIHandler != null)
            {
                OwnerPlayer.AIHandler.NewDetection(detect);
            }
            return(detect);
        }
Exemple #8
0
        //public virtual void Sweep()
        //{
        //    if (!IsReady)
        //    {
        //        return;
        //    }
        //    if (OwnerUnit.CarriedByUnit != null)
        //    {
        //        return;
        //    }
        //    System.Diagnostics.Debug.Assert(OwnerPlayer != null, "BaseSensor.Sweep: Sensor OwnerPlayer should never be null.");
        //    System.Diagnostics.Debug.Assert(OwnerUnit != null, "BaseSensor.Sweep: Sensor OwnerUnit should never be null.");
        //    System.Diagnostics.Debug.Assert(SensorClass != null, "BaseSensor.Sweep: Sensor SensorClass should never be null.");


        //}

        public virtual bool AttemptDetectUnit(BaseUnit unit, double distanceM)
        {
            //TODO: Hit test on detection
            if (!IsAbleToDetectUnit(unit, distanceM))
            {
                return(false);
            }
            if (SensorClass.MaxHeightDeployedM > 0 && OwnerUnit.ActualHeightOverSeaLevelM > SensorClass.MaxHeightDeployedM)
            {
                ReadyInSec = 120;
                return(false);
            }
            if (SensorClass.MaxSpeedDeployedKph > 0 && OwnerUnit.ActualSpeedKph > SensorClass.MaxSpeedDeployedKph)
            {
                ReadyInSec = 120;
                return(false);
            }
            //if (!OwnerPlayer.IsComputerPlayer)
            //{
            //    GameManager.Instance.Log.LogDebug(string.Format(
            //        "PLAYER {0}, UNIT {1}, SENSOR {2} attemtping to detect unit {3}.",
            //        OwnerPlayer.ToString(), OwnerUnit.ToString(), this.ToString(), unit.ToString()));
            //}
            GameConstants.DirectionCardinalPoints DirectionToTarget =
                MapHelper.CalculateBearingDegrees(OwnerUnit.Position.Coordinate,
                                                  unit.Position.Coordinate).ToCardinalMark();

            TerrainLineSummary terrainLineSummary = GetTerrainHeightSummaryToTarget(unit);

            //No sensor can see through terrain
            if (terrainLineSummary.MaxHeightM > OwnerUnit.Position.HeightOverSeaLevelM && terrainLineSummary.MaxHeightM > unit.Position.HeightOverSeaLevelM)
            {
                return(false);
            }
            double targetApparentSizeArcSec =
                unit.CalculateRadarCorrectedSizeArcSec(DirectionToTarget, distanceM);

            if (SensorClass.SensorType == GameConstants.SensorType.Visual)
            {
                if ((double)OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M ||
                    (double)unit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_SHALLOW_MIN_M)    //under sea level
                {
                    return(false);
                }
                double lineOfSightM = MapHelper.CalculateMaxLineOfSightM(
                    (double)OwnerUnit.Position.HeightOverSeaLevelM
                    + OwnerUnit.UnitClass.HeightM,
                    (double)unit.Position.HeightOverSeaLevelM
                    + unit.UnitClass.HeightM);

                double minimumTargetSizeArcSec = SensorClass.MinimumTargetSurfaceSizeArcSec;
                if (unit.Position.HeightOverSeaLevelM > 10)
                {
                    minimumTargetSizeArcSec = SensorClass.MinimumTargetAirSizeArcSec;
                }
                if (distanceM <= lineOfSightM && targetApparentSizeArcSec >= minimumTargetSizeArcSec)
                {
                    double        degradationPercent = 0;
                    WeatherSystem wsystem            = OwnerUnit.GetWeatherSystem();
                    if (wsystem != null && SensorClass.SensorType == GameConstants.SensorType.Visual)
                    {
                        degradationPercent = 100 - wsystem.TotalLightPercent;
                    }

                    if (OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M ||
                        unit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M)    //only if any below cloud cover
                    {
                        degradationPercent += GameManager.Instance.GetRadarDegradationFromWeatherPercent(wsystem);
                    }
                    //double MinDetectableSizeArcSec = SensorClass.MinimumTargetSurfaceSizeArcSec;
                    minimumTargetSizeArcSec = minimumTargetSizeArcSec * (1.0 + (degradationPercent / 100));
                    double DetectionStrength = targetApparentSizeArcSec
                                               / minimumTargetSizeArcSec; //(LineOfSightM - DistanceM) / LineOfSightM;
                    DetectedUnit detect = CreateOrUpdateDetectionReport(unit, DetectionStrength, distanceM,
                                                                        targetApparentSizeArcSec, minimumTargetSizeArcSec);
                    return(detect != null);
                }
                else
                {
                    return(false); //does not detect it
                }
            }
            else if (SensorClass.SensorType == GameConstants.SensorType.Infrared)
            {
                if ((double)OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M ||
                    (double)unit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_SHALLOW_MIN_M)    //under sea level
                {
                    return(false);
                }

                double        irDegradationPercent = 0;
                WeatherSystem weatherSystem        = OwnerUnit.GetWeatherSystem();
                if (OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M ||
                    unit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M)    //only if any below cloud cover
                {
                    irDegradationPercent += GameManager.Instance.GetIRDegradationFromWeatherPercent(weatherSystem);
                }

                double maxTargetDetectionDistanceM = unit.GetMaxIrDetectionDistanceM();
                double LineOfSightM = MapHelper.CalculateMaxLineOfSightM(
                    (double)OwnerUnit.Position.HeightOverSeaLevelM
                    + OwnerUnit.UnitClass.HeightM,
                    (double)unit.Position.HeightOverSeaLevelM)
                                      + unit.UnitClass.HeightM;
                if (maxTargetDetectionDistanceM > LineOfSightM)
                {
                    maxTargetDetectionDistanceM = LineOfSightM;
                }
                double detectionStrength = distanceM / maxTargetDetectionDistanceM;
                if (detectionStrength > 1.0)
                {
                    DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM,
                                                                        0, 0);
                    return(detect != null);
                }
                else
                {
                    return(false);
                }
            }
            else if (SensorClass.SensorType == GameConstants.SensorType.MAD)
            {
                if (unit.Position == null ||
                    !unit.Position.HasHeightOverSeaLevel ||
                    unit.Position.HeightOverSeaLevelM >= GameConstants.DEPTH_SHALLOW_MIN_M)
                {
                    return(false);
                }
                var unitDepthM = (double)unit.Position.HeightOverSeaLevelM;
                if (OwnerUnit.Position == null || !OwnerUnit.Position.HasHeightOverSeaLevel ||
                    OwnerUnit.Position.HeightOverSeaLevelM >= GameConstants.HEIGHT_MEDIUM_MIN_M)
                {
                    return(false);
                }
                if (unitDepthM <= GameConstants.DEPTH_DEEP_MIN_M)
                {
                    return(false);
                }
                double maxDetectionDistanceM = 1000.0;
                if (unitDepthM <= GameConstants.DEPTH_MEDIUM_MIN_M)
                {
                    maxDetectionDistanceM = 500;
                }
                double detectionStrength = distanceM / maxDetectionDistanceM;
                if (detectionStrength > 1.0)
                {
                    DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM,
                                                                        0, 0);
                    return(detect != null);
                }
                else
                {
                    return(false);
                }
            }
            return(false);
        }