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);
        }
Example #2
0
        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;
        }
Example #3
0
        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
            }
        }