IEnumerator LaunchWarningRoutine(TargetSignatureData data) { launchWarnings.Add(data); yield return(new WaitForSeconds(2)); launchWarnings.Remove(data); }
/// <summary> /// Find a flare within acceptable thermal range that will "decoy" for the passed heatsignature /// </summary> public static TargetSignatureData GetFlareTarget(Ray ray, float scanRadius, float highpassThreshold, bool allAspect, float heatSignature) { TargetSignatureData flareTarget = TargetSignatureData.noTarget; List <CMFlare> .Enumerator flare = BDArmorySetup.Flares.GetEnumerator(); while (flare.MoveNext()) { if (!flare.Current) { continue; } float angle = Vector3.Angle(flare.Current.transform.position - ray.origin, ray.direction); if (angle < scanRadius) { float score = flare.Current.thermal * Mathf.Clamp01(15 / angle); score *= Mathf.Pow(1400, 2) / Mathf.Clamp((flare.Current.transform.position - ray.origin).sqrMagnitude, 90000, 36000000); score *= Mathf.Clamp(Vector3.Angle(flare.Current.transform.position - ray.origin, -VectorUtils.GetUpDirection(ray.origin)) / 90, 0.5f, 1.5f); // check acceptable range: // flare cannot be too cool, but also not too bright if ((score > heatSignature * 0.9) && (score < heatSignature * 1.15)) { flareTarget = new TargetSignatureData(flare.Current, score); } } } return(flareTarget); }
public override void OnStart(StartState state) { if (HighLogic.LoadedSceneIsFlight) { pingsData = new TargetSignatureData[dataCount]; pingWorldPositions = new Vector3[dataCount]; TargetSignatureData.ResetTSDArray(ref pingsData); launchWarnings = new List <TargetSignatureData>(); rwrIconLabelStyle = new GUIStyle(); rwrIconLabelStyle.alignment = TextAnchor.MiddleCenter; rwrIconLabelStyle.normal.textColor = Color.green; rwrIconLabelStyle.fontSize = 12; rwrIconLabelStyle.border = new RectOffset(0, 0, 0, 0); rwrIconLabelStyle.clipping = TextClipping.Overflow; rwrIconLabelStyle.wordWrap = false; rwrIconLabelStyle.fontStyle = FontStyle.Bold; audioSource = gameObject.AddComponent <AudioSource>(); audioSource.minDistance = 500; audioSource.maxDistance = 1000; audioSource.spatialBlend = 1; audioSource.dopplerLevel = 0; audioSource.loop = false; UpdateVolume(); BDArmorySetup.OnVolumeChange += UpdateVolume; float size = displayRect.height + 20; if (!WindowRectRWRInitialized) { BDArmorySetup.WindowRectRwr = new Rect(40, Screen.height - size - 20, size, size + 20); WindowRectRWRInitialized = true; } List <MissileFire> .Enumerator mf = vessel.FindPartModulesImplementing <MissileFire>().GetEnumerator(); while (mf.MoveNext()) { if (mf.Current == null) { continue; } mf.Current.rwr = this; if (!weaponManager) { weaponManager = mf.Current; } } mf.Dispose(); if (rwrEnabled) { EnableRWR(); } } }
public void SetActiveLock(TargetSignatureData target) { for (int i = 0; i < lockedTargets.Count; i++) { if (target.vessel == lockedTargets[i].vessel) { lockedTargetIndex = i; return; } } }
public override void OnStart(StartState state) { if (HighLogic.LoadedSceneIsFlight) { pingsData = new TargetSignatureData[dataCount]; pingWorldPositions = new Vector3[dataCount]; TargetSignatureData.ResetTSDArray(ref pingsData); launchWarnings = new List <TargetSignatureData>(); rwrIconLabelStyle = new GUIStyle(); rwrIconLabelStyle.alignment = TextAnchor.MiddleCenter; rwrIconLabelStyle.normal.textColor = Color.green; rwrIconLabelStyle.fontSize = 12; rwrIconLabelStyle.border = new RectOffset(0, 0, 0, 0); rwrIconLabelStyle.clipping = TextClipping.Overflow; rwrIconLabelStyle.wordWrap = false; rwrIconLabelStyle.fontStyle = FontStyle.Bold; audioSource = gameObject.AddComponent <AudioSource>(); audioSource.minDistance = 500; audioSource.maxDistance = 1000; audioSource.spatialBlend = 1; audioSource.dopplerLevel = 0; audioSource.loop = false; UpdateVolume(); BDArmorySetup.OnVolumeChange += UpdateVolume; if (!WindowRectRWRInitialized) { BDArmorySetup.WindowRectRwr = new Rect(BDArmorySetup.WindowRectRwr.x, BDArmorySetup.WindowRectRwr.y, RwrDisplayRect.height + BorderSize, RwrDisplayRect.height + BorderSize + HeaderSize); // BDArmorySetup.WindowRectRwr = new Rect(40, Screen.height - RwrDisplayRect.height, RwrDisplayRect.height + BorderSize, RwrDisplayRect.height + BorderSize + HeaderSize); WindowRectRWRInitialized = true; } using (var mf = VesselModuleRegistry.GetModules <MissileFire>(vessel).GetEnumerator()) while (mf.MoveNext()) { if (mf.Current == null) { continue; } mf.Current.rwr = this; // Set the rwr on all weapon managers to this. if (!weaponManager) { weaponManager = mf.Current; // Set the first found weapon manager as the one in control. } } //if (rwrEnabled) EnableRWR(); EnableRWR(); } }
public void UpdateLockedTargetInfo(TargetSignatureData newData) { int index = -1; for (int i = 0; i < lockedTargets.Count; i++) { if (lockedTargets[i].vessel != newData.vessel) { continue; } index = i; break; } if (index >= 0) { lockedTargets[index] = newData; } }
public void ReceiveContactData(TargetSignatureData contactData, bool _locked) { if (vesselRadarData) { vesselRadarData.AddRadarContact(this, contactData, _locked); } List <VesselRadarData> .Enumerator vrd = linkedToVessels.GetEnumerator(); while (vrd.MoveNext()) { if (vrd.Current == null) { continue; } if (vrd.Current.canReceiveRadarData && vrd.Current.vessel != contactData.vessel) { vrd.Current.AddRadarContact(this, contactData, _locked); } } vrd.Dispose(); }
protected void UpdateHeatTarget() { if (lockFailTimer > 1) { legacyTargetVessel = null; TargetAcquired = false; return; } if (heatTarget.exists && lockFailTimer < 0) { lockFailTimer = 0; } if (lockFailTimer >= 0) { Ray lookRay = new Ray(transform.position, heatTarget.position + (heatTarget.velocity * Time.fixedDeltaTime) - transform.position); heatTarget = BDATargetManager.GetHeatTarget(SourceVessel, vessel, lookRay, lockedSensorFOV / 2, heatThreshold, allAspect, SourceVessel?.gameObject?.GetComponent <MissileFire>()); if (heatTarget.exists) { TargetAcquired = true; TargetPosition = heatTarget.position + (2 * heatTarget.velocity * Time.fixedDeltaTime); TargetVelocity = heatTarget.velocity; TargetAcceleration = heatTarget.acceleration; lockFailTimer = 0; } else { TargetAcquired = false; if (FlightGlobals.ready) { lockFailTimer += Time.fixedDeltaTime; } } } }
public void AddRadarContact(ModuleRadar radar, TargetSignatureData contactData, bool _locked) { RadarDisplayData rData = new RadarDisplayData(); rData.vessel = contactData.vessel; if(rData.vessel == vessel) { return; } rData.signalPersistTime = radar.signalPersistTime; rData.detectedByRadar = radar; rData.locked = _locked; rData.targetData = contactData; rData.pingPosition = UpdatedPingPosition(contactData.position, radar); if(_locked) { radar.UpdateLockedTargetInfo(contactData); } bool dontOverwrite = false; int replaceIndex = -1; for(int i = 0; i < displayedTargets.Count; i++) { if(displayedTargets[i].vessel == rData.vessel) { if(displayedTargets[i].locked && !_locked) { dontOverwrite = true; break; } replaceIndex = i; break; } } if(replaceIndex >= 0) { displayedTargets[replaceIndex] = rData; //UpdateLockedTargets(); return; } else if(dontOverwrite) { //UpdateLockedTargets(); return; } else { displayedTargets.Add(rData); UpdateLockedTargets(); return; } }
public override void OnAwake() { clickSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/click"); warningSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/warning"); armOnSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/armOn"); armOffSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/armOff"); heatGrowlSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/heatGrowl"); //HEAT LOCKING heatTarget = TargetSignatureData.noTarget; }
void UpdateRadarTarget() { targetAcquired = false; float angleToTarget = Vector3.Angle(radarTarget.predictedPosition-transform.position,transform.forward); if(radarTarget.exists) { if(!activeRadar && ((radarTarget.predictedPosition - transform.position).sqrMagnitude > Mathf.Pow(activeRadarRange, 2) || angleToTarget > maxOffBoresight * 0.75f)) { if(vrd) { TargetSignatureData t = TargetSignatureData.noTarget; List<TargetSignatureData> possibleTargets = vrd.GetLockedTargets(); for(int i = 0; i < possibleTargets.Count; i++) { if(possibleTargets[i].vessel == radarTarget.vessel) { t = possibleTargets[i]; } } if(t.exists) { targetAcquired = true; radarTarget = t; targetPosition = radarTarget.predictedPosition; targetVelocity = radarTarget.velocity; targetAcceleration = radarTarget.acceleration; radarFailTimer = 0; return; } else { if(radarFailTimer > maxRadarFailTime) { Debug.Log("Semi-Active Radar guidance failed. Parent radar lost target."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } else { if(radarFailTimer == 0) { Debug.Log("Semi-Active Radar guidance failed - waiting for data"); } radarFailTimer += Time.fixedDeltaTime; radarTarget.timeAcquired = Time.time; radarTarget.position = radarTarget.predictedPosition; targetPosition = radarTarget.predictedPosition; targetVelocity = radarTarget.velocity; targetAcceleration = Vector3.zero; targetAcquired = true; } } } else { Debug.Log("Semi-Active Radar guidance failed. Out of range and no data feed."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } } else { vrd = null; if(angleToTarget > maxOffBoresight) { Debug.Log("Radar guidance failed. Target is out of active seeker gimbal limits."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } else { if(scannedTargets == null) scannedTargets = new TargetSignatureData[5]; TargetSignatureData.ResetTSDArray(ref scannedTargets); Ray ray = new Ray(transform.position, radarTarget.predictedPosition - transform.position); bool pingRWR = Time.time - lastRWRPing > 0.4f; if(pingRWR) lastRWRPing = Time.time; bool radarSnapshot = (snapshotTicker > 20); if(radarSnapshot) { snapshotTicker = 0; } else { snapshotTicker++; } RadarUtils.UpdateRadarLock(ray, lockedSensorFOV, activeRadarMinThresh, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); float sqrThresh = radarLOALSearching ? Mathf.Pow(500, 2) : Mathf.Pow(40, 2); if(radarLOAL && radarLOALSearching && !radarSnapshot) { //only scan on snapshot interval } else { for(int i = 0; i < scannedTargets.Length; i++) { if(scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) { radarTarget = scannedTargets[i]; targetAcquired = true; radarLOALSearching = false; targetPosition = radarTarget.predictedPosition + (radarTarget.velocity * Time.fixedDeltaTime); targetVelocity = radarTarget.velocity; targetAcceleration = radarTarget.acceleration; radarFailTimer = 0; if(!activeRadar && Time.time - timeFired > 1) { if(locksCount == 0) { RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); Debug.Log("Pitbull! Radar missile has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); } else if(locksCount > 2) { guidanceActive = false; checkMiss = true; if(BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("Radar missile reached max re-lock attempts."); } } locksCount++; } activeRadar = true; return; } } } if(radarLOAL) { radarLOALSearching = true; targetAcquired = true; targetPosition = radarTarget.predictedPosition + (radarTarget.velocity * Time.fixedDeltaTime); targetVelocity = radarTarget.velocity; targetAcceleration = Vector3.zero; activeRadar = false; } else { radarTarget = TargetSignatureData.noTarget; } } } } else if(radarLOAL && radarLOALSearching) { if(scannedTargets == null) scannedTargets = new TargetSignatureData[5]; TargetSignatureData.ResetTSDArray(ref scannedTargets); Ray ray = new Ray(transform.position, transform.forward); bool pingRWR = Time.time - lastRWRPing > 0.4f; if(pingRWR) lastRWRPing = Time.time; bool radarSnapshot = (snapshotTicker > 6); if(radarSnapshot) { snapshotTicker = 0; } else { snapshotTicker++; } RadarUtils.UpdateRadarLock(ray, lockedSensorFOV*3, activeRadarMinThresh*2, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); float sqrThresh = Mathf.Pow(300, 2); float smallestAngle = 360; TargetSignatureData lockedTarget = TargetSignatureData.noTarget; for(int i = 0; i < scannedTargets.Length; i++) { if(scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) { float angle = Vector3.Angle(scannedTargets[i].predictedPosition - transform.position, transform.forward); if(angle < smallestAngle) { lockedTarget = scannedTargets[i]; smallestAngle = angle; } activeRadar = true; return; } } if(lockedTarget.exists) { radarTarget = lockedTarget; targetAcquired = true; radarLOALSearching = false; targetPosition = radarTarget.predictedPosition + (radarTarget.velocity * Time.fixedDeltaTime); targetVelocity = radarTarget.velocity; targetAcceleration = radarTarget.acceleration; if(!activeRadar && Time.time - timeFired > 1) { RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); Debug.Log("Pitbull! Radar missile has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); } return; } else { targetAcquired = true; targetPosition = transform.position + (startDirection * 500); targetVelocity = Vector3.zero; targetAcceleration = Vector3.zero; radarLOALSearching = true; return; } } if(!radarTarget.exists) { legacyTargetVessel = null; } }
public static void UpdateRadarLock(MissileFire myWpnManager, float directionAngle, Transform referenceTransform, float fov, Vector3 position, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType, bool radarSnapshot) { Vector3d geoPos = VectorUtils.WorldPositionToGeoCoords(position, FlightGlobals.currentMainBody); Vector3 forwardVector = referenceTransform.forward; Vector3 upVector = referenceTransform.up;//VectorUtils.GetUpDirection(position); Vector3 lookDirection = Quaternion.AngleAxis(directionAngle, upVector) * forwardVector; int dataIndex = 0; foreach(var vessel in BDATargetManager.LoadedVessels) { if(vessel == null) continue; if(!vessel.loaded) continue; if(myWpnManager) { if(vessel == myWpnManager.vessel) continue; //ignore self } else if((vessel.transform.position - position).sqrMagnitude < 3600) continue; Vector3 vesselDirection = Vector3.ProjectOnPlane(vessel.CoM - position, upVector); if(Vector3.Angle(vesselDirection, lookDirection) < fov / 2) { if(TerrainCheck(referenceTransform.position, vessel.transform.position)) continue; //blocked by terrain float sig = float.MaxValue; if(radarSnapshot && minSignature > 0) sig = GetModifiedSignature(vessel, position); RadarWarningReceiver.PingRWR(vessel, position, rwrType, dataPersistTime); float detectSig = sig; VesselECMJInfo vesselJammer = vessel.GetComponent<VesselECMJInfo>(); if(vesselJammer) { sig *= vesselJammer.rcsReductionFactor; detectSig += vesselJammer.jammerStrength; } if(detectSig > minSignature) { if(vessel.vesselType == VesselType.Debris) { vessel.gameObject.AddComponent<TargetInfo>(); } else if(myWpnManager != null) { BDATargetManager.ReportVessel(vessel, myWpnManager); } while(dataIndex < dataArray.Length - 1) { if((dataArray[dataIndex].exists && Time.time - dataArray[dataIndex].timeAcquired > dataPersistTime) || !dataArray[dataIndex].exists) { break; } dataIndex++; } if(dataIndex >= dataArray.Length) break; dataArray[dataIndex] = new TargetSignatureData(vessel, sig); dataIndex++; if(dataIndex >= dataArray.Length) break; } } } }
public void SetActiveLock(TargetSignatureData target) { for(int i = 0; i < lockedTargets.Count; i++) { if(target.vessel == lockedTargets[i].vessel) { lockedTargetIndex = i; return; } } }
public static TargetSignatureData GetHeatTarget(Ray ray, float scanRadius, float highpassThreshold, bool allAspect) { float minScore = highpassThreshold; float minMass = 0.5f; TargetSignatureData finalData = TargetSignatureData.noTarget; float finalScore = 0; foreach(var vessel in BDATargetManager.LoadedVessels) { if(!vessel || !vessel.loaded) { continue; } if(vessel.GetTotalMass() < minMass) { continue; } if(RadarUtils.TerrainCheck(ray.origin, vessel.transform.position)) { continue; } float angle = Vector3.Angle(vessel.CoM-ray.origin, ray.direction); if(angle < scanRadius) { float score = 0; foreach(var part in vessel.Parts) { if(!part) continue; if(!allAspect) { if(!Misc.CheckSightLine(ray.origin, part.transform.position, 10000, 5, 5)) continue; } float thisScore = (float)(part.thermalInternalFluxPrevious+part.skinTemperature) * Mathf.Clamp01(15/angle); thisScore *= Mathf.Pow(1400,2)/Mathf.Clamp((vessel.CoM-ray.origin).sqrMagnitude, 90000, 36000000); score = Mathf.Max (score, thisScore); } if(vessel.LandedOrSplashed) { score /= 4; } score *= Mathf.Clamp(Vector3.Angle(vessel.transform.position-ray.origin, -VectorUtils.GetUpDirection(ray.origin))/90, 0.5f, 1.5f); if(score > finalScore) { finalScore = score; finalData = new TargetSignatureData(vessel, score); } } } heatScore = finalScore;//DEBUG flareScore = 0; //DEBUG foreach(var flare in BDArmorySettings.Flares) { if(!flare) continue; float angle = Vector3.Angle(flare.transform.position-ray.origin, ray.direction); if(angle < scanRadius) { float score = flare.thermal * Mathf.Clamp01(15/angle); score *= Mathf.Pow(1400,2)/Mathf.Clamp((flare.transform.position-ray.origin).sqrMagnitude, 90000, 36000000); score *= Mathf.Clamp(Vector3.Angle(flare.transform.position-ray.origin, -VectorUtils.GetUpDirection(ray.origin))/90, 0.5f, 1.5f); if(score > finalScore) { flareScore = score;//DEBUG finalScore = score; finalData = new TargetSignatureData(flare, score); } } } if(finalScore < minScore) { finalData = TargetSignatureData.noTarget; } return finalData; }
public void TryLockTarget(Vector3 position) { if(!canLock) { if(linkedRadar && linkedRadar.radarEnabled) { linkedRadar.TryLockTarget(position); lockedTarget = linkedRadar.lockedTarget; locked = true; } return; } Debug.Log ("Trying to radar lock target"); Vector3 targetPlanarDirection = Vector3.ProjectOnPlane(position-referenceTransform.position, referenceTransform.up); float angle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); if(referenceTransform.InverseTransformPoint(position).x < 0) { angle = -angle; } //TargetSignatureData.ResetTSDArray(ref attemptedLocks); RadarUtils.ScanInDirection(weaponManager, angle, referenceTransform, lockAttemptFOV, referenceTransform.position, minLockedSignalThreshold, ref attemptedLocks, signalPersistTime, true, rwrType, true); for(int i = 0; i < attemptedLocks.Length; i++) { if(attemptedLocks[i].exists && (attemptedLocks[i].position-position).sqrMagnitude < Mathf.Pow(40,2)) { locked = true; lockedTarget = attemptedLocks[i]; Debug.Log ("- Acquired lock on target."); return; } } Debug.Log ("- Failed to lock on target."); }
public override void OnStart(StartState state) { base.OnStart (state); if(HighLogic.LoadedSceneIsFlight) { RadarUtils.SetupRadarCamera(); distanceStyle = new GUIStyle(); distanceStyle.normal.textColor = new Color(0,1,0,0.75f); distanceStyle.alignment = TextAnchor.UpperLeft; lockStyle = new GUIStyle(); lockStyle.normal.textColor = new Color(0,1,0,0.75f); lockStyle.alignment = TextAnchor.LowerCenter; lockStyle.fontSize = 16; radarTopStyle = new GUIStyle(); radarTopStyle.normal.textColor = new Color(0, 1, 0, 0.65f); radarTopStyle.alignment = TextAnchor.UpperCenter; radarTopStyle.fontSize = 12; rIncrements = Misc.ParseToFloatArray(rangeIncrements); rangeIndex = Mathf.Clamp(rangeIndex, 0, rIncrements.Length-1); maxRange = rIncrements[rIncrements.Length-1]; signalPersistTime = omnidirectional ? 360/(scanRotationSpeed+5) : directionalFieldOfView/(scanRotationSpeed+5); if(rotationTransformName!=string.Empty) { rotationTransform = part.FindModelTransform(rotationTransformName); } if(!radarRectInitialized) { float width = radarScreenSize + (2*windowBorder); float height = radarScreenSize + (2*windowBorder) + headerHeight + controlsHeight; radarWindowRect = new Rect(Screen.width - width, Screen.height - height, width, height); radarRectInitialized = true; } lockedTarget = TargetSignatureData.noTarget; contacts = new TargetSignatureData[10]; TargetSignatureData.ResetTSDArray(ref contacts); attemptedLocks = new TargetSignatureData[3]; TargetSignatureData.ResetTSDArray(ref attemptedLocks); referenceTransform = (new GameObject()).transform; referenceTransform.parent = transform; referenceTransform.localPosition = Vector3.zero; lockingTurret = part.FindModuleImplementing<ModuleTurret> (); rwrType = (RadarWarningReceiver.RWRThreatTypes) rwrThreatType; unlinkNullRadar = false; foreach(var wm in vessel.FindPartModulesImplementing<MissileFire>()) { wm.radars.Add(this); } StartCoroutine(StartUpRoutine()); } }
void UpdateLock() { if(!canLock && linked && linkedRadar && linkedRadar.locked) { lockedTarget = linkedRadar.lockedTarget; if(!lockedTarget.exists) { UnlockTarget(); } return; } if(!canLock) { if(lockedTarget.exists) { UnlockTarget(); return; } locked = false; return; } Vector3 targetPlanarDirection = Vector3.ProjectOnPlane(lockedTarget.predictedPosition-referenceTransform.position, referenceTransform.up); float lookAngle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); if(referenceTransform.InverseTransformPoint(lockedTarget.predictedPosition).x < 0) { lookAngle = -lookAngle; } if(omnidirectional) { if(lookAngle < 0) lookAngle += 360; } lockScanAngle = lookAngle + currentAngleLock; float angleDelta = lockRotationSpeed*Time.fixedDeltaTime; float lockedSignalPersist = lockRotationAngle/lockRotationSpeed; //RadarUtils.ScanInDirection(lockScanAngle, referenceTransform, angleDelta, referenceTransform.position, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist); bool radarSnapshot = (snapshotTicker > 30); if(radarSnapshot) { snapshotTicker = 0; } else { snapshotTicker++; } RadarUtils.ScanInDirection (new Ray (referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), lockRotationAngle * 2, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist, true, rwrType, radarSnapshot); TargetSignatureData prevLock = lockedTarget; lockedTarget = TargetSignatureData.noTarget; for(int i = 0; i < attemptedLocks.Length; i++) { if(attemptedLocks[i].exists && (attemptedLocks[i].predictedPosition-prevLock.predictedPosition).sqrMagnitude < Mathf.Pow(20,2) && attemptedLocks[i].age < 2*lockedSignalPersist) { lockedTarget = attemptedLocks[i]; break; } } if(!lockedTarget.exists) //if failed to maintain lock, get lock data from linked radar { if(linked && linkedRadar && linkedRadar.locked && (linkedRadar.lockedTarget.predictedPosition-prevLock.predictedPosition).sqrMagnitude < Mathf.Pow(20,2)) { lockedTarget = linkedRadar.lockedTarget; //if(lockedTarget.exists) return; } } //if still failed or out of FOV, unlock. if(!lockedTarget.exists || (!omnidirectional && Vector3.Angle(lockedTarget.position-referenceTransform.position, transform.up) > directionalFieldOfView/2)) { UnlockTarget(); return; } //unlock if over-jammed if(lockedTarget.vesselJammer && lockedTarget.vesselJammer.lockBreakStrength > lockedTarget.signalStrength*lockedTarget.vesselJammer.rcsReductionFactor) { UnlockTarget(); return; } //cycle scan direction currentAngleLock += radialScanDirection*angleDelta; if(Mathf.Abs(currentAngleLock) > lockRotationAngle/2) { currentAngleLock = Mathf.Sign(currentAngleLock) * lockRotationAngle/2; radialScanDirection = -radialScanDirection; } }
void UnlockTarget() { lockedTarget = TargetSignatureData.noTarget; locked = false; if (!canTrackWhileScan) { currentAngle = lockScanAngle; } }
public void FireMissile() { if(!hasFired) { hasFired = true; GameEvents.onPartDie.Add(PartDie); BDATargetManager.FiredMissiles.Add(this); if(GetComponentInChildren<KSPParticleEmitter>()) { BDArmorySettings.numberOfParticleEmitters++; } foreach(var wpm in vessel.FindPartModulesImplementing<MissileFire>()) { team = wpm.team; break; } sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/deployClick")); sourceVessel = vessel; //TARGETING targetPosition = transform.position + (transform.forward * 5000); //set initial target position so if no target update, missile will count a miss if it nears this point or is flying post-thrust startDirection = transform.forward; if(BDArmorySettings.ALLOW_LEGACY_TARGETING) { if(vessel.targetObject!=null && vessel.targetObject.GetVessel()!=null) { legacyTargetVessel = vessel.targetObject.GetVessel(); foreach(var mf in legacyTargetVessel.FindPartModulesImplementing<MissileFire>()) { targetMf = mf; break; } if(targetingMode == TargetingModes.Heat) { heatTarget = new TargetSignatureData(legacyTargetVessel, 9999); } } } if(targetingMode == TargetingModes.Laser) { laserStartPosition = transform.position; if(lockedCamera) { targetAcquired = true; targetPosition = lastLaserPoint = lockedCamera.groundTargetPosition; targetingPod = lockedCamera; } } else if(targetingMode == TargetingModes.AntiRad && targetAcquired) { RadarWarningReceiver.OnRadarPing += ReceiveRadarPing; } part.decouple(0); part.force_activate(); part.Unpack(); vessel.situation = Vessel.Situations.FLYING; part.rb.isKinematic = false; BDArmorySettings.Instance.ApplyNewVesselRanges(vessel); part.bodyLiftMultiplier = 0; part.dragModel = Part.DragModel.NONE; //add target info to vessel TargetInfo info = vessel.gameObject.AddComponent<TargetInfo>(); info.team = BDATargetManager.BoolToTeam(team); info.isMissile = true; info.missileModule = this; StartCoroutine(DecoupleRoutine()); vessel.vesselName = GetShortName(); vessel.vesselType = VesselType.Probe; timeFired = Time.time; //setting ref transform for navball GameObject refObject = new GameObject(); refObject.transform.rotation = Quaternion.LookRotation(-transform.up, transform.forward); refObject.transform.parent = transform; part.SetReferenceTransform(refObject.transform); vessel.SetReferenceTransform(part); vesselReferenceTransform = refObject.transform; MissileState = MissileStates.Drop; part.crashTolerance = 9999; StartCoroutine(MissileRoutine()); } }
public static TargetSignatureData GetHeatTarget(Ray ray, float scanRadius, float highpassThreshold, bool allAspect, MissileFire mf = null) { float minScore = highpassThreshold; float minMass = 0.5f; TargetSignatureData finalData = TargetSignatureData.noTarget; float finalScore = 0; foreach(var vessel in BDATargetManager.LoadedVessels) { if(!vessel || !vessel.loaded) { continue; } TargetInfo tInfo = vessel.gameObject.GetComponent<TargetInfo>(); if(mf == null || !tInfo || !(mf && tInfo.isMissile && tInfo.team != BDATargetManager.BoolToTeam(mf.team) && (tInfo.missileModule.MissileState == MissileLauncher.MissileStates.Boost || tInfo.missileModule.MissileState == MissileLauncher.MissileStates.Cruise))) { if(vessel.GetTotalMass() < minMass) { continue; } } if(RadarUtils.TerrainCheck(ray.origin, vessel.transform.position)) { continue; } float angle = Vector3.Angle(vessel.CoM-ray.origin, ray.direction); if(angle < scanRadius) { float score = 0; foreach(var part in vessel.Parts) { if(!part) continue; if(!allAspect) { if(!Misc.CheckSightLineExactDistance(ray.origin, part.transform.position+vessel.rb_velocity, Vector3.Distance(part.transform.position,ray.origin), 5, 5)) continue; } float thisScore = (float)(part.thermalInternalFluxPrevious+part.skinTemperature) * (15/Mathf.Max(15,angle)); thisScore *= Mathf.Pow(1400,2)/Mathf.Clamp((vessel.CoM-ray.origin).sqrMagnitude, 90000, 36000000); score = Mathf.Max (score, thisScore); } if(vessel.LandedOrSplashed) { score /= 4; } score *= Mathf.Clamp(Vector3.Angle(vessel.transform.position-ray.origin, -VectorUtils.GetUpDirection(ray.origin))/90, 0.5f, 1.5f); if(score > finalScore) { finalScore = score; finalData = new TargetSignatureData(vessel, score); } } } heatScore = finalScore;//DEBUG flareScore = 0; //DEBUG foreach(var flare in BDArmorySettings.Flares) { if(!flare) continue; float angle = Vector3.Angle(flare.transform.position-ray.origin, ray.direction); if(angle < scanRadius) { float score = flare.thermal * Mathf.Clamp01(15/angle); score *= Mathf.Pow(1400,2)/Mathf.Clamp((flare.transform.position-ray.origin).sqrMagnitude, 90000, 36000000); score *= Mathf.Clamp(Vector3.Angle(flare.transform.position-ray.origin, -VectorUtils.GetUpDirection(ray.origin))/90, 0.5f, 1.5f); if(score > finalScore) { flareScore = score;//DEBUG finalScore = score; finalData = new TargetSignatureData(flare, score); } } } if(finalScore < minScore) { finalData = TargetSignatureData.noTarget; } return finalData; }
IEnumerator LaunchWarningRoutine(TargetSignatureData data) { launchWarnings.Add(data); yield return new WaitForSeconds(2); launchWarnings.Remove(data); }
public void SendTargetDataToMissile(MissileLauncher ml) { if(ml.targetingMode == MissileLauncher.TargetingModes.Laser && laserPointDetected) { ml.lockedCamera = foundCam; } else if(ml.targetingMode == MissileLauncher.TargetingModes.GPS) { if(BDArmorySettings.ALLOW_LEGACY_TARGETING) { if(vessel.targetObject != null && vessel.targetObject.GetVessel() != null) { ml.targetAcquired = true; ml.legacyTargetVessel = vessel.targetObject.GetVessel(); } } else if(designatedGPSCoords != Vector3d.zero) { ml.targetGPSCoords = designatedGPSCoords; ml.targetAcquired = true; } } else if(ml.targetingMode == MissileLauncher.TargetingModes.Heat && heatTarget.exists) { ml.heatTarget = heatTarget; heatTarget = TargetSignatureData.noTarget; } else if(ml.targetingMode == MissileLauncher.TargetingModes.Radar && radar && radar.lockedTarget.exists) { ml.radarTarget = radar.lockedTarget; if(radar.linked && radar.linkedRadar.locked) { ml.radar = radar.linkedRadar; } else { ml.radar = radar; } radar.lastMissile = ml; } else if(ml.targetingMode == MissileLauncher.TargetingModes.AntiRad && antiRadTargetAcquired) { ml.targetAcquired = true; ml.targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(antiRadiationTarget, vessel.mainBody); } }
void BoresightScan() { currentAngle = Mathf.Lerp(currentAngle, 0, 0.08f); RadarUtils.ScanInDirection (new Ray (transform.position, transform.up), boresightFOV, minSignalThreshold * 5, ref attemptedLocks, Time.fixedDeltaTime, true, rwrType, true); for(int i = 0; i < attemptedLocks.Length; i++) { if(attemptedLocks[i].exists && attemptedLocks[i].age < 0.1f) { locked = true; lockedTarget = attemptedLocks[i]; Debug.Log ("- Acquired lock on target."); boresightScan = false; return; } } }
protected void UpdateRadarTarget() { TargetAcquired = false; float angleToTarget = Vector3.Angle(radarTarget.predictedPosition - transform.position, GetForwardTransform()); if (radarTarget.exists) { // locked-on before launch, passive radar guidance or waiting till in active radar range: if (!ActiveRadar && ((radarTarget.predictedPosition - transform.position).sqrMagnitude > Mathf.Pow(activeRadarRange, 2) || angleToTarget > maxOffBoresight * 0.75f)) { if (vrd) { TargetSignatureData t = TargetSignatureData.noTarget; List <TargetSignatureData> possibleTargets = vrd.GetLockedTargets(); for (int i = 0; i < possibleTargets.Count; i++) { if (possibleTargets[i].vessel == radarTarget.vessel) { t = possibleTargets[i]; } } if (t.exists) { TargetAcquired = true; radarTarget = t; TargetPosition = radarTarget.predictedPositionWithChaffFactor; TargetVelocity = radarTarget.velocity; TargetAcceleration = radarTarget.acceleration; _radarFailTimer = 0; return; } else { if (_radarFailTimer > maxRadarFailTime) { Debug.Log("[BDArmory]: Semi-Active Radar guidance failed. Parent radar lost target."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } else { if (_radarFailTimer == 0) { Debug.Log("[BDArmory]: Semi-Active Radar guidance failed - waiting for data"); } _radarFailTimer += Time.fixedDeltaTime; radarTarget.timeAcquired = Time.time; radarTarget.position = radarTarget.predictedPosition; TargetPosition = radarTarget.predictedPositionWithChaffFactor; TargetVelocity = radarTarget.velocity; TargetAcceleration = Vector3.zero; TargetAcquired = true; } } } else { Debug.Log("[BDArmory]: Semi-Active Radar guidance failed. Out of range and no data feed."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } } else { // active radar with target locked: vrd = null; if (angleToTarget > maxOffBoresight) { Debug.Log("[BDArmory]: Active Radar guidance failed. Target is out of active seeker gimbal limits."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } else { if (scannedTargets == null) { scannedTargets = new TargetSignatureData[5]; } TargetSignatureData.ResetTSDArray(ref scannedTargets); Ray ray = new Ray(transform.position, radarTarget.predictedPosition - transform.position); bool pingRWR = Time.time - lastRWRPing > 0.4f; if (pingRWR) { lastRWRPing = Time.time; } bool radarSnapshot = (snapshotTicker > 10); if (radarSnapshot) { snapshotTicker = 0; } else { snapshotTicker++; } //RadarUtils.UpdateRadarLock(ray, lockedSensorFOV, activeRadarMinThresh, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); RadarUtils.RadarUpdateMissileLock(ray, lockedSensorFOV, ref scannedTargets, 0.4f, this); float sqrThresh = radarLOALSearching ? Mathf.Pow(500, 2) : Mathf.Pow(40, 2); if (radarLOAL && radarLOALSearching && !radarSnapshot) { //only scan on snapshot interval } else { for (int i = 0; i < scannedTargets.Length; i++) { if (scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) { //re-check engagement envelope, only lock appropriate targets if (CheckTargetEngagementEnvelope(scannedTargets[i].targetInfo)) { radarTarget = scannedTargets[i]; TargetAcquired = true; radarLOALSearching = false; TargetPosition = radarTarget.predictedPositionWithChaffFactor + (radarTarget.velocity * Time.fixedDeltaTime); TargetVelocity = radarTarget.velocity; TargetAcceleration = radarTarget.acceleration; _radarFailTimer = 0; if (!ActiveRadar && Time.time - TimeFired > 1) { if (locksCount == 0) { if (weaponClass == WeaponClasses.SLW) { RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.Torpedo, 2f); } else { RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); } Debug.Log("[BDArmory]: Pitbull! Radar missilebase has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); } else if (locksCount > 2) { guidanceActive = false; checkMiss = true; if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory]: Active Radar guidance failed. Radar missileBase reached max re-lock attempts."); } } locksCount++; } ActiveRadar = true; return; } } } } if (radarLOAL) { radarLOALSearching = true; TargetAcquired = true; TargetPosition = radarTarget.predictedPositionWithChaffFactor + (radarTarget.velocity * Time.fixedDeltaTime); TargetVelocity = radarTarget.velocity; TargetAcceleration = Vector3.zero; ActiveRadar = false; _radarFailTimer = 0; } else { Debug.Log("[BDArmory]: Active Radar guidance failed. No target locked."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; radarLOALSearching = false; TargetAcquired = false; ActiveRadar = false; } } } } else if (radarLOAL && radarLOALSearching) { // not locked on before launch, trying lock-on after launch: if (scannedTargets == null) { scannedTargets = new TargetSignatureData[5]; } TargetSignatureData.ResetTSDArray(ref scannedTargets); Ray ray = new Ray(transform.position, GetForwardTransform()); bool pingRWR = Time.time - lastRWRPing > 0.4f; if (pingRWR) { lastRWRPing = Time.time; } bool radarSnapshot = (snapshotTicker > 5); if (radarSnapshot) { snapshotTicker = 0; } else { snapshotTicker++; } //RadarUtils.UpdateRadarLock(ray, lockedSensorFOV * 3, activeRadarMinThresh * 2, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); RadarUtils.RadarUpdateMissileLock(ray, lockedSensorFOV * 3, ref scannedTargets, 0.4f, this); float sqrThresh = Mathf.Pow(300, 2); float smallestAngle = 360; TargetSignatureData lockedTarget = TargetSignatureData.noTarget; for (int i = 0; i < scannedTargets.Length; i++) { if (scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) { //re-check engagement envelope, only lock appropriate targets if (CheckTargetEngagementEnvelope(scannedTargets[i].targetInfo)) { float angle = Vector3.Angle(scannedTargets[i].predictedPosition - transform.position, GetForwardTransform()); if (angle < smallestAngle) { lockedTarget = scannedTargets[i]; smallestAngle = angle; } ActiveRadar = true; return; } } } if (lockedTarget.exists) { radarTarget = lockedTarget; TargetAcquired = true; radarLOALSearching = false; TargetPosition = radarTarget.predictedPositionWithChaffFactor + (radarTarget.velocity * Time.fixedDeltaTime); TargetVelocity = radarTarget.velocity; TargetAcceleration = radarTarget.acceleration; if (!ActiveRadar && Time.time - TimeFired > 1) { if (weaponClass == WeaponClasses.SLW) { RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.Torpedo, 2f); } else { RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); } Debug.Log("[BDArmory]: Pitbull! Radar missileBase has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); } return; } else { TargetAcquired = true; TargetPosition = transform.position + (startDirection * 500); TargetVelocity = Vector3.zero; TargetAcceleration = Vector3.zero; radarLOALSearching = true; _radarFailTimer += Time.fixedDeltaTime; if (_radarFailTimer > maxRadarFailTime) { Debug.Log("[BDArmory]: Active Radar guidance failed. LOAL could not lock a target."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; radarLOALSearching = false; TargetAcquired = false; ActiveRadar = false; } return; } } if (!radarTarget.exists) { legacyTargetVessel = null; } }
void DrawScannedContacts(ref TargetSignatureData[] scannedContacts, Rect radarRect) { float myAlt = (float)vessel.altitude; for (int i = 0; i < scannedContacts.Length; i++) { if(scannedContacts[i].exists)// && scannedContacts[i].signalStrength > minSignalThreshold) { //ignore old target data if(scannedContacts[i].age > signalPersistTime) { scannedContacts[i].exists = false; continue; } //ignore targets outside of directional field of view if(!omnidirectional && !linked && Vector3.Angle(scannedContacts[i].position - transform.position, transform.up) > directionalFieldOfView) { scannedContacts[i].exists = false; continue; } //ignore locked target if tracking while scanning if((canTrackWhileScan||(linked&&linkedRadar&&linkedRadar.canTrackWhileScan)) && locked && (scannedContacts[i].predictedPosition - lockedTarget.predictedPosition).sqrMagnitude < 100) { scannedContacts[i].exists = false; continue; } float minusAlpha = (Mathf.Clamp01((Time.time - scannedContacts[i].timeAcquired) / signalPersistTime) * 2) - 1; //dont draw self if reading remote data if(linked && (scannedContacts[i].predictedPosition - transform.position).sqrMagnitude < Mathf.Pow(50, 2)) { minusAlpha = 1; continue; } //jamming bool jammed = false; if(scannedContacts[i].vesselJammer && scannedContacts[i].vesselJammer.jammerStrength > scannedContacts[i].signalStrength) { jammed = true; } Vector2 pingPosition; if(pingPositionsDirty || scannedContacts[i].pingPosition == Vector2.zero) { if(omnidirectional || linked) { pingPosition = RadarUtils.WorldToRadar(scannedContacts[i].position, referenceTransform, radarRect, rIncrements[rangeIndex]); } else { pingPosition = RadarUtils.WorldToRadarRadial(scannedContacts[i].position, referenceTransform, radarRect, rIncrements[rangeIndex], directionalFieldOfView / 2); } scannedContacts[i].pingPosition = pingPosition; } else { pingPosition = scannedContacts[i].pingPosition; } Rect pingRect; //draw missiles and debris as dots if((scannedContacts[i].targetInfo && scannedContacts[i].targetInfo.isMissile) || scannedContacts[i].team == BDArmorySettings.BDATeams.None) { float mDotSize = 6; pingRect = new Rect(pingPosition.x - (mDotSize / 2), pingPosition.y - (mDotSize / 2), mDotSize, mDotSize); Color origGUIColor = GUI.color; GUI.color = Color.white - new Color(0, 0, 0, minusAlpha); GUI.DrawTexture(pingRect, BDArmorySettings.Instance.greenDotTexture, ScaleMode.StretchToFill, true); GUI.color = origGUIColor; } //draw contacts with direction indicator else if(!jammed && (showDirectionWhileScan || (linked&&linkedRadar&&linkedRadar.showDirectionWhileScan)) && scannedContacts[i].velocity.sqrMagnitude > 100) { pingRect = new Rect(pingPosition.x - (lockIconSize / 2), pingPosition.y - (lockIconSize / 2), lockIconSize, lockIconSize); float vAngle = Vector3.Angle(Vector3.ProjectOnPlane(scannedContacts[i].velocity, referenceTransform.up), referenceTransform.forward); if(referenceTransform.InverseTransformVector(scannedContacts[i].velocity).x < 0) { vAngle = -vAngle; } GUIUtility.RotateAroundPivot(vAngle, pingPosition); Color origGUIColor = GUI.color; GUI.color = Color.white - new Color(0, 0, 0, minusAlpha); if(weaponManager && scannedContacts[i].team == BDATargetManager.BoolToTeam(weaponManager.team)) { GUI.DrawTexture(pingRect, friendlyContactIcon, ScaleMode.StretchToFill, true); } else { GUI.DrawTexture(pingRect, radarContactIcon, ScaleMode.StretchToFill, true); } GUI.matrix = Matrix4x4.identity; GUI.Label(new Rect(pingPosition.x + (lockIconSize * 0.35f) + 2, pingPosition.y, 100, 24), (scannedContacts[i].altitude / 1000).ToString("0"), distanceStyle); GUI.color = origGUIColor; } else //draw contacts as rectangles { int drawCount = jammed ? 4 : 1; pingRect = new Rect(pingPosition.x - (pingSize.x / 2), pingPosition.y - (pingSize.y / 2), pingSize.x, pingSize.y); for(int d = 0; d < drawCount; d++) { Rect jammedRect = new Rect(pingRect); Vector3 contactPosition = scannedContacts[i].position; if(jammed) { //jamming Vector3 jammedPosition = transform.position + ((scannedContacts[i].position - transform.position).normalized * UnityEngine.Random.Range(100, rIncrements[rangeIndex])); float bearingVariation = Mathf.Clamp(Mathf.Pow(32000, 2) / (scannedContacts[i].position - transform.position).sqrMagnitude, 0, 80); jammedPosition = transform.position + (Quaternion.AngleAxis(UnityEngine.Random.Range(-bearingVariation, bearingVariation), referenceTransform.up) * (jammedPosition - transform.position)); if(omnidirectional || linked) { pingPosition = RadarUtils.WorldToRadar(jammedPosition, referenceTransform, radarRect, rIncrements[rangeIndex]); } else { pingPosition = RadarUtils.WorldToRadarRadial(jammedPosition, referenceTransform, radarRect, rIncrements[rangeIndex], directionalFieldOfView / 2); } jammedRect = new Rect(pingPosition.x - (pingSize.x / 2), pingPosition.y - (pingSize.y / 2) - (pingSize.y / 3), pingSize.x, pingSize.y / 3); contactPosition = jammedPosition; } Color iconColor = Color.green; float contactAlt = scannedContacts[i].altitude; if(!omnidirectional && !jammed) { if(contactAlt - myAlt > 1000) { iconColor = new Color(0, 0.6f, 1f, 1); } else if(contactAlt - myAlt < -1000) { iconColor = new Color(1f, 0.68f, 0, 1); } } if(omnidirectional) { Vector3 localPos = referenceTransform.InverseTransformPoint(contactPosition); localPos.y = 0; float angleToContact = Vector3.Angle(localPos, Vector3.forward); if(localPos.x < 0) angleToContact = -angleToContact; GUIUtility.RotateAroundPivot(angleToContact, pingPosition); } BDGUIUtils.DrawRectangle(jammedRect, iconColor - new Color(0, 0, 0, minusAlpha)); GUI.matrix = Matrix4x4.identity; } } if(GUI.RepeatButton(pingRect, GUIContent.none, GUIStyle.none)) { TryLockTarget(scannedContacts[i].predictedPosition); if(Event.current.isMouse && Event.current.type == EventType.mouseDown) { Event.current.Use(); } } if(BDArmorySettings.DRAW_DEBUG_LABELS) { GUI.Label(new Rect(pingPosition.x + (pingSize.x / 2), pingPosition.y, 100, 24), scannedContacts[i].signalStrength.ToString("0.0")); } } } pingPositionsDirty = false; }
public void ReceiveContactData(TargetSignatureData contactData, bool _locked) { if(vesselRadarData) { vesselRadarData.AddRadarContact(this, contactData, _locked); } foreach(var vrd in linkedToVessels) { if(vrd && vrd.canReceiveRadarData && vrd.vessel!=contactData.vessel) { vrd.AddRadarContact(this, contactData, _locked); } } }
void LinkToRadar(ModuleRadar mr) { if(!mr) { return; } linkedRadar = mr; linkedVesselID = mr.vessel.id.ToString(); linked = true; if(mr.locked) { locked = true; lockedTarget = mr.lockedTarget; } CloseLinkRadarWindow(); }
public void UpdateLockedTargetInfo(TargetSignatureData newData) { int index = -1; for(int i = 0; i < lockedTargets.Count; i++) { if(lockedTargets[i].vessel == newData.vessel) { index = i; break; } } if(index >= 0) { lockedTargets[index] = newData; } }
void UpdateHeatTarget() { targetAcquired = false; if(heatTarget.exists && lockFailTimer < 0) { lockFailTimer = 0; } if(lockFailTimer >= 0 && lockFailTimer < 1) { Ray lookRay = new Ray(transform.position, heatTarget.position+(heatTarget.velocity*Time.fixedDeltaTime)-transform.position); heatTarget = BDATargetManager.GetHeatTarget(lookRay, lockedSensorFOV/2, heatThreshold, allAspect); if(heatTarget.exists) { targetAcquired = true; targetPosition = heatTarget.position+(heatTarget.velocity*Time.fixedDeltaTime); targetVelocity = heatTarget.velocity; targetAcceleration = heatTarget.acceleration; lockFailTimer = 0; } else { if(FlightGlobals.ready) { lockFailTimer += Time.fixedDeltaTime; } } } if(lockFailTimer > 1) { legacyTargetVessel = null; } }
public static void UpdateRadarLock(Ray ray, float fov, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType, bool radarSnapshot) { int dataIndex = 0; foreach(var vessel in BDATargetManager.LoadedVessels) { if(vessel == null) continue; if(!vessel.loaded) continue; //if(vessel.Landed) continue; Vector3 vectorToTarget = vessel.transform.position - ray.origin; if((vectorToTarget).sqrMagnitude < 10) continue; //ignore self if(Vector3.Dot(vectorToTarget, ray.direction) < 0) continue; //ignore behind ray if(Vector3.Angle(vessel.CoM - ray.origin, ray.direction) < fov / 2) { if(TerrainCheck(ray.origin, vessel.transform.position)) continue; //blocked by terrain float sig = float.MaxValue; if(radarSnapshot) sig = GetModifiedSignature(vessel, ray.origin); if(pingRWR && sig > minSignature * 0.66f) { RadarWarningReceiver.PingRWR(vessel, ray.origin, rwrType, dataPersistTime); } if(sig > minSignature) { while(dataIndex < dataArray.Length - 1) { if((dataArray[dataIndex].exists && Time.time - dataArray[dataIndex].timeAcquired > dataPersistTime) || !dataArray[dataIndex].exists) { break; } dataIndex++; } if(dataIndex >= dataArray.Length) break; dataArray[dataIndex] = new TargetSignatureData(vessel, sig); dataIndex++; if(dataIndex >= dataArray.Length) break; } } } }
void UpdateLock(int index) { TargetSignatureData lockedTarget = lockedTargets[index]; Vector3 targetPlanarDirection = Vector3.ProjectOnPlane(lockedTarget.predictedPosition - referenceTransform.position, referenceTransform.up); float lookAngle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); if (referenceTransform.InverseTransformPoint(lockedTarget.predictedPosition).x < 0) { lookAngle = -lookAngle; } if (omnidirectional) { if (lookAngle < 0) { lookAngle += 360; } } lockScanAngle = lookAngle + currentAngleLock; if (!canTrackWhileScan && index == lockedTargetIndex) { currentAngle = lockScanAngle; } float angleDelta = lockRotationSpeed * Time.fixedDeltaTime; float lockedSignalPersist = lockRotationAngle / lockRotationSpeed; //RadarUtils.ScanInDirection(lockScanAngle, referenceTransform, angleDelta, referenceTransform.position, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist); bool radarSnapshot = (snapshotTicker > 30); if (radarSnapshot) { snapshotTicker = 0; } else { snapshotTicker++; } //RadarUtils.ScanInDirection (new Ray (referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), lockRotationAngle * 2, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist, true, rwrType, radarSnapshot); if ( Vector3.Angle(lockedTarget.position - referenceTransform.position, this.lockedTarget.position - referenceTransform.position) > multiLockFOV / 2) { UnlockTargetAt(index, true); return; } RadarUtils.RadarUpdateLockTrack( new Ray(referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), lockedTarget.predictedPosition, lockRotationAngle * 2, this, lockedSignalPersist, true, index, lockedTarget.vessel); //if still failed or out of FOV, unlock. if (!lockedTarget.exists || (!omnidirectional && Vector3.Angle(lockedTarget.position - referenceTransform.position, transform.up) > directionalFieldOfView / 2)) { //UnlockAllTargets(); UnlockTargetAt(index, true); return; } //unlock if over-jammed // MOVED TO RADARUTILS! //cycle scan direction if (index == lockedTargetIndex) { currentAngleLock += lockScanDirection * angleDelta; if (Mathf.Abs(currentAngleLock) > lockRotationAngle / 2) { currentAngleLock = Mathf.Sign(currentAngleLock) * lockRotationAngle / 2; lockScanDirection = -lockScanDirection; } } }
void ReceivePing(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime) { if (v == null) { return; } if (referenceTransform == null) { return; } if (weaponManager == null) { return; } if (rwrEnabled && vessel && v == vessel) { //if we are airborne or on land, no Sonar or SLW type weapons on the RWR! if ((type == RWRThreatTypes.Torpedo || type == RWRThreatTypes.TorpedoLock || type == RWRThreatTypes.Sonar) && (vessel.situation != Vessel.Situations.SPLASHED)) { // rwr stays silent... return; } if (type == RWRThreatTypes.MissileLaunch || type == RWRThreatTypes.Torpedo) { StartCoroutine( LaunchWarningRoutine(new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange), Vector3.zero, true, (float)type))); PlayWarningSound(type, (source - vessel.transform.position).sqrMagnitude); return; } else if (type == RWRThreatTypes.MissileLock) { if (weaponManager && weaponManager.guardMode) { weaponManager.FireChaff(); // TODO: if torpedo inbound, also fire accoustic decoys (not yet implemented...) } } int openIndex = -1; for (int i = 0; i < dataCount; i++) { if (pingsData[i].exists && ((Vector2)pingsData[i].position - RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange)).sqrMagnitude < 900f) //prevent ping spam { break; } if (!pingsData[i].exists && openIndex == -1) { openIndex = i; } } if (openIndex >= 0) { referenceTransform.rotation = Quaternion.LookRotation(vessel.ReferenceTransform.up, VectorUtils.GetUpDirection(transform.position)); pingsData[openIndex] = new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange), Vector3.zero, true, (float)type); // HACK! Evil misuse of signalstrength for the threat type! pingWorldPositions[openIndex] = source; StartCoroutine(PingLifeRoutine(openIndex, persistTime)); PlayWarningSound(type, (source - vessel.transform.position).sqrMagnitude); } } }
public static void ScanInDirection(Ray ray, float fov, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType) { int dataIndex = 0; foreach(var vessel in FlightGlobals.Vessels) { if(vessel && vessel.loaded && !vessel.Landed) { if((vessel.transform.position-ray.origin).sqrMagnitude < 10) continue; //ignore self if(TerrainCheck(ray.origin, vessel.transform.position)) continue; //blocked by terrain if(Vector3.Angle(vessel.CoM-ray.origin, ray.direction) < fov/2) { float sig = GetModifiedSignature(vessel, ray.origin); if(pingRWR && sig > minSignature * 0.66f) { RadarWarningReceiver.PingRWR(vessel, ray.origin, rwrType, dataPersistTime); } if(sig > minSignature) { TargetInfo ti = vessel.GetComponent<TargetInfo>(); if(!ti) { vessel.gameObject.AddComponent<TargetInfo>(); } while(dataIndex < dataArray.Length-1) { if((dataArray[dataIndex].exists && Time.time-dataArray[dataIndex].timeAcquired > dataPersistTime) || !dataArray[dataIndex].exists) { break; } dataIndex++; } if(dataIndex >= dataArray.Length) break; dataArray[dataIndex] = new TargetSignatureData(vessel, sig); dataIndex++; if(dataIndex >= dataArray.Length) break; } } } } }
public static TargetSignatureData GetHeatTarget(Ray ray, float scanRadius, float highpassThreshold, bool allAspect, MissileFire mf = null, bool favorGroundTargets = false) { float minMass = 0.05f; //otherwise the RAMs have trouble shooting down incoming missiles TargetSignatureData finalData = TargetSignatureData.noTarget; float finalScore = 0; foreach (Vessel vessel in LoadedVessels) { if (!vessel || !vessel.loaded) { continue; } if (favorGroundTargets && !vessel.LandedOrSplashed) // for AGM heat guidance { continue; } TargetInfo tInfo = vessel.gameObject.GetComponent <TargetInfo>(); if (mf == null || !tInfo || !(mf && tInfo.isMissile && tInfo.team != BoolToTeam(mf.team) && (tInfo.MissileBaseModule.MissileState == MissileBase.MissileStates.Boost || tInfo.MissileBaseModule.MissileState == MissileBase.MissileStates.Cruise))) { if (vessel.GetTotalMass() < minMass) { continue; } } float angle = Vector3.Angle(vessel.CoM - ray.origin, ray.direction); if (angle < scanRadius) { if (RadarUtils.TerrainCheck(ray.origin, vessel.transform.position)) { continue; } if (!allAspect) { if (!Misc.Misc.CheckSightLineExactDistance(ray.origin, vessel.CoM + vessel.Velocity(), Vector3.Distance(vessel.CoM, ray.origin), 5, 5)) { continue; } } float score = GetVesselHeatSignature(vessel) * Mathf.Clamp01(15 / angle); score *= Mathf.Pow(1400, 2) / Mathf.Clamp((vessel.CoM - ray.origin).sqrMagnitude, 90000, 36000000); if (vessel.LandedOrSplashed && !favorGroundTargets) { score /= 4; } score *= Mathf.Clamp(Vector3.Angle(vessel.transform.position - ray.origin, -VectorUtils.GetUpDirection(ray.origin)) / 90, 0.5f, 1.5f); if (score > finalScore) { finalScore = score; finalData = new TargetSignatureData(vessel, score); } } } // see if there are flares decoying us: TargetSignatureData flareData = GetFlareTarget(ray, scanRadius, highpassThreshold, allAspect, finalScore); if (finalScore < highpassThreshold) { finalData = TargetSignatureData.noTarget; } // return matching flare if (!flareData.Equals(TargetSignatureData.noTarget)) { return(flareData); } //else return the target: return(finalData); }
void SearchForHeatTarget() { MissileLauncher ml = currentMissile; if(!ml || ml.targetingMode != MissileLauncher.TargetingModes.Heat) { return; } float scanRadius = ml.lockedSensorFOV*2; float maxOffBoresight = ml.maxOffBoresight*0.85f; bool radarSlaved = false; if(radar && radar.radarEnabled && radar.locked) { heatTarget = radar.lockedTarget; radarSlaved = true; } Vector3 direction = heatTarget.exists && Vector3.Angle(heatTarget.position - ml.transform.position, ml.transform.forward) < maxOffBoresight ? heatTarget.predictedPosition - ml.transform.position : ml.transform.forward; float heatThresh = radarSlaved ? ml.heatThreshold*0.5f : ml.heatThreshold; heatTarget = BDATargetManager.GetHeatTarget(new Ray(ml.transform.position, direction), scanRadius, ml.heatThreshold, ml.allAspect); }
void UpdateLegacyTarget() { if(legacyTargetVessel) { maxOffBoresight = 90; if(targetingMode == TargetingModes.Radar) { activeRadarRange = 20000; targetAcquired = true; radarTarget = new TargetSignatureData(legacyTargetVessel, 500); return; } else if(targetingMode == TargetingModes.Heat) { targetAcquired = true; heatTarget = new TargetSignatureData(legacyTargetVessel, 500); return; } targetAcquired = true; targetPosition = legacyTargetVessel.CoM + (legacyTargetVessel.rb_velocity*Time.fixedDeltaTime); targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(targetPosition, vessel.mainBody); targetVelocity = legacyTargetVessel.srf_velocity; targetAcceleration = legacyTargetVessel.acceleration; lastLaserPoint = targetPosition; lockFailTimer = 0; } }
void ReceivePing(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime) { if(rwrEnabled && vessel && v == vessel) { if(type == RWRThreatTypes.MissileLaunch) { StartCoroutine(LaunchWarningRoutine(new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange), Vector3.zero, true, (float)type))); PlayWarningSound(type); return; } else if(type == RWRThreatTypes.MissileLock) { if(!BDArmorySettings.ALLOW_LEGACY_TARGETING && weaponManager && weaponManager.guardMode) { weaponManager.FireChaff(); } } int openIndex = -1; for(int i = 0; i < dataCount; i++) { if(pingsData[i].exists && ((Vector2)pingsData[i].position - RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange)).sqrMagnitude < Mathf.Pow(20, 2)) { break; } if(!pingsData[i].exists && openIndex == -1) { openIndex = i; } } if(openIndex >= 0) { referenceTransform.rotation = Quaternion.LookRotation(vessel.ReferenceTransform.up, VectorUtils.GetUpDirection(transform.position)); pingsData[openIndex] = new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange), Vector3.zero, true, (float)type); pingWorldPositions[openIndex] = source; StartCoroutine(PingLifeRoutine(openIndex, persistTime)); PlayWarningSound(type); } } }
public override void OnStart(StartState state) { base.OnStart(state); if (HighLogic.LoadedSceneIsFlight) { myVesselID = vessel.id.ToString(); RadarUtils.SetupResources(); if (string.IsNullOrEmpty(radarName)) { radarName = part.partInfo.title; } linkedToVessels = new List <VesselRadarData>(); signalPersistTime = omnidirectional ? 360 / (scanRotationSpeed + 5) : directionalFieldOfView / (scanRotationSpeed + 5); rwrType = (RadarWarningReceiver.RWRThreatTypes)rwrThreatType; if (rwrType == RadarWarningReceiver.RWRThreatTypes.Sonar) { signalPersistTimeForRwr = RadarUtils.ACTIVE_MISSILE_PING_PERISTS_TIME; } else { signalPersistTimeForRwr = signalPersistTime / 2; } if (rotationTransformName != string.Empty) { rotationTransform = part.FindModelTransform(rotationTransformName); } attemptedLocks = new TargetSignatureData[3]; TargetSignatureData.ResetTSDArray(ref attemptedLocks); lockedTargets = new List <TargetSignatureData>(); referenceTransform = (new GameObject()).transform; referenceTransform.parent = transform; referenceTransform.localPosition = Vector3.zero; List <ModuleTurret> .Enumerator turr = part.FindModulesImplementing <ModuleTurret>().GetEnumerator(); while (turr.MoveNext()) { if (turr.Current == null) { continue; } if (turr.Current.turretID != turretID) { continue; } lockingTurret = turr.Current; break; } turr.Dispose(); //GameEvents.onVesselGoOnRails.Add(OnGoOnRails); //not needed EnsureVesselRadarData(); StartCoroutine(StartUpRoutine()); } else if (HighLogic.LoadedSceneIsEditor) { //Editor only: List <ModuleTurret> .Enumerator tur = part.FindModulesImplementing <ModuleTurret>().GetEnumerator(); while (tur.MoveNext()) { if (tur.Current == null) { continue; } if (tur.Current.turretID != turretID) { continue; } lockingTurret = tur.Current; break; } tur.Dispose(); if (lockingTurret) { lockingTurret.Fields["minPitch"].guiActiveEditor = false; lockingTurret.Fields["maxPitch"].guiActiveEditor = false; lockingTurret.Fields["yawRange"].guiActiveEditor = false; } } // check for not updated legacy part: if ((canScan && (radarMinDistanceDetect == float.MaxValue)) || (canLock && (radarMinDistanceLockTrack == float.MaxValue))) { Debug.Log("[BDArmory]: WARNING: " + part.name + " has legacy definition, missing new radarDetectionCurve and radarLockTrackCurve definitions! Please update for the part to be usable!"); } }
void UpdateRadarTarget() { targetAcquired = false; float angleToTarget = Vector3.Angle(radarTarget.position-transform.position,transform.forward); if(radarTarget.exists) { if((radarTarget.predictedPosition-transform.position).sqrMagnitude > Mathf.Pow(activeRadarRange, 2) || angleToTarget > maxOffBoresight*0.75f) { if(radar && radar.lockedTarget.exists && (radarTarget.predictedPosition-radar.lockedTarget.predictedPosition).sqrMagnitude<Mathf.Pow(100,2) && (radar.transform.position-transform.position).sqrMagnitude < Mathf.Pow(activeRadarRange,2)) { targetAcquired = true; radarTarget = radar.lockedTarget; targetPosition = radarTarget.predictedPosition; targetVelocity = radarTarget.velocity; targetAcceleration = radarTarget.acceleration; //radarTarget.signalStrength = return; } else { Debug.Log ("Radar guidance failed. Out of range and no data feed."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } } else { radar = null; if(angleToTarget > maxOffBoresight) { Debug.Log ("Radar guidance failed. Target is out of active seeker gimbal limits."); radarTarget = TargetSignatureData.noTarget; legacyTargetVessel = null; return; } else { if(scannedTargets == null) scannedTargets = new TargetSignatureData[5]; TargetSignatureData.ResetTSDArray(ref scannedTargets); Ray ray = new Ray(transform.position,radarTarget.predictedPosition-transform.position); bool pingRWR = Time.time - lastRWRPing > 0.4f; if(pingRWR) lastRWRPing = Time.time; RadarUtils.ScanInDirection(ray, lockedSensorFOV, 100, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock); for(int i = 0; i < scannedTargets.Length; i++) { if(scannedTargets[i].exists && (scannedTargets[i].predictedPosition-radarTarget.predictedPosition).sqrMagnitude < Mathf.Pow(20,2)) { radarTarget = scannedTargets[i]; targetAcquired = true; targetPosition = radarTarget.predictedPosition + (radarTarget.velocity*Time.fixedDeltaTime); targetVelocity = radarTarget.velocity; targetAcceleration = radarTarget.acceleration; if(!activeRadar) { activeRadar = true; RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); Debug.Log ("Pitbull! Radar missile has gone active. Radar sig strength: "+radarTarget.signalStrength.ToString("0.0")); } return; } } radarTarget = TargetSignatureData.noTarget; } } } if(!radarTarget.exists) { legacyTargetVessel = null; } }
public void FireMissile() { if(!hasFired) { if(GetComponentInChildren<KSPParticleEmitter>()) { BDArmorySettings.numberOfParticleEmitters++; } foreach(var wpm in vessel.FindPartModulesImplementing<MissileFire>()) { team = wpm.team; break; } sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/deployClick")); sourceVessel = vessel; //TARGETING if(BDArmorySettings.ALLOW_LEGACY_TARGETING) { if(vessel.targetObject!=null && vessel.targetObject.GetVessel()!=null) { legacyTargetVessel = vessel.targetObject.GetVessel(); if(targetingMode == TargetingModes.Heat) { heatTarget = new TargetSignatureData(legacyTargetVessel, 9999); } } } if(targetingMode == TargetingModes.Laser) { laserStartPosition = transform.position; laserStartDirection = transform.forward; if(lockedCamera) { targetAcquired = true; targetPosition = lastLaserPoint = lockedCamera.groundTargetPosition; } } else if(targetingMode == TargetingModes.AntiRad && targetAcquired) { RadarWarningReceiver.OnRadarPing += ReceiveRadarPing; } part.decouple(0); part.force_activate(); part.Unpack(); vessel.situation = Vessel.Situations.FLYING; rigidbody.isKinematic = false; BDArmorySettings.Instance.ApplyNewVesselRanges(vessel); part.bodyLiftMultiplier = 0; part.dragModel = Part.DragModel.NONE; //add target info to vessel if(legacyTargetVessel!=null && !vessel.gameObject.GetComponent<TargetInfo>()) { TargetInfo info = vessel.gameObject.AddComponent<TargetInfo>(); info.isMissile = true; info.missileModule = this; foreach(var mf in legacyTargetVessel.FindPartModulesImplementing<MissileFire>()) { targetMf = mf; break; } } if(decoupleForward) { part.rb.velocity += decoupleSpeed * part.transform.forward; } else { part.rb.velocity += decoupleSpeed * -part.transform.up; } if(rndAngVel > 0) { part.rb.angularVelocity += UnityEngine.Random.insideUnitSphere.normalized * rndAngVel; } vessel.vesselName = GetShortName(); vessel.vesselType = VesselType.Probe; timeFired = Time.time; hasFired = true; previousRotation = transform.rotation; //setting ref transform for navball GameObject refObject = new GameObject(); refObject.transform.rotation = Quaternion.LookRotation(-transform.up, transform.forward); refObject.transform.parent = transform; part.SetReferenceTransform(refObject.transform); vessel.SetReferenceTransform(part); MissileState = MissileStates.Drop; part.crashTolerance = 9999; } }
public static void ScanInDirection(float directionAngle, Transform referenceTransform, float fov, Vector3 position, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType) { Vector3d geoPos = VectorUtils.WorldPositionToGeoCoords(position, FlightGlobals.currentMainBody); Vector3 forwardVector = referenceTransform.forward; Vector3 upVector = VectorUtils.GetUpDirection(position); Vector3 lookDirection = Quaternion.AngleAxis(directionAngle, upVector) * forwardVector; int dataIndex = 0; foreach(var vessel in FlightGlobals.Vessels) { if(vessel.loaded) { if((vessel.transform.position-position).sqrMagnitude < 100) continue; //ignore self if(TerrainCheck(referenceTransform.position, vessel.transform.position)) continue; //blocked by terrain Vector3 vesselDirection = Vector3.ProjectOnPlane(vessel.CoM-position, upVector); if(Vector3.Angle(vesselDirection,lookDirection) < fov/2) { float sig = GetModifiedSignature(vessel, position); RadarWarningReceiver.PingRWR(vessel, position, rwrType, dataPersistTime); if(sig > minSignature) { TargetInfo ti = vessel.GetComponent<TargetInfo>(); if(!ti) { vessel.gameObject.AddComponent<TargetInfo>(); } while(dataIndex < dataArray.Length-1) { if((dataArray[dataIndex].exists && Time.time-dataArray[dataIndex].timeAcquired > dataPersistTime) || !dataArray[dataIndex].exists) { break; } dataIndex++; } if(dataIndex >= dataArray.Length) break; dataArray[dataIndex] = new TargetSignatureData(vessel, sig); dataIndex++; if(dataIndex >= dataArray.Length) break; } } } } }