Ejemplo n.º 1
0
        public void vesselDestroyEvent(Vessel v)
        {
            if (!KCT_GameStates.settings.enabledForSave)
            {
                return;
            }
            Dictionary <string, int> PartsRecovered = new Dictionary <string, int>();
            float         FundsRecovered = 0, KSCDistance = 0, RecoveryPercent = 0;
            StringBuilder Message = new StringBuilder();

            if (FlightGlobals.fetch == null)
            {
                return;
            }

            if (v != null && !(HighLogic.LoadedSceneIsFlight && v.isActiveVessel) && v.mainBody.bodyName == "Kerbin" && (!v.loaded || v.packed) && v.altitude < 35000 &&
                (v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.SUB_ORBITAL) && !v.isEVA)
            {
                double totalMass      = 0;
                double dragCoeff      = 0;
                bool   realChuteInUse = false;

                float RCParameter = 0;

                if (!v.packed) //adopted from mission controller.
                {
                    foreach (Part p in v.Parts)
                    {
                        p.Pack();
                    }
                }

                if (v.protoVessel == null)
                {
                    return;
                }
                KCTDebug.Log("Attempting to recover vessel.");
                try
                {
                    foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                    {
                        //KCTDebug.Log("Has part " + p.partName + ", mass " + p.mass);
                        List <string> ModuleNames = new List <string>();
                        foreach (ProtoPartModuleSnapshot ppms in p.modules)
                        {
                            //Debug.Log(ppms.moduleName);
                            ModuleNames.Add(ppms.moduleName);
                        }
                        totalMass += p.mass;
                        totalMass += GetResourceMass(p.resources);
                        bool isParachute = false;
                        if (ModuleNames.Contains("ModuleParachute"))
                        {
                            KCTDebug.Log("Found parachute module on " + p.partInfo.name);
                            //Find the ModuleParachute (find it in the module list by checking for a module with the name ModuleParachute)
                            ProtoPartModuleSnapshot ppms = p.modules.First(mod => mod.moduleName == "ModuleParachute");
                            float drag = 500;
                            if (ppms.moduleRef != null)
                            {
                                ModuleParachute mp = (ModuleParachute)ppms.moduleRef;
                                mp.Load(ppms.moduleValues);
                                drag = mp.fullyDeployedDrag;
                            }
                            //Add the part mass times the fully deployed drag (typically 500) to the dragCoeff variable (you'll see why later)
                            dragCoeff += p.mass * drag;
                            //This is most definitely a parachute part
                            isParachute = true;
                        }
                        if (ModuleNames.Contains("RealChuteModule"))
                        {
                            KCTDebug.Log("Found realchute module on " + p.partInfo.name);
                            ProtoPartModuleSnapshot realChute = p.modules.First(mod => mod.moduleName == "RealChuteModule");
                            if ((object)realChute != null) //Some of this was adopted from DebRefund, as Vendan's method of handling multiple parachutes is better than what I had.
                            {
                                Type matLibraryType = AssemblyLoader.loadedAssemblies
                                                      .SelectMany(a => a.assembly.GetExportedTypes())
                                                      .SingleOrDefault(t => t.FullName == "RealChute.Libraries.MaterialsLibrary");

                                ConfigNode[] parchutes = realChute.moduleValues.GetNodes("PARACHUTE");
                                foreach (ConfigNode chute in parchutes)
                                {
                                    float  diameter = float.Parse(chute.GetValue("deployedDiameter"));
                                    string mat      = chute.GetValue("material");
                                    System.Reflection.MethodInfo matMethod = matLibraryType.GetMethod("GetMaterial", new Type[] { mat.GetType() });
                                    object MatLibraryInstance = matLibraryType.GetProperty("instance").GetValue(null, null);
                                    object materialObject     = matMethod.Invoke(MatLibraryInstance, new object[] { mat });
                                    float  dragC = (float)KCT_Utilities.GetMemberInfoValue(materialObject.GetType().GetMember("dragCoefficient")[0], materialObject);

                                    RCParameter += dragC * (float)Math.Pow(diameter, 2);
                                }
                                isParachute    = true;
                                realChuteInUse = true;
                            }
                        }
                        if (!isParachute)
                        {
                            if (p.partRef != null)
                            {
                                dragCoeff += p.mass * p.partRef.maximum_drag;
                            }
                            else
                            {
                                dragCoeff += p.mass * 0.2;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.LogError("[KCT] Error while attempting to recover vessel.");
                    Debug.LogException(e);
                }
                double Vt = double.MaxValue;
                if (!realChuteInUse)
                {
                    dragCoeff = dragCoeff / (totalMass);
                    Vt        = Math.Sqrt((250 * 6.674E-11 * 5.2915793E22) / (3.6E11 * 1.22309485 * dragCoeff));
                    KCTDebug.Log("Using Stock Module! Drag: " + dragCoeff + " Vt: " + Vt);
                }
                else
                {
                    Vt = Math.Sqrt((8000 * totalMass * 9.8) / (1.223 * Math.PI) * Math.Pow(RCParameter, -1)); //This should work perfect for multiple identical chutes and gives an approximation for multiple differing chutes
                    KCTDebug.Log("Using RealChute Module! Vt: " + Vt);
                }
                if (Vt < 10.0)
                {
                    KCTDebug.Log("Recovered parts from " + v.vesselName);
                    foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                    {
                        KCT_Utilities.AddPartToInventory(p.partInfo.name + KCT_Utilities.GetTweakScaleSize(p));
                        if (!PartsRecovered.ContainsKey(p.partInfo.title))
                        {
                            PartsRecovered.Add(p.partInfo.title, 1);
                        }
                        else
                        {
                            ++PartsRecovered[p.partInfo.title];
                        }
                    }

                    Message.AppendLine("Vessel name: " + v.vesselName);
                    Message.AppendLine("Parts recovered: ");
                    for (int i = 0; i < PartsRecovered.Count; i++)
                    {
                        Message.AppendLine(PartsRecovered.Values.ElementAt(i) + "x " + PartsRecovered.Keys.ElementAt(i));
                    }

                    if (KCT_Utilities.CurrentGameIsCareer())
                    {
                        if (KCT_Utilities.StageRecoveryAddonActive || KCT_Utilities.DebRefundAddonActive) //Delegate funds handling to Stage Recovery or DebRefund if it's present
                        {
                            KCTDebug.Log("Delegating Funds recovery to another addon.");
                        }
                        else  //Otherwise do it ourselves
                        {
                            bool probeCoreAttached = false;
                            foreach (ProtoPartSnapshot pps in v.protoVessel.protoPartSnapshots)
                            {
                                if (pps.modules.Find(module => (module.moduleName == "ModuleCommand" && ((ModuleCommand)module.moduleRef).minimumCrew == 0)) != null)
                                {
                                    KCTDebug.Log("Probe Core found!");
                                    probeCoreAttached = true;
                                    break;
                                }
                            }
                            float RecoveryMod = probeCoreAttached ? 1.0f : KCT_GameStates.settings.RecoveryModifier;
                            KSCDistance = (float)SpaceCenter.Instance.GreatCircleDistance(SpaceCenter.Instance.cb.GetRelSurfaceNVector(v.protoVessel.latitude, v.protoVessel.longitude));
                            double maxDist = SpaceCenter.Instance.cb.Radius * Math.PI;
                            RecoveryPercent = RecoveryMod * Mathf.Lerp(0.98f, 0.1f, (float)(KSCDistance / maxDist));
                            float totalReturn = 0;
                            foreach (ProtoPartSnapshot pps in v.protoVessel.protoPartSnapshots)
                            {
                                float dryCost, fuelCost;
                                totalReturn += Math.Max(ShipConstruction.GetPartCosts(pps, pps.partInfo, out dryCost, out fuelCost), 0);
                            }
                            float totalBeforeModifier = totalReturn;
                            totalReturn   *= RecoveryPercent;
                            FundsRecovered = totalReturn;
                            KCTDebug.Log("Vessel being recovered by KCT. Percent returned: " + 100 * RecoveryPercent + "%. Distance from KSC: " + Math.Round(KSCDistance / 1000, 2) + " km");
                            KCTDebug.Log("Funds being returned: " + Math.Round(totalReturn, 2) + "/" + Math.Round(totalBeforeModifier, 2));

                            Message.AppendLine("Funds recovered: " + FundsRecovered + "(" + Math.Round(RecoveryPercent * 100, 1) + "%)");
                            KCT_Utilities.AddFunds(FundsRecovered);
                        }
                    }
                    Message.AppendLine("\nAdditional information:");
                    Message.AppendLine("Distance from KSC: " + Math.Round(KSCDistance / 1000, 2) + " km");
                    if (!realChuteInUse)
                    {
                        Message.AppendLine("Stock module used. Terminal velocity (less than 10 needed): " + Math.Round(Vt, 2));
                    }
                    else
                    {
                        Message.AppendLine("RealChute module used. Terminal velocity (less than 10 needed): " + Math.Round(Vt, 2));
                    }
                    if (!(KCT_Utilities.StageRecoveryAddonActive || KCT_Utilities.DebRefundAddonActive) &&
                        (KCT_Utilities.CurrentGameIsCareer() || !KCT_GUI.PrimarilyDisabled) &&
                        !(KCT_GameStates.settings.DisableAllMessages || KCT_GameStates.settings.DisableRecoveryMessages))
                    {
                        KCT_Utilities.DisplayMessage("Stage Recovered", Message, MessageSystemButton.MessageButtonColor.BLUE, MessageSystemButton.ButtonIcons.MESSAGE);
                    }
                }
            }
        }