public bool ProcessMessage(ForceEventArgs message) { if (message == null) { return(false); } Part part = PartUtils.GetPart(message.VesselId, message.PartFlightId, message.PartCraftId); if (part == null) { return(false); } part.AddForceToPart(new Vector3(message.ForceX, message.ForceY, message.ForceZ), new Vector3(message.PositionX, message.PositionY, message.PositionZ), message.Mode, false); return(true); }
void FixedUpdate() { if (!gameObject.activeInHierarchy) { return; } //floating origin and velocity offloading corrections if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) { transform.position -= FloatingOrigin.OffsetNonKrakensbane; startPosition -= FloatingOrigin.OffsetNonKrakensbane; } float distanceFromStart = Vector3.Distance(transform.position, startPosition); //calculate flight time for drag purposes flightTimeElapsed += Time.fixedDeltaTime; //Drag types currently only affect Impactvelocity //Numerical Integration is currently Broken switch (dragType) { case BulletDragTypes.None: break; case BulletDragTypes.AnalyticEstimate: CalculateDragAnalyticEstimate(); break; case BulletDragTypes.NumericalIntegration: CalculateDragNumericalIntegration(); break; } if (tracerLength == 0) { // visual tracer velocity is relative to the observer linePositions[0] = transform.position + ((currentVelocity - FlightGlobals.ActiveVessel.Velocity()) * tracerDeltaFactor * 0.45f * Time.fixedDeltaTime); } else { linePositions[0] = transform.position + ((currentVelocity - FlightGlobals.ActiveVessel.Velocity()).normalized * tracerLength); } if (fadeColor) { FadeColor(); bulletTrail.material.SetColor("_TintColor", currentColor * tracerLuminance); } linePositions[1] = transform.position; bulletTrail.SetPositions(linePositions); currPosition = transform.position; if (Time.time > timeToLiveUntil) //kill bullet when TTL ends { KillBullet(); return; } // bullet collision block { //reset our hit variables to default state hasPenetrated = true; hasDetonated = false; hasRichocheted = false; penTicker = 0; float dist = currentVelocity.magnitude * Time.fixedDeltaTime; Ray ray = new Ray(currPosition, currentVelocity); var hits = Physics.RaycastAll(ray, dist, 9076737); if (hits.Length > 0) { var orderedHits = hits.OrderBy(x => x.distance); using (var hitsEnu = orderedHits.GetEnumerator()) { while (hitsEnu.MoveNext()) { if (!hasPenetrated || hasRichocheted || 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) { Debug.Log("[BDArmory]:NullReferenceException for Ballistic Hit"); return; } 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; } ApplyDamage(hitPart, hit, 1, 1); break; } if (hitPart?.vessel == sourceVessel) { continue; //avoid autohit; } Vector3 impactVector = currentVelocity; if (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 (CheckGroundHit(hitPart, hit)) { CheckBuildingHit(hit); if (!RicochetScenery(hitAngle)) { ExplosiveDetonation(hitPart, hit, ray); KillBullet(); } else { DoRicochet(hitPart, hit, hitAngle); } return; } //Standard Pipeline Hitpoints, Armor and Explosives impactVelocity = impactVector.magnitude; float anglemultiplier = (float)Math.Cos(Math.PI * hitAngle / 180.0); float penetrationFactor = CalculateArmorPenetration(hitPart, anglemultiplier, hit); if (penetrationFactor >= 2) { //its not going to bounce if it goes right through hasRichocheted = false; } else { if (RicochetOnPart(hitPart, hit, hitAngle, impactVelocity)) { hasRichocheted = true; } } if (penetrationFactor > 1 && !hasRichocheted) //fully penetrated continue ballistic damage { hasPenetrated = true; ApplyDamage(hitPart, hit, 1, penetrationFactor); penTicker += 1; 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 * Time.fixedDeltaTime) / 3; ExplosiveDetonation(hitPart, hit, ray); hasDetonated = true; KillBullet(); } } else if (!hasRichocheted) // explosive bullets that get stopped by armor will explode { //New method if (hitPart.rb != null) { float forceAverageMagnitude = impactVelocity * impactVelocity * (1f / hit.distance) * (bulletMass - tntMass); float accelerationMagnitude = forceAverageMagnitude / (hitPart.vessel.GetTotalMass() * 1000); hitPart?.AddForceToPart(impactVector.normalized * accelerationMagnitude, hit.point, ForceMode.Acceleration, false); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory]: Force Applied " + Math.Round(accelerationMagnitude, 2) + "| Vessel mass in kgs=" + hitPart.vessel.GetTotalMass() * 1000 + "| bullet effective mass =" + (bulletMass - tntMass)); } } hasPenetrated = false; ApplyDamage(hitPart, hit, 1, penetrationFactor); ExplosiveDetonation(hitPart, hit, ray); hasDetonated = true; KillBullet(); } ///////////////////////////////////////////////////////////////////////////////// // penetrated after a few ticks ///////////////////////////////////////////////////////////////////////////////// //penetrating explosive //richochets if ((penTicker >= 2 && explosive) || (hasRichocheted && explosive)) { //detonate ExplosiveDetonation(hitPart, hit, ray, airDetonation); return; } //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]: Bullet Velocity too low, stopping"); } KillBullet(); return; } //we need to stop the loop if the bullet has stopped,richochet or detonated if (!hasPenetrated || hasRichocheted || hasDetonated) { break; } } //end While } //end enumerator } //end if hits } // end if collision ////////////////////////////////////////////////// //Flak Explosion (air detonation/proximity fuse) ////////////////////////////////////////////////// Vessel vesselHit = null; if (ProximityAirDetonation(distanceFromStart, out vesselHit)) { //detonate ExplosionFx.CreateExplosion(currPosition, tntMass, explModelPath, explSoundPath, false, caliber, null, currentVelocity, vesselHit); KillBullet(); return; } if (bulletDrop) { // Gravity??? var gravity_ = FlightGlobals.getGeeForceAtPosition(transform.position); //var gravity_ = Physics.gravity; currentVelocity += gravity_ * TimeWarp.deltaTime; } //move bullet transform.position += currentVelocity * Time.fixedDeltaTime; }
private void ExecutePartBlastEvent(PartBlastHitEvent eventToExecute) { if (eventToExecute.Part == null || eventToExecute.Part.Rigidbody == null || eventToExecute.Part.vessel == null || eventToExecute.Part.partInfo == null) { return; } try { Part part = eventToExecute.Part; Rigidbody rb = part.Rigidbody; var realDistance = eventToExecute.Distance; if (!eventToExecute.IsNegativePressure) { BlastInfo blastInfo = BlastPhysicsUtils.CalculatePartBlastEffects(part, realDistance, part.vessel.GetTotalMass() * 1000f, Power, Range); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log( "[BDArmory]: Executing blast event Part: {" + part.name + "}, " + " VelocityChange: {" + blastInfo.VelocityChange + "}," + " Distance: {" + realDistance + "}," + " TotalPressure: {" + blastInfo.TotalPressure + "}," + " Damage: {" + blastInfo.Damage + "}," + " EffectiveArea: {" + blastInfo.EffectivePartArea + "}," + " Positive Phase duration: {" + blastInfo.PositivePhaseDuration + "}," + " Vessel mass: {" + Math.Round(part.vessel.GetTotalMass() * 1000f) + "}," + " TimeIndex: {" + TimeIndex + "}," + " TimePlanned: {" + eventToExecute.TimeToImpact + "}," + " NegativePressure: {" + eventToExecute.IsNegativePressure + "}"); } // Add Reverse Negative Event ExplosionEvents.Enqueue(new PartBlastHitEvent() { Distance = Range - realDistance, Part = part, TimeToImpact = 2 * (Range / ExplosionVelocity) + (Range - realDistance) / ExplosionVelocity, IsNegativePressure = true, NegativeForce = blastInfo.VelocityChange * 0.25f }); part.AddForceToPart((eventToExecute.HitPoint + part.rb.velocity * TimeIndex - Position).normalized * blastInfo.VelocityChange * BDArmorySettings.EXP_IMP_MOD, eventToExecute.HitPoint + part.rb.velocity * TimeIndex, ForceMode.VelocityChange, false); if (!OnlyVisual) { part.AddExplosiveDamage(blastInfo.Damage, Caliber, IsMissile); } } else { if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log( "[BDArmory]: Executing blast event Part: {" + part.name + "}, " + " VelocityChange: {" + eventToExecute.NegativeForce + "}," + " Distance: {" + realDistance + "}," + " Vessel mass: {" + Math.Round(part.vessel.totalMass * 1000f) + "}," + " TimeIndex: {" + TimeIndex + "}," + " TimePlanned: {" + eventToExecute.TimeToImpact + "}," + " NegativePressure: {" + eventToExecute.IsNegativePressure + "}"); } part.AddForceToPart((Position - part.transform.position).normalized * eventToExecute.NegativeForce * BDArmorySettings.EXP_IMP_MOD * 0.25f, part.transform.position, ForceMode.VelocityChange, false); } } catch { // ignored due to depending on previous event an object could be disposed } }