private static IEnumerable <ScienceSubject> GetSubjects(ScienceExperiment experiment, CelestialBody body, Func <string, bool> biomeFilter, bool difficult)
        {
            IEnumerable <ExperimentSituations> situations = Enum.GetValues(typeof(ExperimentSituations)).Cast <ExperimentSituations>();

            // Set up the biome filter
            bool biomesFiltered = biomeFilter != null;

            if (biomeFilter == null)
            {
                biomeFilter = new Func <string, bool>(x => true);
            }

            IEnumerable <string> biomes = body.BiomeMap == null?Enumerable.Empty <string>() :
                                              body.BiomeMap.Attributes.Select(attr => attr.name.Replace(" ", string.Empty)).
                                              Where(biomeFilter);

            return(situations
                   .Where(sit => ExperimentAvailable(experiment, sit, body) &&
                          (sit != ExperimentSituations.SrfSplashed || body.ocean) &&
                          ((sit != ExperimentSituations.FlyingLow && sit != ExperimentSituations.FlyingHigh) || body.atmosphere))
                   .SelectMany <ExperimentSituations, ScienceSubject>(sit =>
            {
                if (experiment.BiomeIsRelevantWhile(sit))
                {
                    ExperimentRules rules = GetExperimentRules(experiment.id);

                    return biomes.Where(biome => !(BiomeTracker.IsDifficult(body, biome, sit) || experiment.id == "asteroidSample") ^ difficult)
                    .Select(biome => ScienceSubject(experiment, sit, body, biome))
                    .Union(body.isHomeWorld && !rules.disallowKSC && sit == ExperimentSituations.SrfLanded         // static KSC items can only be landed
                                ? Biome.KSCBiomes.Where(biomeFilter).Where(b => experiment.id == "asteroidSample" ^ !difficult).Select(
                               staticName =>
                               ScienceSubject(experiment, ExperimentSituations.SrfLanded, body, staticName))
                                        : Enumerable.Empty <ScienceSubject>());
                }
                else if (experiment.id.StartsWith("ROCScience") && biomesFiltered)
                {
                    ROCDefinition roc = ROCManager.Instance.rocDefinitions.Where(r => r.myCelestialBodies.Any(x => x.name == body.name) && experiment.id.Contains(r.type)).FirstOrDefault();
                    if (roc != null && roc.myCelestialBodies.First().biomes.Where(biomeFilter).Any())
                    {
                        return new ScienceSubject[] { ScienceSubject(experiment, sit, body, "") };
                    }
                    else
                    {
                        return Enumerable.Empty <ScienceSubject>();
                    }
                }
                else if (!biomesFiltered && !difficult)
                {
                    return new ScienceSubject[] { ScienceSubject(experiment, sit, body, "") };
                }
                else
                {
                    return Enumerable.Empty <ScienceSubject>();
                }
            }));
        }
        /// <summary>
        /// parts that have experiments can't get their module info (what is shown in the VAB tooltip) correctly setup
        /// because the ExperimentInfo database isn't available at loading time, so we recompile their info manually.
        /// </summary>
        public void CompileModuleInfos()
        {
            if (PartLoader.LoadedPartsList == null)
            {
                Lib.Log("Dazed and confused: PartLoader.LoadedPartsList == null");
                return;
            }

            foreach (AvailablePart ap in PartLoader.LoadedPartsList)
            {
                if (ap == null || ap.partPrefab == null)
                {
                    Lib.Log("AvailablePart is null or without prefab: " + ap);
                    continue;
                }

                foreach (PartModule module in ap.partPrefab.Modules)
                {
                    if (module is Experiment expModule)
                    {
                        // don't show configurable experiments
                        if (!expModule.isConfigurable && expModule.experiment_id == ExperimentId)
                        {
                            expModule.ExpInfo = this;

                            // get module info for the ExperimentInfo, once
                            if (string.IsNullOrEmpty(ModuleInfo))
                            {
                                ModuleInfo  = Lib.Color(Title, Lib.Kolor.Cyan, true);
                                ModuleInfo += "\n";
                                ModuleInfo += expModule.GetInfo();
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(ModuleInfo))
                    {
                        continue;
                    }

                    if (module is ModuleScienceExperiment stockExpModule)
                    {
                        if (stockExpModule.experimentID == ExperimentId)
                        {
                            ModuleInfo  = Lib.Color(Title, Lib.Kolor.Cyan, true);
                            ModuleInfo += "\n" + Local.Experimentinfo_Datasize + ": ";                         //Data size
                            ModuleInfo += Lib.HumanReadableDataSize(DataSize);
                            if (stockExpModule.xmitDataScalar < Science.maxXmitDataScalarForSample)
                            {
                                ModuleInfo += "\n" + Local.Experimentinfo_generatesample;                              //Will generate a sample.
                                ModuleInfo += "\n" + Local.Experimentinfo_Samplesize + " ";                            //Sample size:
                                ModuleInfo += Lib.HumanReadableSampleSize(DataSize);
                            }
                            ModuleInfo += "\n\n";
                            ModuleInfo += Lib.Color(Local.Experimentinfo_Situations, Lib.Kolor.Cyan, true);                            //"Situations:\n"

                            foreach (string s in AvailableSituations())
                            {
                                ModuleInfo += Lib.BuildString("• <b>", s, "</b>\n");
                            }

                            ModuleInfo += "\n";
                            ModuleInfo += stockExpModule.GetInfo();
                        }
                    }
                    else if (module is ModuleGroundExperiment groundExpModule)
                    {
                        if (groundExpModule.experimentId == ExperimentId)
                        {
                            ModuleInfo  = Lib.Color(Title, Lib.Kolor.Cyan, true);
                            ModuleInfo += "\n" + Local.Experimentinfo_Datasize + ": ";                            //Data size
                            ModuleInfo += Lib.HumanReadableDataSize(DataSize);
                            ModuleInfo += "\n\n";
                            ModuleInfo += groundExpModule.GetInfo();
                        }
                    }
                }

                // special cases
                if (ExperimentId == "asteroidSample" || ExperimentId.StartsWith("cometSample_", StringComparison.Ordinal))
                {
                    ModuleInfo  = Local.Experimentinfo_Asteroid;                   //"Asteroid samples can be taken by kerbals on EVA"
                    ModuleInfo += "\n" + Local.Experimentinfo_Samplesize + " ";    //Sample size:
                    ModuleInfo += Lib.HumanReadableSampleSize(DataSize);
                    ModuleInfo += "\n" + Local.Experimentinfo_Samplemass + " ";    //Sample mass:
                    ModuleInfo += Lib.HumanReadableMass(DataSize * Settings.AsteroidSampleMassPerMB);
                }
                else if (IsROC)
                {
                    string        rocType = ExperimentId.Substring(ExperimentId.IndexOf('_') + 1);
                    ROCDefinition rocDef  = ROCManager.Instance.rocDefinitions.Find(p => p.type == rocType);
                    if (rocDef != null)
                    {
                        ModuleInfo  = Lib.Color(rocDef.displayName, Lib.Kolor.Cyan, true);
                        ModuleInfo += "\n- " + Local.Experimentinfo_scannerarm;                        //Analyse with a scanner arm
                        ModuleInfo += "\n  " + Local.Experimentinfo_Datasize + ": ";                   //Data size
                        ModuleInfo += Lib.HumanReadableDataSize(DataSize);

                        if (rocDef.smallRoc)
                        {
                            ModuleInfo += "\n- " + Local.Experimentinfo_smallRoc;                            //Collectable on EVA as a sample"
                            ModuleInfo += "\n" + Local.Experimentinfo_Samplesize + " ";                      //Sample size:
                            ModuleInfo += Lib.HumanReadableSampleSize(DataSize);
                        }
                        else
                        {
                            ModuleInfo += "\n- " + Local.Experimentinfo_smallRoc2;                          //Can't be collected on EVA
                        }

                        foreach (RocCBDefinition body in rocDef.myCelestialBodies)
                        {
                            ModuleInfo += Lib.Color("\n\n" + Local.Experimentinfo_smallRoc3.Format(body.name), Lib.Kolor.Cyan, true);                            //"Found on <<1>>'s :"
                            foreach (string biome in body.biomes)
                            {
                                ModuleInfo += "\n- ";
                                ModuleInfo += biome;
                            }
                        }
                    }
                }
            }
        }
Example #3
0
        /// <summary>
        /// parts that have experiments can't get their module info (what is shown in the VAB tooltip) correctly setup
        /// because the ExperimentInfo database isn't available at loading time, so we recompile their info manually.
        /// </summary>
        public void SetupPrefabs()
        {
            if (PartLoader.LoadedPartsList == null)
            {
                Lib.Log("Dazed and confused: PartLoader.LoadedPartsList == null");
                return;
            }

            foreach (AvailablePart ap in PartLoader.LoadedPartsList)
            {
                if (ap == null || ap.partPrefab == null)
                {
                    Lib.Log("AvailablePart is null or without prefab: " + ap);
                    continue;
                }

                bool partHasExperimentModule = false;

                foreach (PartModule module in ap.partPrefab.Modules)
                {
                    if (module is Experiment expModule)
                    {
                        if (expModule.experiment_id == ExperimentId)
                        {
                            expModule.ExpInfo       = this;                       // works inside the ExperimentInfo ctor, but make sure it's called at the end of it.
                            partHasExperimentModule = true;

                            // get module info for the ExperimentInfo, once
                            if (string.IsNullOrEmpty(ModuleInfo))
                            {
                                ModuleInfo  = Lib.Color(Title, Lib.Kolor.Cyan, true);
                                ModuleInfo += "\n";
                                ModuleInfo += expModule.GetInfo();
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(ModuleInfo))
                    {
                        continue;
                    }

                    if (module is ModuleScienceExperiment stockExpModule)
                    {
                        if (stockExpModule.experimentID == ExperimentId)
                        {
                            ModuleInfo  = Lib.Color(Title, Lib.Kolor.Cyan, true);
                            ModuleInfo += "\nData size: ";
                            ModuleInfo += Lib.HumanReadableDataSize(DataSize);
                            if (stockExpModule.xmitDataScalar < Science.maxXmitDataScalarForSample)
                            {
                                ModuleInfo += "\nWill generate a sample.";
                                ModuleInfo += "\nSample size: ";
                                ModuleInfo += Lib.HumanReadableSampleSize(DataSize);
                            }
                            ModuleInfo += "\n\n";
                            ModuleInfo += Lib.Color("Situations:\n", Lib.Kolor.Cyan, true);

                            foreach (string s in AvailableSituations())
                            {
                                ModuleInfo += Lib.BuildString("• <b>", s, "</b>\n");
                            }

                            ModuleInfo += "\n";
                            ModuleInfo += stockExpModule.GetInfo();
                        }
                    }

#if !KSP15_16
                    else if (module is ModuleGroundExperiment groundExpModule)
                    {
                        if (groundExpModule.experimentId == ExperimentId)
                        {
                            ModuleInfo  = Lib.Color(Title, Lib.Kolor.Cyan, true);
                            ModuleInfo += "\nData size: ";
                            ModuleInfo += Lib.HumanReadableDataSize(DataSize);
                            ModuleInfo += "\n\n";
                            ModuleInfo += groundExpModule.GetInfo();
                        }
                    }
#endif
                }

                // special cases
                if (ExperimentId == "asteroidSample")
                {
                    ModuleInfo  = "Asteroid samples can be taken by kerbals on EVA";
                    ModuleInfo += "\nSample size: ";
                    ModuleInfo += Lib.HumanReadableSampleSize(DataSize);
                    ModuleInfo += "\nSample mass: ";
                    ModuleInfo += Lib.HumanReadableMass(DataSize * Settings.AsteroidSampleMassPerMB);
                }
#if !KSP15_16
                else if (IsROC)
                {
                    string        rocType = ExperimentId.Substring(ExperimentId.IndexOf('_') + 1);
                    ROCDefinition rocDef  = ROCManager.Instance.rocDefinitions.Find(p => p.type == rocType);
                    if (rocDef != null)
                    {
                        ModuleInfo  = Lib.Color(rocDef.displayName, Lib.Kolor.Cyan, true);
                        ModuleInfo += "\n- Analyse with a scanner arm";
                        ModuleInfo += "\n  Data size: ";
                        ModuleInfo += Lib.HumanReadableDataSize(DataSize);

                        if (rocDef.smallRoc)
                        {
                            ModuleInfo += "\n- Collectable on EVA as a sample";
                            ModuleInfo += "\nSample size: ";
                            ModuleInfo += Lib.HumanReadableSampleSize(DataSize);
                        }
                        else
                        {
                            ModuleInfo += "\n- Can't be collected on EVA";
                        }

                        foreach (RocCBDefinition body in rocDef.myCelestialBodies)
                        {
                            ModuleInfo += Lib.Color("\n\nFound on " + body.name + "'s :", Lib.Kolor.Cyan, true);
                            foreach (string biome in body.biomes)
                            {
                                ModuleInfo += "\n- ";
                                ModuleInfo += biome;
                            }
                        }
                    }
                }
#endif


                if (partHasExperimentModule && !ap.name.StartsWith("kerbalEVA"))
                {
                    ap.moduleInfos.Clear();
                    ap.resourceInfos.Clear();
                    try
                    {
                        Lib.ReflectionCall(PartLoader.Instance, "CompilePartInfo", new Type[] { typeof(AvailablePart), typeof(Part) }, new object[] { ap, ap.partPrefab });
                    }
                    catch (Exception ex)
                    {
                        Lib.Log("Could not patch the moduleInfo for part " + ap.name + " - " + ex.Message + "\n" + ex.StackTrace);
                    }
                }
            }
        }