/// <summary> /// This method will calculate if there is valid line of sight between the explosion origin and the specific Part /// In order to avoid collisions with the same missile part, It will not take into account those parts beloging to same vessel that contains the explosive part /// </summary> /// <param name="part"></param> /// <param name="explosivePart"></param> /// <param name="hit"> out property with the actual hit</param> /// <returns></returns> private bool IsInLineOfSight(Part part, Part explosivePart, out RaycastHit hit, out float distance, out List <Tuple <float, float, float> > intermediateParts) { Ray partRay = new Ray(Position, part.transform.position - Position); var hitCount = Physics.RaycastNonAlloc(partRay, lineOfSightHits, Range, 9076737); if (hitCount == lineOfSightHits.Length) // If there's a whole bunch of stuff in the way (unlikely), then we need to increase the size of our hits buffer. { lineOfSightHits = Physics.RaycastAll(partRay, Range, 9076737); hitCount = lineOfSightHits.Length; } intermediateParts = new List <Tuple <float, float, float> >(); using (var hitsEnu = lineOfSightHits.Take(hitCount).OrderBy(x => x.distance).GetEnumerator()) while (hitsEnu.MoveNext()) { Part partHit = hitsEnu.Current.collider.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } hit = hitsEnu.Current; distance = hit.distance; if (partHit == part) { return(true); } if (partHit != part) { // ignoring collisions against the explosive if (explosivePart != null && partHit.vessel == explosivePart.vessel) { continue; } if (FlightGlobals.currentMainBody != null && hit.collider.gameObject == FlightGlobals.currentMainBody.gameObject) { return(false); // Terrain hit. Full absorption. Should avoid NREs in the following. } var partHP = partHit.Damage(); var partArmour = partHit.GetArmorThickness(); if (partHP > 0) // Ignore parts that are already dead but not yet removed from the game. { intermediateParts.Add(new Tuple <float, float, float>(hit.distance, partHP, partArmour)); } } } hit = new RaycastHit(); distance = 0; return(false); }
private List <BlastHitEvent> ProcessingBlastSphere() { explosionEventsPreProcessing.Clear(); explosionEventsPartsAdded.Clear(); explosionEventsBuildingAdded.Clear(); explosionEventsVesselsHitByMissiles.Clear(); string sourceVesselName = null; if (BDACompetitionMode.Instance) { switch (ExplosionSource) { case ExplosionSourceType.Missile: var explosivePart = ExplosivePart ? ExplosivePart.FindModuleImplementing <BDExplosivePart>() : null; sourceVesselName = explosivePart ? explosivePart.sourcevessel.GetName() : SourceVesselName; break; case ExplosionSourceType.Bullet: sourceVesselName = SourceVesselName; break; default: break; } } var overlapSphereColliderCount = Physics.OverlapSphereNonAlloc(Position, Range, overlapSphereColliders, 9076737); if (overlapSphereColliderCount == overlapSphereColliders.Length) { overlapSphereColliders = Physics.OverlapSphere(Position, Range, 9076737); overlapSphereColliderCount = overlapSphereColliders.Length; } using (var hitCollidersEnu = overlapSphereColliders.Take(overlapSphereColliderCount).GetEnumerator()) { while (hitCollidersEnu.MoveNext()) { if (hitCollidersEnu.Current == null) { continue; } Part partHit = hitCollidersEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (partHit != null && partHit.mass > 0 && !explosionEventsPartsAdded.Contains(partHit)) { var damaged = ProcessPartEvent(partHit, sourceVesselName, explosionEventsPreProcessing, explosionEventsPartsAdded); // If the explosion derives from a missile explosion, count the parts damaged for missile hit scores. if (damaged && ExplosionSource == ExplosionSourceType.Missile && BDACompetitionMode.Instance) { if (sourceVesselName != null && BDACompetitionMode.Instance.Scores.ContainsKey(sourceVesselName)) // Check that the source vessel is in the competition. { var damagedVesselName = partHit.vessel != null?partHit.vessel.GetName() : null; if (damagedVesselName != null && damagedVesselName != sourceVesselName && BDACompetitionMode.Instance.Scores.ContainsKey(damagedVesselName)) // Check that the damaged vessel is in the competition and isn't the source vessel. { if (BDACompetitionMode.Instance.Scores[damagedVesselName].missilePartDamageCounts.ContainsKey(sourceVesselName)) { ++BDACompetitionMode.Instance.Scores[damagedVesselName].missilePartDamageCounts[sourceVesselName]; } else { BDACompetitionMode.Instance.Scores[damagedVesselName].missilePartDamageCounts[sourceVesselName] = 1; } if (!BDACompetitionMode.Instance.Scores[damagedVesselName].everyoneWhoHitMeWithMissiles.Contains(sourceVesselName)) { BDACompetitionMode.Instance.Scores[damagedVesselName].everyoneWhoHitMeWithMissiles.Add(sourceVesselName); } ++BDACompetitionMode.Instance.Scores[sourceVesselName].totalDamagedPartsDueToMissiles; BDACompetitionMode.Instance.Scores[damagedVesselName].lastMissileHitTime = Planetarium.GetUniversalTime(); BDACompetitionMode.Instance.Scores[damagedVesselName].lastPersonWhoHitMeWithAMissile = sourceVesselName; if (explosionEventsVesselsHitByMissiles.ContainsKey(damagedVesselName)) { ++explosionEventsVesselsHitByMissiles[damagedVesselName]; } else { explosionEventsVesselsHitByMissiles[damagedVesselName] = 1; } if (BDArmorySettings.REMOTE_LOGGING_ENABLED) { BDAScoreService.Instance.TrackMissileParts(sourceVesselName, damagedVesselName, 1); } } } } } else { DestructibleBuilding building = hitCollidersEnu.Current.GetComponentInParent <DestructibleBuilding>(); if (building != null && !explosionEventsBuildingAdded.Contains(building)) { ProcessBuildingEvent(building, explosionEventsPreProcessing, explosionEventsBuildingAdded); } } } } if (explosionEventsVesselsHitByMissiles.Count > 0) { string message = ""; foreach (var vesselName in explosionEventsVesselsHitByMissiles.Keys) { message += (message == "" ? "" : " and ") + vesselName + " had " + explosionEventsVesselsHitByMissiles[vesselName]; } message += " parts damaged due to missile strike" + (SourceWeaponName != null ? " (" + SourceWeaponName + ")" : "") + (sourceVesselName != null ? " from " + sourceVesselName : "") + "."; BDACompetitionMode.Instance.competitionStatus.Add(message); // Note: damage hasn't actually been applied to the parts yet, just assigned as events, so we can't know if they survived. foreach (var vesselName in explosionEventsVesselsHitByMissiles.Keys) // Note: sourceVesselName is already checked for being in the competition before damagedVesselName is added to explosionEventsVesselsHitByMissiles, so we don't need to check it here. { if (BDACompetitionMode.Instance.Scores[vesselName].missileHitCounts.ContainsKey(sourceVesselName)) { ++BDACompetitionMode.Instance.Scores[vesselName].missileHitCounts[sourceVesselName]; } else { BDACompetitionMode.Instance.Scores[vesselName].missileHitCounts[sourceVesselName] = 1; } } } return(explosionEventsPreProcessing); }
private bool ProximityAirDetonation(float distanceFromStart) { bool detonate = false; if (distanceFromStart <= 500f) { return(false); } if (!explosive || tntMass <= 0) { return(false); } if (airDetonation) { if (distanceFromStart > maxAirDetonationRange || distanceFromStart > defaultDetonationRange) { return(detonate = true); } } if (proximityDetonation) { using (var hitsEnu = Physics.OverlapSphere(transform.position, detonationRange, 557057).AsEnumerable().GetEnumerator()) { while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } try { Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (partHit.vessel == sourceVessel) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.PooledBullet]: Bullet proximity sphere hit | Distance overlap = " + detonationRange + "| Part name = " + partHit.name); } return(detonate = true); } catch (Exception e) { // ignored Debug.LogWarning("[BDArmory.PooledBullet]: Exception thrown in ProximityAirDetonation: " + e.Message + "\n" + e.StackTrace); } } } } return(detonate); }
void Detonate() //borrowed from Stockalike Project Orion { if (hasDetonated || FlightGlobals.currentMainBody == null || VesselSpawner.Instance.vesselsSpawning) // Don't trigger on scene changes or during spawning. { return; } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.NukeTest]: Running Detonate() on nerva in vessel " + Sourcevessel); } //affect any nearby parts/vessels that aren't the source vessel Dictionary <string, int> vesselsHitByMissiles = new Dictionary <string, int>(); using (var blastHits = Physics.OverlapSphere(part.transform.position, thermalRadius, 9076737).AsEnumerable().GetEnumerator()) { partsHit.Clear(); while (blastHits.MoveNext()) { if (blastHits.Current == null) { continue; } if (blastHits.Current.gameObject == FlightGlobals.currentMainBody.gameObject) { continue; // Ignore terrain hits. } Part partHit = blastHits.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (partsHit.Contains(partHit)) { continue; // Don't hit the same part multiple times. } partsHit.Add(partHit); if (partHit != null && partHit.mass > 0) { var distToG0 = Math.Max((part.transform.position - partHit.transform.position).magnitude, 1f); float radiativeArea = !double.IsNaN(partHit.radiativeArea) ? (float)partHit.radiativeArea : partHit.GetArea(); if (BDArmorySettings.DRAW_DEBUG_LABELS && double.IsNaN(partHit.radiativeArea)) { Debug.Log("[BDArmory.NukeTest]: radiative area of part " + partHit + " was NaN, using approximate area " + radiativeArea + " instead."); } //if (partHit.vessel != this.vessel) if (partHit != part) { partHit.skinTemperature += fluence * 3370000000 / (4 * Math.PI * Math.Pow(distToG0, 2.0)) * radiativeArea / 2; // Fluence scales linearly w/ yield, 1 Kt will produce between 33 TJ and 337 kJ at 0-1000m, } // everything gets heated via atmosphere Ray LoSRay = new Ray(part.transform.position, partHit.transform.position - part.transform.position); RaycastHit hit; if (Physics.Raycast(LoSRay, out hit, distToG0, 9076737)) // only add impulse to parts with line of sight to detonation { KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent <Part>(); float blastDamage = 100; if (p == partHit) { //if (p.vessel != this.vessel) if (p != part) { // Forces if (p.rb != null && p.rb.mass > 0) // Don't apply forces to physicsless parts. { var blastImpulse = Mathf.Pow(3.01f * 1100f / distToG0, 1.25f) * 6.894f * lastValidAtmDensity * yieldCubeRoot * radiativeArea / 3f; // Math.Pow(Math.Pow(Math.Pow(9.54e-3 * 2200.0 / distToG0, 1.95), 4.0) + Math.Pow(Math.Pow(3.01 * 1100.0 / distToG0, 1.25), 4.0), 0.25) * 6.894 * vessel.atmDensity * Math.Pow(yield, 1.0 / 3.0) * partHit.radiativeArea / 3.0; //assuming a 0.05 kT yield if (float.IsNaN(blastImpulse)) { Debug.LogWarning("[BDArmory.NukeTest]: blast impulse is NaN. distToG0: " + distToG0 + ", vessel: " + vessel + ", atmDensity: " + lastValidAtmDensity + ", yield^(1/3): " + yieldCubeRoot + ", partHit: " + partHit + ", radiativeArea: " + radiativeArea); } else { if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.NukeTest]: Applying " + blastImpulse.ToString("0.0") + " impulse to " + p + " of mass " + p.mass + " at distance " + distToG0 + "m"); } p.rb.AddForceAtPosition((partHit.transform.position - part.transform.position).normalized * (float)blastImpulse, partHit.transform.position, ForceMode.Impulse); } } // Damage blastDamage = ((float)((yield * 3370000000) / (4f * Mathf.PI * distToG0 * distToG0) * (radiativeArea / 2f))); if (float.IsNaN(blastDamage)) { Debug.LogWarning("[BDArmory.NukeTest]: blast damage is NaN. distToG0: " + distToG0 + ", yield: " + yield + ", part: " + partHit + ", radiativeArea: " + radiativeArea); continue; } p.AddExplosiveDamage(blastDamage, 100, ExplosionSourceType.Missile); // Scoring var aName = Sourcevessel; // Attacker var tName = p.vessel.GetName(); // Target if (tName != null && aName != tName && BDACompetitionMode.Instance.Scores.ContainsKey(tName) && BDACompetitionMode.Instance.Scores.ContainsKey(aName)) { // Part hit counts if (BDACompetitionMode.Instance.Scores[tName].missilePartDamageCounts.ContainsKey(aName)) { ++BDACompetitionMode.Instance.Scores[tName].missilePartDamageCounts[aName]; } else { BDACompetitionMode.Instance.Scores[tName].missilePartDamageCounts[aName] = 1; } if (!BDACompetitionMode.Instance.Scores[tName].everyoneWhoHitMeWithMissiles.Contains(aName)) { BDACompetitionMode.Instance.Scores[tName].everyoneWhoHitMeWithMissiles.Add(aName); } ++BDACompetitionMode.Instance.Scores[aName].totalDamagedPartsDueToMissiles; BDACompetitionMode.Instance.Scores[tName].lastMissileHitTime = Planetarium.GetUniversalTime(); BDACompetitionMode.Instance.Scores[tName].lastPersonWhoHitMeWithAMissile = aName; if (vesselsHitByMissiles.ContainsKey(tName)) { ++vesselsHitByMissiles[tName]; } else { vesselsHitByMissiles[tName] = 1; } if (BDArmorySettings.REMOTE_LOGGING_ENABLED) { BDAScoreService.Instance.TrackMissileParts(aName, tName, 1); } // Part damage scoring var tData = BDACompetitionMode.Instance.Scores[tName]; if (tData.damageFromMissiles.ContainsKey(aName)) { tData.damageFromMissiles[aName] += blastDamage; } else { tData.damageFromMissiles.Add(aName, blastDamage); } if (BDArmorySettings.REMOTE_LOGGING_ENABLED) { BDAScoreService.Instance.TrackMissileDamage(aName, tName, blastDamage); } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.NukeTest]: " + aName + " did " + blastDamage + " blast damage to " + tName + " at " + distToG0.ToString("0.000") + "m"); } } } } } } else { DestructibleBuilding building = blastHits.Current.GetComponentInParent <DestructibleBuilding>(); if (building != null) { var distToEpicenter = Mathf.Max((part.transform.position - building.transform.position).magnitude, 1f); var blastImpulse = Mathf.Pow(3.01f * 1100f / distToEpicenter, 1.25f) * 6.894f * lastValidAtmDensity * yieldCubeRoot; // blastImpulse = (((((Math.Pow((Math.Pow((Math.Pow((9.54 * Math.Pow(10.0, -3.0) * (2200.0 / distToEpicenter)), 1.95)), 4.0) + Math.Pow((Math.Pow((3.01 * (1100.0 / distToEpicenter)), 1.25)), 4.0)), 0.25)) * 6.894) * (vessel.atmDensity)) * Math.Pow(yield, (1.0 / 3.0)))); if (!double.IsNaN(blastImpulse) && blastImpulse > 140) //140kPa, level at which reinforced concrete structures are destroyed { building.Demolish(); } } } } } if (vesselsHitByMissiles.Count > 0) { string message = ""; foreach (var vesselName in vesselsHitByMissiles.Keys) { message += (message == "" ? "" : " and ") + vesselName + " had " + vesselsHitByMissiles[vesselName]; } message += " parts damaged (Blast Wave) by " + Sourcevessel + "'s exploding engine core."; BDACompetitionMode.Instance.competitionStatus.Add(message); Debug.Log("[BDArmory.NukeTest]: " + message); } ExplosionFx.CreateExplosion(part.transform.position, 1, explModelPath, explSoundPath, ExplosionSourceType.Missile, 0, null, Sourcevessel, "Reactor Containment Failure"); hasDetonated = true; if (part.vessel != null) // Already in the process of being destroyed. { part.Destroy(); } }
void Detonate() { if (!parentPart.partName.Contains("exploding")) { bool excessFuel = false; parentPart.partName += "exploding"; PartResource fuel = parentPart.Resources.Where(pr => pr.resourceName == "LiquidFuel").FirstOrDefault(); PartResource ox = parentPart.Resources.Where(pr => pr.resourceName == "Oxidizer").FirstOrDefault(); if (fuel != null) { tntMassEquivilent += (Mathf.Clamp((float)fuel.amount, ((float)fuel.maxAmount * 0.05f), ((float)fuel.maxAmount * 0.2f)) / 2); if (fuel != null && ox != null) { tntMassEquivilent += (Mathf.Clamp((float)ox.amount, ((float)ox.maxAmount * 0.1f), ((float)ox.maxAmount * 0.3f)) / 2); tntMassEquivilent *= 1.3f; } if (fuel.amount > fuel.maxAmount * 0.3f) { excessFuel = true; } } PartResource mp = parentPart.Resources.Where(pr => pr.resourceName == "MonoPropellant").FirstOrDefault(); if (mp != null) { tntMassEquivilent += (Mathf.Clamp((float)mp.amount, ((float)mp.maxAmount * 0.1f), ((float)mp.maxAmount * 0.3f)) / 3); if (mp.amount > mp.maxAmount * 0.3f) { excessFuel = true; } } PartResource ec = parentPart.Resources.Where(pr => pr.resourceName == "ElectricCharge").FirstOrDefault(); if (ec != null) { tntMassEquivilent += ((float)ec.maxAmount / 5000); //fix for cockpit batteries weighing a tonne+ ec.maxAmount = 0; ec.isVisible = false; parentPart.RemoveResource(ec);//destroy battery. not calling part.destroy, since some batteries in cockpits. Misc.Misc.RefreshAssociatedWindows(parentPart); } tntMassEquivilent *= BDArmorySettings.BD_AMMO_DMG_MULT; if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.FireFX] Fuel Explosion in " + this.parentPart.name + ", TNT mass equivilent " + tntMassEquivilent); } if (excessFuel) { float blastRadius = BlastPhysicsUtils.CalculateBlastRange(tntMassEquivilent); using (var blastHits = Physics.OverlapSphere(parentPart.transform.position, blastRadius, 9076737).AsEnumerable().GetEnumerator()) { while (blastHits.MoveNext()) { if (blastHits.Current == null) { continue; } try { Part partHit = blastHits.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (partHit != null && partHit.mass > 0) { Rigidbody rb = partHit.Rigidbody; Vector3 distToG0 = parentPart.transform.position - partHit.transform.position; Ray LoSRay = new Ray(parentPart.transform.position, partHit.transform.position - parentPart.transform.position); RaycastHit hit; if (Physics.Raycast(LoSRay, out hit, distToG0.magnitude, 9076737)) { KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent <Part>(); if (p == partHit) { if (rb == null) { return; } BulletHitFX.AttachFire(hit, p, 1, SourceVessel, BDArmorySettings.WEAPON_FX_DURATION * (1 - (distToG0.magnitude / blastRadius))); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.FireFX] " + this.parentPart.name + " hit by burning fuel"); } } } } } catch (Exception e) { Debug.LogWarning("[BDArmory.FireFX]: Exception thrown in Detonate: " + e.Message + "\n" + e.StackTrace); } } } } ExplosionFx.CreateExplosion(parentPart.transform.position, tntMassEquivilent, explModelPath, explSoundPath, ExplosionSourceType.Bullet, 0, null, parentPart.vessel != null ? parentPart.vessel.name : null, null); // needs to be Explosiontype Bullet since missile only returns Module MissileLauncher gameObject.SetActive(false); } }
/// <summary> /// Check for bullet collision in the upcoming period. /// </summary> /// <param name="period">Period to consider, typically Time.fixedDeltaTime</param> /// <param name="reverse">Also perform raycast in reverse to detect collisions from rays starting within an object.</param> /// <returns>true if a collision is detected, false otherwise.</returns> public bool CheckBulletCollision(float period, bool reverse = false) { //reset our hit variables to default state hasPenetrated = true; hasDetonated = false; hasRicocheted = false; penTicker = 0; currPosition = transform.position; float dist = currentVelocity.magnitude * period; bulletRay = new Ray(currPosition, currentVelocity + 0.5f * period * FlightGlobals.getGeeForceAtPosition(transform.position)); var hitCount = Physics.RaycastNonAlloc(bulletRay, hits, dist, 9076737); if (hitCount == hits.Length) // If there's a whole bunch of stuff in the way (unlikely), then we need to increase the size of our hits buffer. { hits = Physics.RaycastAll(bulletRay, dist, 9076737); hitCount = hits.Length; } int reverseHitCount = 0; if (reverse) { reverseHitCount = Physics.RaycastNonAlloc(new Ray(currPosition + currentVelocity * period, -currentVelocity), reverseHits, dist, 9076737); if (reverseHitCount == reverseHits.Length) { reverseHits = Physics.RaycastAll(new Ray(currPosition + currentVelocity * period, -currentVelocity), dist, 9076737); reverseHitCount = reverseHits.Length; } for (int i = 0; i < reverseHitCount; ++i) { reverseHits[i].distance = dist - reverseHits[i].distance; } } if (hitCount + reverseHitCount > 0) { var orderedHits = hits.Take(hitCount).Concat(reverseHits.Take(reverseHitCount)).OrderBy(x => x.distance); using (var hitsEnu = orderedHits.GetEnumerator()) { RaycastHit hit; Part hitPart; KerbalEVA hitEVA; while (hitsEnu.MoveNext()) { if (!hasPenetrated || hasRicocheted || hasDetonated) { return(true); } hit = hitsEnu.Current; hitPart = null; hitEVA = null; try { hitPart = hit.collider.gameObject.GetComponentInParent <Part>(); hitEVA = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); } catch (NullReferenceException e) { Debug.Log("[BDArmory.PooledBullet]:NullReferenceException for Ballistic Hit: " + e.Message); return(true); } if (hitPart != null && ProjectileUtils.IsIgnoredPart(hitPart)) { continue; // Ignore ignored parts. } if (hitEVA != null) { hitPart = hitEVA.part; // relative velocity, separate from the below statement, because the hitpart might be assigned only above if (hitPart.rb != null) { impactVelocity = (currentVelocity * dragVelocityFactor - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f())).magnitude; } else { impactVelocity = currentVelocity.magnitude * dragVelocityFactor; } distanceTraveled += hit.distance; ProjectileUtils.ApplyDamage(hitPart, hit, 1, 1, caliber, bulletMass, impactVelocity, bulletDmgMult, distanceTraveled, explosive, incendiary, hasRicocheted, sourceVessel, bullet.name, team); ExplosiveDetonation(hitPart, hit, bulletRay); KillBullet(); // Kerbals are too thick-headed for penetration... return(true); } if (hitPart != null && hitPart.vessel == sourceVessel) { continue; //avoid autohit; } Vector3 impactVector = currentVelocity; if (hitPart != null && hitPart.rb != null) { // using relative velocity vector instead of just bullet velocity // since KSP vessels might move faster than bullets impactVector = currentVelocity * dragVelocityFactor - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f()); } float hitAngle = Vector3.Angle(impactVector, -hit.normal); if (ProjectileUtils.CheckGroundHit(hitPart, hit, caliber)) { ProjectileUtils.CheckBuildingHit(hit, bulletMass, currentVelocity, bulletDmgMult); if (!RicochetScenery(hitAngle)) { ExplosiveDetonation(hitPart, hit, bulletRay); KillBullet(); distanceTraveled += hit.distance; return(true); } else { DoRicochet(hitPart, hit, hitAngle, hit.distance / dist, period); return(true); } } //Standard Pipeline Hitpoints, Armor and Explosives impactVelocity = impactVector.magnitude; if (massMod != 0) { var ME = hitPart.FindModuleImplementing <ModuleMassAdjust>(); if (ME == null) { ME = (ModuleMassAdjust)hitPart.AddModule("ModuleMassAdjust"); } ME.massMod += massMod; ME.duration += BDArmorySettings.WEAPON_FX_DURATION; } if (impulse != 0 && hitPart.rb != null) { hitPart.rb.AddForceAtPosition(impactVector.normalized * impulse, hit.point, ForceMode.Acceleration); ProjectileUtils.ApplyScore(hitPart, sourceVessel, distanceTraveled, 0, bullet.name); break; //impulse rounds shouldn't penetrate/do damage } float anglemultiplier = (float)Math.Cos(Math.PI * hitAngle / 180.0); float thickness = ProjectileUtils.CalculateThickness(hitPart, anglemultiplier); float penetration = ProjectileUtils.CalculatePenetration(caliber, bulletMass, impactVelocity, apBulletMod); float penetrationFactor = ProjectileUtils.CalculateArmorPenetration(hitPart, anglemultiplier, hit, penetration, thickness, caliber); if (penetration > thickness) { currentVelocity = currentVelocity * (float)Math.Sqrt(thickness / penetration); if (penTicker > 0) { currentVelocity *= 0.55f; } flightTimeElapsed -= period; } if (penetrationFactor >= 2) { //its not going to bounce if it goes right through hasRicocheted = false; } else { if (RicochetOnPart(hitPart, hit, hitAngle, impactVelocity, hit.distance / dist, period)) { hasRicocheted = true; } } if (penetrationFactor > 1 && !hasRicocheted) //fully penetrated continue ballistic damage { hasPenetrated = true; ProjectileUtils.ApplyDamage(hitPart, hit, 1, penetrationFactor, caliber, bulletMass, impactVelocity, bulletDmgMult, distanceTraveled, explosive, incendiary, hasRicocheted, sourceVessel, bullet.name, team); penTicker += 1; ProjectileUtils.CheckPartForExplosion(hitPart); //Explosive bullets that penetrate should explode shortly after //if penetration is very great, they will have moved on //checking velocity as they would not be able to come out the other side //if (explosive && penetrationFactor < 3 || currentVelocity.magnitude <= 800f) if (explosive) { //move bullet transform.position += (currentVelocity * period) / 3; distanceTraveled += hit.distance; ExplosiveDetonation(hitPart, hit, bulletRay); hasDetonated = true; KillBullet(); return(true); } } else if (!hasRicocheted) // explosive bullets that get stopped by armor will explode { if (hitPart.rb != null && hitPart.rb.mass > 0) { float forceAverageMagnitude = impactVelocity * impactVelocity * (1f / hit.distance) * (bulletMass - tntMass); float accelerationMagnitude = forceAverageMagnitude / (hitPart.vessel.GetTotalMass() * 1000); hitPart.rb.AddForceAtPosition(impactVector.normalized * accelerationMagnitude, hit.point, ForceMode.Acceleration); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.PooledBullet]: Force Applied " + Math.Round(accelerationMagnitude, 2) + "| Vessel mass in kgs=" + hitPart.vessel.GetTotalMass() * 1000 + "| bullet effective mass =" + (bulletMass - tntMass)); } } distanceTraveled += hit.distance; hasPenetrated = false; ProjectileUtils.ApplyDamage(hitPart, hit, 1, penetrationFactor, caliber, bulletMass, impactVelocity, bulletDmgMult, distanceTraveled, explosive, incendiary, hasRicocheted, sourceVessel, bullet.name, team); ExplosiveDetonation(hitPart, hit, bulletRay); hasDetonated = true; KillBullet(); return(true); } ///////////////////////////////////////////////////////////////////////////////// // penetrated after a few ticks ///////////////////////////////////////////////////////////////////////////////// //penetrating explosive //richochets if ((penTicker >= 2 && explosive) || (hasRicocheted && explosive)) { //detonate ExplosiveDetonation(hitPart, hit, bulletRay, airDetonation); distanceTraveled += hit.distance; return(true); } //bullet should not go any further if moving too slowly after hit //smaller caliber rounds would be too deformed to do any further damage if (currentVelocity.magnitude <= 100 && hasPenetrated) { if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.PooledBullet]: Bullet Velocity too low, stopping"); } KillBullet(); distanceTraveled += hit.distance; return(true); } } //end While } //end enumerator } //end of hits return(false); }
public void DetonateIfPossible() { if (!hasDetonated) { hasDetonated = true; // Set hasDetonated here to avoid recursive calls due to ammo boxes exploding each other. var vesselName = vessel != null ? vessel.vesselName : null; Vector3 direction = default(Vector3); GetBlastRadius(); if (CASELevel == 0) //a considerable quantity of explosives and propellants just detonated inside your ship { ExplosionFx.CreateExplosion(part.transform.position, (float)ammoExplosionYield * BDArmorySettings.BD_AMMO_DMG_MULT, explModelPath, explSoundPath, ExplosionSourceType.Missile, 0, part, vesselName, null, direction); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.ModuleCASE] CASE 0 explosion, tntMassEquivilent: " + ammoExplosionYield); } } else if (CASELevel == 1) // the blast is reduced. Damage is severe, but (potentially) survivable { ExplosionFx.CreateExplosion(part.transform.position, ((float)ammoExplosionYield / 2), limitEdexploModelPath, explSoundPath, ExplosionSourceType.Missile, 0, part, vesselName, null, direction, true); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.ModuleCASE] CASE I explosion, tntMassEquivilent: " + ammoExplosionYield + ", part: " + part + ", vessel: " + vesselName); } using (var blastHits = Physics.OverlapSphere(part.transform.position, blastRadius / 2, 9076737).AsEnumerable().GetEnumerator()) { while (blastHits.MoveNext()) { if (blastHits.Current == null) { continue; } try { Part partHit = blastHits.Current.GetComponentInParent <Part>(); if (partHit == null || partHit == part) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (partHit.mass > 0) { Rigidbody rb = partHit.Rigidbody; if (rb == null) { continue; } Vector3 distToG0 = part.transform.position - partHit.transform.position; Ray LoSRay = new Ray(part.transform.position, partHit.transform.position - part.transform.position); RaycastHit hit; if (Physics.Raycast(LoSRay, out hit, distToG0.magnitude, 9076737)) { if (FlightGlobals.currentMainBody == null || hit.collider.gameObject != FlightGlobals.currentMainBody.gameObject) { KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent <Part>(); if (p == partHit) { ApplyDamage(p, hit, (1 - Mathf.Sqrt(distToG0.magnitude / (blastRadius / 2)))); } } } } } catch (Exception e) { Debug.LogError("[BDArmory.ModuleCASE]: Exception in AmmoExplosion Hit: " + e.Message + "\n" + e.StackTrace); } } } } else //if (CASELevel == 2) //blast contained, shunted out side of hull, minimal damage { ExplosionFx.CreateExplosion(part.transform.position, (float)ammoExplosionYield, shuntExploModelPath, explSoundPath, ExplosionSourceType.Missile, 0, part, vesselName, null, direction, true); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.ModuleCASE] CASE II explosion, tntMassEquivilent: " + ammoExplosionYield); } Ray BlastRay = new Ray(part.transform.position, part.transform.up); var hits = Physics.RaycastAll(BlastRay, blastRadius, 9076737); if (hits.Length > 0) { var orderedHits = hits.OrderBy(x => x.distance); using (var hitsEnu = orderedHits.GetEnumerator()) { while (hitsEnu.MoveNext()) { RaycastHit hit = hitsEnu.Current; Part hitPart = null; KerbalEVA hitEVA = null; if (hit.collider.gameObject != FlightGlobals.currentMainBody.gameObject) { try { hitPart = hit.collider.gameObject.GetComponentInParent <Part>(); hitEVA = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); } catch (NullReferenceException e) { Debug.LogError("[BDArmory.ModuleCASE]: NullReferenceException for AmmoExplosion Hit: " + e.Message + "\n" + e.StackTrace); continue; } if (hitPart == null || hitPart == part) { continue; } if (ProjectileUtils.IsIgnoredPart(hitPart)) { continue; // Ignore ignored parts. } if (hitEVA != null) { hitPart = hitEVA.part; if (hitPart.rb != null) { ApplyDamage(hitPart, hit); } break; } ApplyDamage(hitPart, hit); } } } } } if (part.vessel != null) // Already in the process of being destroyed. { part.Destroy(); } } }
void Detonate(Vector3 pos, bool missed) { if (!missed) { if (tntMass > 0) { Vector3 direction = default(Vector3); if (shaped) { direction = (pos + rb.velocity * Time.deltaTime).normalized; } if (gravitic) { using (var hitsEnu = Physics.OverlapSphere(transform.position, blastRadius, 557057).AsEnumerable().GetEnumerator()) { while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } float distance = Vector3.Distance(transform.position, partHit.transform.position); if (gravitic) { if (partHit.mass > 0) { var ME = partHit.vessel.rootPart.FindModuleImplementing <ModuleMassAdjust>(); if (ME == null) { ME = (ModuleMassAdjust)partHit.vessel.rootPart.AddModule("ModuleMassAdjust"); } ME.massMod += (massMod * (1 - (distance / blastRadius))); //this way craft at edge of blast might only get disabled instead of bricked ME.duration += (BDArmorySettings.WEAPON_FX_DURATION * (1 - (distance / blastRadius))); //can bypass EMP damage cap } } } } } if (incendiary) { for (int f = 0; f < 20; f++) //throw 20 random raytraces out in a sphere and see what gets tagged { Ray LoSRay = new Ray(transform.position, VectorUtils.GaussianDirectionDeviation(transform.forward, 170)); RaycastHit hit; if (Physics.Raycast(LoSRay, out hit, blastRadius * 1.2f, 9076737)) // only add fires to parts in LoS of blast { KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent <Part>(); float distance = Vector3.Distance(transform.position, hit.point); if (p != null) { BulletHitFX.AttachFire(hit, p, caliber, sourceVesselName, BDArmorySettings.WEAPON_FX_DURATION * (1 - (distance / blastRadius)), 1, false, true); //else apply fire to occluding part if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.Rocket]: Applying fire to " + p.name + " at distance " + distance + "m, for " + BDArmorySettings.WEAPON_FX_DURATION * (1 - (distance / blastRadius)) + " seconds"); } ; } } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[Rocket] incendiary raytrace: " + hit.point.x + "; " + hit.point.y + "; " + hit.point.z); } } } if (concussion || EMP || choker) { using (var hitsEnu = Physics.OverlapSphere(transform.position, 25, 557057).AsEnumerable().GetEnumerator()) { var craftHit = new HashSet <Vessel>(); while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } if (hitsEnu.Current.gameObject == FlightGlobals.currentMainBody.gameObject) { continue; // Ignore terrain hits. } Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (craftHit.Contains(partHit.vessel)) { continue; // Don't hit the same craft multiple times. } craftHit.Add(partHit.vessel); float Distance = Vector3.Distance(partHit.transform.position, this.transform.position); if (partHit != null) { if (concussion && partHit.mass > 0) { partHit.rb.AddForceAtPosition((partHit.transform.position - this.transform.position).normalized * impulse, partHit.transform.position, ForceMode.Acceleration); } if (EMP) { var MDEC = partHit.vessel.rootPart.FindModuleImplementing <ModuleDrainEC>(); if (MDEC == null) { MDEC = (ModuleDrainEC)partHit.vessel.rootPart.AddModule("ModuleDrainEC"); } MDEC.incomingDamage += ((25 - Distance) * 5); //this way craft at edge of blast might only get disabled instead of bricked MDEC.softEMP = false; //can bypass EMP damage cap } if (choker) { var ash = partHit.vessel.rootPart.FindModuleImplementing <ModuleDrainIntakes>(); if (ash == null) { ash = (ModuleDrainIntakes)partHit.vessel.rootPart.AddModule("ModuleDrainIntakes"); } ash.drainDuration += BDArmorySettings.WEAPON_FX_DURATION * (1 - (Distance / 25)); //reduce intake knockout time based on distance from epicenter } } } } ExplosionFx.CreateExplosion(pos, tntMass, explModelPath, explSoundPath, ExplosionSourceType.Bullet, caliber, null, sourceVesselName, null, direction, true); } else { ExplosionFx.CreateExplosion(pos, tntMass, explModelPath, explSoundPath, ExplosionSourceType.Bullet, caliber, null, sourceVesselName, null, direction); } } } // needs to be Explosiontype Bullet since missile only returns Module MissileLauncher gameObject.SetActive(false); }
private bool ProximityAirDetonation(float distanceFromStart) { bool detonate = false; if (distanceFromStart <= blastRadius) { return(false); } if (!explosive || tntMass <= 0) { return(false); } if (flak) { using (var hitsEnu = Physics.OverlapSphere(transform.position, detonationRange, 557057).AsEnumerable().GetEnumerator()) { while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } try { Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (partHit.vessel == sourceVessel) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } var aName = sourceVessel.GetName(); //proxi detonated rocket scoring var tName = partHit.vessel.GetName(); if (aName != null && tName != null && aName != tName && BDACompetitionMode.Instance.Scores.ContainsKey(aName) && BDACompetitionMode.Instance.Scores.ContainsKey(tName)) { if (BDArmorySettings.REMOTE_LOGGING_ENABLED) { BDAScoreService.Instance.TrackHit(aName, tName, name, distanceFromStart); } var aData = BDACompetitionMode.Instance.Scores[aName]; aData.Score += 1; if (partHit.vessel.GetName() == "Pinata") { aData.PinataHits++; } var tData = BDACompetitionMode.Instance.Scores[tName]; tData.lastPersonWhoHitMe = aName; tData.lastHitTime = Planetarium.GetUniversalTime(); tData.everyoneWhoHitMe.Add(aName); if (tData.hitCounts.ContainsKey(aName)) { ++tData.hitCounts[aName]; } else { tData.hitCounts.Add(aName, 1); } } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.PooledRocket]: rocket proximity sphere hit | Distance overlap = " + detonationRange + "| Part name = " + partHit.name); } return(detonate = true); } catch (Exception e) { Debug.LogWarning("[BDArmory.PooledRocket]: Exception thrown in ProximityAirDetonation: " + e.Message + "\n" + e.StackTrace); } } } } return(detonate); }
void FixedUpdate() { if (!gameObject.activeInHierarchy) { return; } //floating origin and velocity offloading corrections if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) { transform.position -= FloatingOrigin.OffsetNonKrakensbane; prevPosition -= FloatingOrigin.OffsetNonKrakensbane; startPosition -= FloatingOrigin.OffsetNonKrakensbane; } distanceFromStart = Vector3.Distance(transform.position, startPosition); if (Time.time - startTime < stayTime && transform.parent != null) { transform.rotation = transform.parent.rotation; transform.position = spawnTransform.position; //+(transform.parent.rigidbody.velocity*Time.fixedDeltaTime); } else { if (transform.parent != null && parentRB) { transform.parent = null; rb.isKinematic = false; rb.velocity = parentRB.velocity + Krakensbane.GetFrameVelocityV3f(); } } if (rb && !rb.isKinematic) { //physics if (FlightGlobals.RefFrameIsRotating) { rb.velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; } //guidance and attitude stabilisation scales to atmospheric density. float atmosMultiplier = Mathf.Clamp01(2.5f * (float) FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody)); //model transform. always points prograde transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(rb.velocity + Krakensbane.GetFrameVelocity(), transform.up), atmosMultiplier * (0.5f * (Time.time - startTime)) * 50 * Time.fixedDeltaTime); if (Time.time - startTime < thrustTime && Time.time - startTime > stayTime) { thrustVector.x = randomThrustDeviation * (1 - (Mathf.PerlinNoise(4 * Time.time, randThrustSeed) * 2)) / massScalar; //this needs to scale w/ rocket mass, or light projectiles will be thrustVector.y = randomThrustDeviation * (1 - (Mathf.PerlinNoise(randThrustSeed, 4 * Time.time) * 2)) / massScalar; //far more affected than heavier ones rb.AddRelativeForce(thrustVector); }//0.012/rocketmass - use .012 as baseline, it's the mass of the hydra, which the randomTurstdeviation was originally calibrated for } if (Time.time - startTime > thrustTime) { using (var pe = pEmitters.AsEnumerable().GetEnumerator()) while (pe.MoveNext()) { if (pe.Current == null) { continue; } pe.Current.emit = false; } using (var gpe = gpEmitters.AsEnumerable().GetEnumerator()) while (gpe.MoveNext()) { if (gpe.Current == null) { continue; } gpe.Current.emit = false; } if (audioSource) { audioSource.loop = false; audioSource.Stop(); } } if (Time.time - startTime > 0.1f + stayTime) { hasPenetrated = true; hasDetonated = false; penTicker = 0; currPosition = transform.position; float dist = (currPosition - prevPosition).magnitude; RocketRay = new Ray(prevPosition, currPosition - prevPosition); var hits = Physics.RaycastAll(RocketRay, dist, 9076737); if (hits.Length > 0) { var orderedHits = hits.OrderBy(x => x.distance); using (var hitsEnu = orderedHits.GetEnumerator()) { while (hitsEnu.MoveNext()) { if (!hasPenetrated || hasDetonated) { break; } RaycastHit hit = hitsEnu.Current; Part hitPart = null; KerbalEVA hitEVA = null; try { hitPart = hit.collider.gameObject.GetComponentInParent <Part>(); hitEVA = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); } catch (NullReferenceException e) { Debug.LogWarning("[BDArmory.BDArmory]:NullReferenceException for Kinetic Hit: " + e.Message); return; } if (hitPart != null && ProjectileUtils.IsIgnoredPart(hitPart)) { continue; // Ignore ignored parts. } if (hitEVA != null) { hitPart = hitEVA.part; // relative velocity, separate from the below statement, because the hitpart might be assigned only above if (hitPart.rb != null) { impactVelocity = (rb.velocity - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f())).magnitude; } else { impactVelocity = rb.velocity.magnitude; } ProjectileUtils.ApplyDamage(hitPart, hit, 1, 1, caliber, rocketMass, impactVelocity, bulletDmgMult, distanceFromStart, explosive, incendiary, false, sourceVessel, rocketName, team); Detonate(hit.point, false); return; } if (hitPart != null && hitPart.vessel == sourceVessel) { continue; //avoid autohit; } Vector3 impactVector = rb.velocity; if (hitPart != null && hitPart.rb != null) { // using relative velocity vector instead of just rocket velocity // since KSP vessels can easily be moving faster than rockets impactVector = rb.velocity - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f()); } float hitAngle = Vector3.Angle(impactVector, -hit.normal); if (ProjectileUtils.CheckGroundHit(hitPart, hit, caliber)) { ProjectileUtils.CheckBuildingHit(hit, rocketMass, rb.velocity, bulletDmgMult); Detonate(hit.point, false); return; } impactVelocity = impactVector.magnitude; if (gravitic) { var ME = hitPart.FindModuleImplementing <ModuleMassAdjust>(); if (ME == null) { ME = (ModuleMassAdjust)hitPart.AddModule("ModuleMassAdjust"); } ME.massMod += massMod; ME.duration += BDArmorySettings.WEAPON_FX_DURATION; } if (concussion) { hitPart.rb.AddForceAtPosition(impactVector.normalized * impulse, hit.point, ForceMode.Acceleration); Detonate(hit.point, false); hasDetonated = true; return; //impulse rounds shouldn't penetrate/do damage } float anglemultiplier = (float)Math.Cos(Math.PI * hitAngle / 180.0); float thickness = ProjectileUtils.CalculateThickness(hitPart, anglemultiplier); float penetration = ProjectileUtils.CalculatePenetration(caliber, rocketMass, impactVelocity); float penetrationFactor = ProjectileUtils.CalculateArmorPenetration(hitPart, anglemultiplier, hit, penetration, thickness, caliber); if (penetration > thickness) { rb.velocity = rb.velocity * (float)Math.Sqrt(thickness / penetration); if (penTicker > 0) { rb.velocity *= 0.55f; } } if (penetrationFactor > 1) { hasPenetrated = true; ProjectileUtils.ApplyDamage(hitPart, hit, 1, penetrationFactor, caliber, rocketMass, impactVelocity, bulletDmgMult, distanceFromStart, explosive, incendiary, false, sourceVessel, rocketName, team); penTicker += 1; ProjectileUtils.CheckPartForExplosion(hitPart); if (explosive) { transform.position += (rb.velocity * Time.fixedDeltaTime) / 3; Detonate(transform.position, false); hasDetonated = true; } } else // stopped by armor { if (hitPart.rb != null && hitPart.rb.mass > 0) { float forceAverageMagnitude = impactVelocity * impactVelocity * (1f / hit.distance) * rocketMass; float accelerationMagnitude = forceAverageMagnitude / (hitPart.vessel.GetTotalMass() * 1000); hitPart.rb.AddForceAtPosition(impactVector.normalized * accelerationMagnitude, hit.point, ForceMode.Acceleration); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.PooledRocket]: Force Applied " + Math.Round(accelerationMagnitude, 2) + "| Vessel mass in kgs=" + hitPart.vessel.GetTotalMass() * 1000 + "| rocket effective mass =" + rocketMass); } } hasPenetrated = false; ProjectileUtils.ApplyDamage(hitPart, hit, 1, penetrationFactor, caliber, rocketMass, impactVelocity, bulletDmgMult, distanceFromStart, explosive, incendiary, false, sourceVessel, rocketName, team); Detonate(hit.point, false); hasDetonated = true; } if (penTicker >= 2) { Detonate(hit.point, false); return; } if (rb.velocity.magnitude <= 100 && hasPenetrated && (Time.time - startTime > thrustTime)) { if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.PooledRocket]: Rocket ballistic velocity too low, stopping"); } Detonate(hit.point, false); return; } if (!hasPenetrated || hasDetonated) { break; } } } } } else if (FlightGlobals.getAltitudeAtPos(currPosition) <= 0) { Detonate(currPosition, false); } prevPosition = currPosition; if (Time.time - startTime > lifeTime) // life's 10s, quite a long time for faster rockets { Detonate(transform.position, true); } if (distanceFromStart >= maxAirDetonationRange)//rockets are performance intensive, lets cull those that have flown too far away { Detonate(transform.position, false); } if (ProximityAirDetonation(distanceFromStart)) { Detonate(transform.position, false); } }
private bool Checkproximity(float distanceFromStart) { bool detonate = false; if (distanceFromStart < blastRadius) { return(detonate = false); } using (var hitsEnu = Physics.OverlapSphere(transform.position, detonationRange, 557057).AsEnumerable().GetEnumerator()) { while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null || partHit.vessel == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (partHit.vessel == vessel || partHit.vessel == sourcevessel) { continue; } if (partHit.vessel.vesselType == VesselType.Debris) { continue; } if (sourcevessel != null && partHit.vessel.vesselName.Contains(sourcevessel.vesselName)) { continue; } var weaponManager = VesselModuleRegistry.GetModule <MissileFire>(partHit.vessel); if (IFF_On && (weaponManager == null || weaponManager.teamString == IFFID)) { continue; } if (detonateAtMinimumDistance) { var distance = Vector3.Distance(partHit.transform.position + partHit.CoMOffset, transform.position); var predictedDistance = Vector3.Distance(AIUtils.PredictPosition(partHit.transform.position + partHit.CoMOffset, partHit.vessel.Velocity(), partHit.vessel.acceleration, Time.fixedDeltaTime), AIUtils.PredictPosition(transform.position, vessel.Velocity(), vessel.acceleration, Time.fixedDeltaTime)); if (distance > predictedDistance && distance > Time.fixedDeltaTime * (float)vessel.srfSpeed) // If we're closing and not going to hit within the next update, then wait. { return(detonate = false); } } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BDExplosivePart]: Proxifuze triggered by " + partHit.partName + " from " + partHit.vessel.vesselName); } return(detonate = true); } } return(detonate); }