Ejemplo n.º 1
0
        ///// <summary>
        ///// Calculation help constant: (approx.) 1 / √(3).
        ///// </summary>
        //private const float invSqrt3 = 0.57735026919f;

        ///// <summary>
        ///// Apply krash to all meshes in this part.
        ///// </summary>
        ///// <param name="krash">Krash to apply.</param>
        ///// <param name="fireEvent">Fire "DamageReceived" event.</param>
        //public void ApplyKrash(Krash krash, bool fireEvent = true)
        //{
        //    Vector3 relativeVelocity = part.transform.TransformDirection(krash.RelativeVelocity); //Transform the direction of the collision to the world reference frame.

        //    //Remove previous log entry.
        //    FlightLogger.eventLog.Remove($"{part.name} (ID: {part.flightID}) was damaged {(Damage * 100).ToString("0.00")}%");

        //    Damage += (relativeVelocity.magnitude / part.crashTolerance) / _damageDivider;

        //    //Add new log entry.
        //    FlightLogger.eventLog.Add($"{part.name} (ID: {part.flightID}) was damaged {(Damage * 100).ToString("0.00")}%");

        //    //Fire "DamageReceived" event.
        //    if (fireEvent && DamageReceived != null)
        //        DamageReceived(this, Damage);

        //    if (_exclude)
        //        return;

        //    //Dent transformation is a maximum of 75% of the part size.
        //    Vector3 transform = (relativeVelocity / (0.75f * part.partInfo.partSize) / (part.crashTolerance / Malleability));
        //    Vector3 worldPosition = part.transform.TransformPoint(krash.ContactPoint);

        //    DeformMesh(transform, worldPosition);

        //    DeformCollider(transform, worldPosition);
        //}

        ///// <summary>
        ///// Updates the visual components of the part.
        ///// Thanks Ryan Bray (https://github.com/rbray89).
        ///// </summary>
        ///// <param name="transform">Vector indicating the amount of deformation.</param>
        ///// <param name="worldPosition">Position in the world to apply the deformation from.</param>
        //private void DeformMesh(Vector3 transform, Vector3 worldPosition)
        //{
        //    foreach (MeshFilter meshFilter in meshFilters)
        //    {
        //        Mesh mesh = meshFilter.mesh;

        //        if (meshFilter.sharedMesh == null)
        //            continue;

        //        if (mesh == null)
        //            mesh = meshFilter.sharedMesh;

        //        if (_subdivide && !subdivided && part.partInfo.partSize >= MeshSubdivisionThreshold)
        //        {
        //            subdivided = true;
        //            MeshHelper.Subdivide(mesh, worldPosition, DentDistance);
        //        }

        //        Vector3 transformT = meshFilter.transform.InverseTransformVector(transform);
        //        Vector3 contactPointLocal = meshFilter.transform.InverseTransformPoint(worldPosition);
        //        Vector3 dentDistanceLocal = meshFilter.transform.TransformDirection(Vector3.one).normalized;

        //        dentDistanceLocal = meshFilter.transform.InverseTransformVector(DentDistance * dentDistanceLocal);
        //        dentDistanceLocal = Vector3.Max(-dentDistanceLocal, dentDistanceLocal);

        //        Vector3 dentDistanceInv;
        //        dentDistanceInv.x = invSqrt3 / dentDistanceLocal.x;
        //        dentDistanceInv.y = invSqrt3 / dentDistanceLocal.y;
        //        dentDistanceInv.z = invSqrt3 / dentDistanceLocal.z;

        //        Vector3[] vertices = mesh.vertices;
        //        Color32[] Colors = new Color32[vertices.Length];

        //        for (int i = 0; i < vertices.Length; i++)
        //        {
        //            Vector3 distance = vertices[i] - contactPointLocal;
        //            distance = Vector3.Max(-distance, distance);
        //            distance = dentDistanceLocal - distance;
        //            distance.Scale(dentDistanceInv);

        //            if (distance.x < 0 || distance.y < 0 || distance.z < 0)
        //                continue;

        //            Colors[i] = Color32.Lerp(new Color32(255, 255, 255, 255), new Color(0, 0, 0, 255), Damage);

        //            vertices[i] += distance.sqrMagnitude * transformT;
        //        }

        //        mesh.vertices = vertices;

        //        //TODO: Make this a KKS-mod
        //        //mesh.colors32 = Colors;
        //    }
        //}
        #endregion

        #region Experimental
        /// <summary>
        /// Apply krash to all meshes in this part.
        /// </summary>
        /// <param name="krash">Krash to apply.</param>
        /// <param name="fireEvent">Fire "DamageReceived" event.</param>
        public void ApplyKrash(Krash krash, bool fireEvent = true)
        {
            Vector3 relativeVelocity = part.transform.TransformDirection(krash.RelativeVelocity); //Transform the direction of the collision to the world reference frame.

            //Remove previous log entry.
            FlightLogger.eventLog.Remove($"{part.name} (ID: {part.flightID}) was damaged {(Damage * 100).ToString("0.00")}%");

            Damage += (relativeVelocity.magnitude / part.crashTolerance) / _damageDivider;

            //Add new log entry.
            FlightLogger.eventLog.Add($"{part.name} (ID: {part.flightID}) was damaged {(Damage * 100).ToString("0.00")}%");

            //Fire "DamageReceived" event.
            if (fireEvent && DamageReceived != null)
            {
                DamageReceived(this, Damage);
            }

            if (_exclude)
            {
                return;
            }

            //Dent transformation.
            Vector3 transform     = (relativeVelocity / (part.crashTolerance / Malleability));
            Vector3 worldPosition = part.transform.TransformPoint(krash.ContactPoint);

            DeformMesh(transform, worldPosition);

            DeformCollider(transform, worldPosition);
        }
        /// <summary>
        /// Called when this part enters a collision with another object.
        /// </summary>
        /// <param name="collision">Collision object containing information about the collision.</param>
        protected virtual void OnCollisionEnter(Collision collision)
        {
            if (!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            //Transform the velocity of the collision into the reference frame of the part.
            Vector3 relativeVelocity = part.transform.InverseTransformDirection(collision.relativeVelocity);

            float angle = Vector3.Angle(relativeVelocity, part.transform.InverseTransformDirection(collision.contacts[0].normal));

            //If collision occurs under a large angle, damage is ignored for now.
            //TODO: angle: [70, 90>: SCRAPING. ADD TEXTURES?
            if (angle > 70)
            {
                return;
            }

            //Convert angle to [0, 1].
            angle = Mathf.Cos(Mathf.Deg2Rad * angle);

            //Scale the impact velocity by the angle.
            relativeVelocity *= angle;

            ////Limit collisions to one per collision delay.
            //if (_collisionDelayCounter < _collisionDelay)
            //    return;

            ////Reset the physics counter.
            //_collisionDelayCounter = 0;

            //Only receive damage if part exists and relative velocity is greater than the original tolerance divided malleability of the part.
            if (part == null || relativeVelocity.magnitude <= OriginalCrashTolerance)
            {
                return;
            }

            //No need to do anything if the damage is neglible.
            if (relativeVelocity.magnitude / part.crashTolerance <= 0)
            {
                return;
            }

            Krash krash = new Krash
            {
                RelativeVelocity = relativeVelocity,

                //Transform the direction of the collision to the reference frame of the part.
                ContactPoint = part.transform.InverseTransformPoint(collision.contacts[0].point),
            };

            Krashes.Add(krash);

            ApplyKrash(krash);
        }
Ejemplo n.º 3
0
        protected virtual void FixedUpdate()
        {
            if (!HighLogic.LoadedSceneIsFlight || part == null)
            {
                _splashed = false;
                return;
            }

            //Shield highlight decay
            shieldVisible -= (float)0.006;
            shieldVisible  = Math.Min(1, Math.Max(0, shieldVisible));
            SetHighlighting();

            //Get the altitude of the part, instead of the altitude of the vessel.
            double partAltitude = FlightGlobals.getAltitudeAtPos(part.transform.position, FlightGlobals.currentMainBody);

            if (partAltitude > 0)
            {
                return;
            }

            //Only receive damage if part's velocity is greater than the original tolerance divided malleability of the part.
            double scaledHorizontalSpeed = part.vessel.horizontalSrfSpeed / HorizontalSplashdownScaling;

            if (part.vessel.verticalSpeed + scaledHorizontalSpeed <= (OriginalCrashTolerance / Malleability))
            {
                return;
            }

            //Already splashed down.
            if (_splashed)
            {
                return;
            }

            _splashed = true;

            //Closest part to the core (lowest point on the collider). This should be faster than checking all vertices.
            Vector3 contactPoint = part.collider.ClosestPointOnBounds(FlightGlobals.currentMainBody.position);

            //Transform the direction of the collision to the reference frame of the part and scale it down a bit to match the actual mesh a bit better.
            contactPoint = part.transform.InverseTransformPoint(contactPoint) / part.collider.bounds.size.magnitude;

            Krash krash = new Krash
            {
                ContactPoint     = contactPoint,
                RelativeVelocity = new Vector3((float)scaledHorizontalSpeed, (float)part.vessel.verticalSpeed),
            };

            //Fire "Splashdown" event.
            if (Splashdown != null)
            {
                Splashdown(this, krash);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Called when this part gets loaded.
        /// </summary>
        /// <param name="node"></param>
        public override void OnLoad(ConfigNode node)
        {
            base.OnLoad(node);

            //No need to load krashes when not in Flight Scene or non-existent parts/vessels.
            if (!HighLogic.LoadedSceneIsFlight || part == null || part.vessel == null)
            {
                return;
            }

#if DEBUG
            Debug.Log($"OnLoad: {part.name}");
#endif

            //Clear damage and krashes.
            Damage  = 0;
            Krashes = new List <Krash>();

            foreach (ConfigNode cn in node.nodes)
            {
                if (cn.name != "Krash")
                {
                    continue; //No krash to apply.
                }
                Vector3 relativeVelocity = new Vector3(float.Parse(cn.GetValue("RelativeVelocity.x")), float.Parse(cn.GetValue("RelativeVelocity.y")), float.Parse(cn.GetValue("RelativeVelocity.z")));
                Vector3 contactPoint     = new Vector3(float.Parse(cn.GetValue("ContactPoint.x")), float.Parse(cn.GetValue("ContactPoint.y")), float.Parse(cn.GetValue("ContactPoint.z")));

                Krash krash = new Krash
                {
                    //Load the relative velocity of the saved krash.
                    RelativeVelocity = relativeVelocity,

                    //Load the position of the saved krash.
                    ContactPoint = contactPoint,
                };

                Krashes.Add(krash);

                ApplyKrash(krash);
            }

#if DEBUG
            if (Krashes.Count > 0)
            {
                Debug.Log($"[KerbalKrashSystem] Loaded {Krashes.Count} krashes for {part.name} (part ID: {part.flightID})");
            }
#endif
        }
        //private bool subdivided = false;

        /// <summary>
        /// Apply krash to all meshes in this part.
        /// </summary>
        /// <param name="krash">Krash to apply.</param>
        /// <param name="fireEvent">Fire "DamageReceived" event.</param>
        public void ApplyKrash(Krash krash, bool fireEvent = true)
        {
            Vector3 relativeVelocity = part.transform.TransformDirection(krash.RelativeVelocity); //Transform the direction of the collision to the world reference frame.

            Damage += (relativeVelocity.magnitude / part.crashTolerance) / _damageDivider;

            //Fire "DamageReceived" event.
            if (fireEvent && DamageReceived != null)
            {
                DamageReceived(this, Damage);
            }

            if (_exclude)
            {
                return;
            }

            Vector3 transform     = (relativeVelocity / (1f * part.partInfo.partSize) / (part.crashTolerance / Malleability));
            Vector3 worldPosition = part.transform.TransformPoint(krash.ContactPoint);

            DeformMesh(transform, worldPosition);

            DeformCollider(transform, worldPosition);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Called when this part enters a collision with another object.
        /// </summary>
        /// <param name="collision">Collision object containing information about the collision.</param>
        protected virtual void OnCollisionEnter(Collision collision)
        {
            //Only receive damage if part exists and relative velocity is greater than the original tolerance divided malleability of the part.
            if (part == null || collision.relativeVelocity.magnitude <= (OriginalCrashTolerance / Malleability))
            {
                return;
            }

            //TODO: Temporary fix.
            foreach (ContactPoint contactPoint in collision.contacts)
            {
                if (contactPoint.thisCollider is WheelCollider || contactPoint.otherCollider is WheelCollider)
                {
                    return;
                }
            }

            //No need to do anything if the damage is neglible.
            if (collision.relativeVelocity.magnitude / part.crashTolerance <= 0)
            {
                return;
            }

            Krash krash = new Krash
            {
                //Transform the velocity of the collision into the reference frame of the part.
                RelativeVelocity = part.transform.InverseTransformDirection(collision.relativeVelocity),

                //Transform the direction of the collision to the reference frame of the part.
                ContactPoint = part.transform.InverseTransformPoint(collision.contacts[0].point),
            };

            Krashes.Add(krash);

            ApplyKrash(krash);
        }
Ejemplo n.º 7
0
        private void OnSplashdown(KerbalKrashSystem sender, Krash krash)
        {
            Krashes.Add(krash);

            ApplyKrash(krash);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Called when this part enters a collision with another object.
        /// </summary>
        /// <param name="collision">Collision object containing information about the collision.</param>
        protected virtual void OnCollisionEnter(Collision collision)
        {
            if (!HighLogic.LoadedSceneIsFlight || (vessel != null && vessel.isEVA))
            {
                return;
            }

            //Transform the velocity of the collision into the reference frame of the part.
            Vector3 relativeVelocity = part.transform.InverseTransformDirection(collision.relativeVelocity);

            float angle = Vector3.Angle(relativeVelocity, part.transform.InverseTransformDirection(collision.contacts[0].normal));

            //If collision occurs under a large angle, damage is ignored for now.
//            if (angle > 70)
//            {
//                //TODO: angle: [70, 90>: SCRAPING. ADD TEXTURES?
//#if DEBUG
//                Debug.Log("Angle too steep, no damage.");
//#endif
//                return;
//            }

            //Convert angle to [0, 1].
            angle = Mathf.Cos(Mathf.Deg2Rad * angle);

            //Scale the impact velocity by the angle.
            relativeVelocity *= angle;

            //Only receive damage if part exists and relative velocity is greater than the original tolerance divided malleability of the part.
            if (part == null || relativeVelocity.magnitude <= OriginalCrashTolerance)
            {
                return;
            }

            //No need to do anything if the damage is neglible.
            if (relativeVelocity.magnitude / part.crashTolerance <= 0)
            {
                return;
            }

            //Clamp the local position to the bounds of the part.
            Vector3 local_position = part.transform.InverseTransformPoint(collision.contacts[0].point);

            local_position = new Vector3
                             (
                Mathf.Clamp(local_position.x, -part.collider.bounds.extents.x, part.collider.bounds.extents.x),
                Mathf.Clamp(local_position.y, -part.collider.bounds.extents.y, part.collider.bounds.extents.y),
                Mathf.Clamp(local_position.z, -part.collider.bounds.extents.z, part.collider.bounds.extents.z)
                             );

            Krash krash = new Krash
            {
                RelativeVelocity = relativeVelocity,

                //Transform the direction of the collision to the reference frame of the part.
                ContactPoint = local_position,
            };

            Krashes.Add(krash);

            ApplyKrash(krash);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Apply krash to all meshes in this part.
        /// </summary>
        /// <param name="krash">Krash to apply.</param>
        /// <param name="inverse">Apply or undo krash.</param>
        protected void ApplyKrash(Krash krash)
        {
            Vector3 relativeVelocity = part.transform.TransformDirection(krash.RelativeVelocity); //Transform the direction of the collision to the world reference frame.

            Damage += (relativeVelocity.magnitude / part.crashTolerance);

            Vector3 worldPosContact = part.transform.TransformPoint(krash.ContactPoint);

            MeshFilter[] meshList = part.FindModelComponents <MeshFilter>();

            Vector3 transform = (relativeVelocity / (1f * part.partInfo.partSize) / (part.crashTolerance / Malleability));
            float   invSqrt3  = 1f / Mathf.Sqrt(3);

            foreach (MeshFilter meshFilter in meshList)
            {
                Mesh mesh = meshFilter.mesh;

                if (meshFilter.sharedMesh == null)
                {
                    continue;
                }

                if (mesh == null)
                {
                    mesh = meshFilter.sharedMesh;
                }

                Vector3 transformT        = meshFilter.transform.InverseTransformVector(transform);
                Vector3 contactPointLocal = meshFilter.transform.InverseTransformPoint(worldPosContact);
                Vector3 dentDistanceLocal = meshFilter.transform.TransformDirection(Vector3.one).normalized;
                dentDistanceLocal = meshFilter.transform.InverseTransformVector(DentDistance * dentDistanceLocal);
                dentDistanceLocal = Vector3.Max(-dentDistanceLocal, dentDistanceLocal);
                Vector3 dentDistanceInv;
                dentDistanceInv.x = invSqrt3 / dentDistanceLocal.x;
                dentDistanceInv.y = invSqrt3 / dentDistanceLocal.y;
                dentDistanceInv.z = invSqrt3 / dentDistanceLocal.z;

                Vector3[] vertices = mesh.vertices;
                for (int i = 0; i < vertices.Length; i++)
                {
                    Vector3 distance = vertices[i] - contactPointLocal;
                    distance = Vector3.Max(-distance, distance);
                    distance = dentDistanceLocal - distance;
                    distance.Scale(dentDistanceInv);

                    if (distance.x < 0 || distance.y < 0 || distance.z < 0)
                    {
                        continue;
                    }

                    vertices[i] += distance.sqrMagnitude * transformT;
                }

                mesh.vertices   = vertices;
                meshFilter.mesh = mesh;
            }

            //Fire "DamageReceived" event.
            if (DamageReceived != null)
            {
                DamageReceived(this, Damage);
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Called when this part gets loaded.
        /// </summary>
        /// <param name="node"></param>
        public override void OnLoad(ConfigNode node)
        {
            base.OnLoad(node);

            //No need to load krashes when not in Flight Scene or non-existent parts/vessels.
            if (!HighLogic.LoadedSceneIsFlight || part == null || part.vessel == null)
                return;

            //Clear damage and krashes.
            Damage = 0;
            Krashes = new List<Krash>();

            foreach (ConfigNode cn in node.nodes)
            {
                if (cn.name != "Krash")
                    continue; //No krash to apply.

                Vector3 relativeVelocity = new Vector3(float.Parse(cn.GetValue("RelativeVelocity.x")), float.Parse(cn.GetValue("RelativeVelocity.y")), float.Parse(cn.GetValue("RelativeVelocity.z")));
                Vector3 contactPoint = new Vector3(float.Parse(cn.GetValue("ContactPoint.x")), float.Parse(cn.GetValue("ContactPoint.y")), float.Parse(cn.GetValue("ContactPoint.z")));

                Krash krash = new Krash
                {
                    //Load the relative velocity of the saved krash.
                    RelativeVelocity = relativeVelocity,

                    //Load the position of the saved krash.
                    ContactPoint = contactPoint,
                };

                Krashes.Add(krash);

                ApplyKrash(krash);
            }

            #if DEBUG
            if (Krashes.Count > 0)
                Debug.Log("[KerbalKrashSystem] Applied " + Krashes.Count + " krashes for part ID: " + part.flightID);
            #endif
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Called when this part enters a collision with another object.
        /// </summary>
        /// <param name="collision">Collision object containing information about the collision.</param>
        protected virtual void OnCollisionEnter(Collision collision)
        {
            //Only receive damage if part exists and relative velocity is greater than the original tolerance divided malleability of the part.
            if (part == null || collision.relativeVelocity.magnitude <= (OriginalCrashTolerance / Malleability))
                return;

            //TODO: Temporary fix.
            foreach (ContactPoint contactPoint in collision.contacts)
            {
                if (contactPoint.thisCollider is WheelCollider || contactPoint.otherCollider is WheelCollider)
                    return;
            }

            //No need to do anything if the damage is neglible.
            if (collision.relativeVelocity.magnitude / part.crashTolerance <= 0)
                return;

            Krash krash = new Krash
            {
                //Transform the velocity of the collision into the reference frame of the part. 
                RelativeVelocity = part.transform.InverseTransformDirection(collision.relativeVelocity),

                //Transform the direction of the collision to the reference frame of the part.
                ContactPoint = part.transform.InverseTransformPoint(collision.contacts[0].point),
            };

            Krashes.Add(krash);

            ApplyKrash(krash);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Apply krash to all meshes in this part.
        /// </summary>
        /// <param name="krash">Krash to apply.</param>
        /// <param name="inverse">Apply or undo krash.</param>
        protected void ApplyKrash(Krash krash)
        {
            Vector3 relativeVelocity = part.transform.TransformDirection(krash.RelativeVelocity); //Transform the direction of the collision to the world reference frame.

            Damage += (relativeVelocity.magnitude / part.crashTolerance);

            Vector3 worldPosContact = part.transform.TransformPoint(krash.ContactPoint);
            MeshFilter[] meshList = part.FindModelComponents<MeshFilter>();

            Vector3 transform = (relativeVelocity / (1f * part.partInfo.partSize) / (part.crashTolerance / Malleability));
            float invSqrt3 = 1f/Mathf.Sqrt(3);

            foreach (MeshFilter meshFilter in meshList)
            {
                Mesh mesh = meshFilter.mesh;

                if (meshFilter.sharedMesh == null)
                    continue;

                if (mesh == null)
                    mesh = meshFilter.sharedMesh;

                Vector3 transformT = meshFilter.transform.InverseTransformVector(transform);
                Vector3 contactPointLocal = meshFilter.transform.InverseTransformPoint(worldPosContact);
                Vector3 dentDistanceLocal = meshFilter.transform.TransformDirection(Vector3.one).normalized;
                dentDistanceLocal = meshFilter.transform.InverseTransformVector(DentDistance * dentDistanceLocal);
                dentDistanceLocal = Vector3.Max(-dentDistanceLocal, dentDistanceLocal);
                Vector3 dentDistanceInv;
                dentDistanceInv.x = invSqrt3 / dentDistanceLocal.x;
                dentDistanceInv.y = invSqrt3 / dentDistanceLocal.y;
                dentDistanceInv.z = invSqrt3 / dentDistanceLocal.z;
                
                Vector3[] vertices = mesh.vertices;
                for (int i = 0; i < vertices.Length; i++)
                {
                    Vector3 distance = vertices[i] - contactPointLocal;
                    distance = Vector3.Max(-distance, distance);
                    distance = dentDistanceLocal - distance;
                    distance.Scale(dentDistanceInv);

                    if (distance.x < 0 || distance.y < 0 || distance.z < 0)
                        continue;
                    
                    vertices[i] += distance.sqrMagnitude * transformT;
                }

                mesh.vertices = vertices;
                meshFilter.mesh = mesh;
            }

            //Fire "DamageReceived" event.
            if (DamageReceived != null)
                DamageReceived(this, Damage);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Called when this part enters a collision with another object.
        /// </summary>
        /// <param name="collision">Collision object containing information about the collision.</param>
        protected virtual void OnCollisionEnter(Collision collision)
        {
            if (!HighLogic.LoadedSceneIsFlight || vessel.isEVA)
            {
                return;
            }

            //Transform the velocity of the collision into the reference frame of the part.
            Vector3 relativeVelocity = part.transform.InverseTransformDirection(collision.relativeVelocity);

            float angle = Vector3.Angle(relativeVelocity, part.transform.InverseTransformDirection(collision.contacts[0].normal));

            //If collision occurs under a large angle, damage is ignored for now.
            //            if (angle > 70)
            //            {
            //                //TODO: angle: [70, 90>: SCRAPING. ADD TEXTURES?
            //#if DEBUG
            //                Debug.Log("Angle too steep, no damage.");
            //#endif
            //                return;
            //            }

            //Convert angle to [0, 1].
            angle = Mathf.Cos(Mathf.Deg2Rad * angle);

            //Scale the impact velocity by the angle.
            relativeVelocity *= angle;

            //Impact damage drains shield charge until zero, then causes residual damage to part
            if (part.Resources.Contains("ShieldCharge") && relativeVelocity.magnitude > 5)
            {
                double charge    = part.Resources.Get("ShieldCharge").amount;
                double maxCharge = part.Resources.Get("ShieldCharge").maxAmount;
                double impact    = relativeVelocity.magnitude * part.mass;
                impact *= 0.5;  //scale down impact force
                if (charge >= impact)
                {
                    part.RequestResource(ShieldCharge.id, impact);
                    relativeVelocity *= 0;
                    shieldVisible    += (float)(impact / maxCharge * 2.0);
                }
                else
                {
                    part.RequestResource(ShieldCharge.id, charge);
                    relativeVelocity *= (float)(1 - charge / impact);
                    shieldVisible    += (float)(charge / maxCharge * 2.0);
                }
                shieldVisible = Math.Min(1, Math.Max(0, shieldVisible));
            }

            //Only receive damage if part exists and relative velocity is greater than the original tolerance divided malleability of the part.
            if (part == null || relativeVelocity.magnitude <= OriginalCrashTolerance)
            {
                return;
            }

            //No need to do anything if the damage is neglible.
            if (relativeVelocity.magnitude / part.crashTolerance <= 0)
            {
                return;
            }

            Krash krash = new Krash
            {
                RelativeVelocity = relativeVelocity,

                //Transform the direction of the collision to the reference frame of the part.
                ContactPoint = part.transform.InverseTransformPoint(collision.contacts[0].point),
            };

            Krashes.Add(krash);

            ApplyKrash(krash);
        }