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