private string BiomeString(ScienceExperiment experiment = null) { if (experiment != null && !experiment.BiomeIsRelevantWhile(ScienceUtil.GetExperimentSituation(vessel))) { return(string.Empty); } if (vessel == null || body == null) { return(string.Empty); } if (body.BiomeMap == null) { return(string.Empty); } var v = vessel.EVALadderVessel; if (!string.IsNullOrEmpty(v.landedAt)) { return(Vessel.GetLandedAtString(v.landedAt)); } else { return(ScienceUtil.GetExperimentBiome(body, v.latitude, v.longitude)); } }
protected string CurrentBiome(ScienceExperiment baseExperiment) { if (!baseExperiment.BiomeIsRelevantWhile(ScienceUtil.GetExperimentSituation(FlightGlobals.ActiveVessel))) { return(string.Empty); } var currentVessel = FlightGlobals.ActiveVessel; var currentBody = FlightGlobals.currentMainBody; if (currentVessel != null && currentBody != null) { if (currentVessel.isEVA) { currentVessel = currentVessel.EVALadderVessel; } if (!string.IsNullOrEmpty(currentVessel.landedAt)) { //big thanks to xEvilReeperx for this one. return(Vessel.GetLandedAtString(currentVessel.landedAt)); } else { return(ScienceUtil.GetExperimentBiome(currentBody, currentVessel.latitude, currentVessel.longitude)); } } else { Log("currentVessel && currentBody == null"); } return(string.Empty); }
//This method handles generating the surface or asteroid sample ScienceData private ScienceData sampleData(ModuleAsteroid m) { ScienceExperiment exp = null; ScienceSubject sub = null; ExperimentSituations expSit; ScienceData data = null; string biome = ""; if (m != null) { exp = asteroidExp; } else { exp = surfaceExp; } if (exp == null) { return(null); } expSit = ScienceUtil.GetExperimentSituation(vessel); if (exp.IsAvailableWhile(expSit, vessel.mainBody)) { if (exp.BiomeIsRelevantWhile(expSit)) { if (!string.IsNullOrEmpty(vessel.landedAt)) { biome = Vessel.GetLandedAtString(vessel.landedAt); } else { biome = ScienceUtil.GetExperimentBiome(vessel.mainBody, vessel.latitude, vessel.longitude); } } if (m != null) { sub = ResearchAndDevelopment.GetExperimentSubject(exp, expSit, m.part.partInfo.name + m.part.flightID, m.part.partInfo.title, vessel.mainBody, biome); } else { sub = ResearchAndDevelopment.GetExperimentSubject(exp, expSit, vessel.mainBody, biome); } if (sub == null) { return(null); } data = new ScienceData(exp.baseValue * exp.dataScale, this.xmitDataScalar, 0f, sub.id, sub.title, false, part.flightID); return(data); } return(null); }
internal static bool CanRunExperiment(Vessel vessel, string expId, ref string msg) { msg = Localizer.Format("#autoLOC_LTech_Util_002"); ScienceExperiment labExp = ResearchAndDevelopment.GetExperiment(expId); if (labExp.IsAvailableWhile((ExperimentSituations)vessel.situation, vessel.mainBody)) { if (labExp.BiomeIsRelevantWhile((ExperimentSituations)vessel.situation)) { return(true); } } if (vessel.situation == Vessel.Situations.LANDED) { if (vessel.situation == Vessel.Situations.LANDED) { return(true); } msg += Localizer.Format("#autoLOC_LTech_Util_003"); } if (vessel.situation == Vessel.Situations.SPLASHED) { if (vessel.situation == Vessel.Situations.SPLASHED) { return(true); } msg += Localizer.Format("#autoLOC_LTech_Util_004"); } if (vessel.situation == Vessel.Situations.FLYING) { if (vessel.altitude <= vessel.orbit.referenceBody.atmosphereDepth) { return(true); } msg += Localizer.Format("#autoLOC_LTech_Util_005"); } if (vessel.situation == Vessel.Situations.ORBITING) { if (vessel.altitude > vessel.orbit.referenceBody.atmosphereDepth) { return(true); } msg += Localizer.Format("#autoLOC_LTech_Util_006"); } msg = msg.Remove(msg.Length - 2); return(false); }
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>(); } })); }
ScienceSubject currentScienceSubject(ScienceExperiment experiment) { string fixBiome = string.Empty; // some biomes don't have 4th string, so we just put an empty in to compare strings later if (experiment.BiomeIsRelevantWhile(currentSituation())) { fixBiome = currentBiome(); // for those that do, we add it to the string } return(ResearchAndDevelopment.GetExperimentSubject(experiment, currentSituation(), currentBody(), fixBiome)); //ikr!, we pretty much did all the work already, jeez }
/// <summary> /// Get the subject ID to use for the vessel's current situation. /// </summary> /// <param name="experiment"></param> /// <param name="vessel"></param> /// <returns></returns> private static string GetSubjectId(ScienceExperiment experiment, Vessel vessel) { string celestialBodyName = vessel.mainBody.name; ExperimentSituations situation = ScienceUtil.GetExperimentSituation(vessel); string biome = GetBiome(vessel); if (experiment.BiomeIsRelevantWhile(situation)) { return(experiment.id + "@" + celestialBodyName + situation.ToString() + biome.Replace(" ", string.Empty)); } else { return(experiment.id + "@" + celestialBodyName + situation.ToString()); } }
private void RunExperiment(ScienceAIExperiment experiment, ExperimentSituations situation, ScienceAIVesselModule mod, Vessel v, String biome) { String currentBiome = String.Empty; ScienceExperiment exp = ResearchAndDevelopment.GetExperiment(experiment.experimentID); if (exp.BiomeIsRelevantWhile(situation)) { currentBiome = v.landedAt != string.Empty ? v.landedAt : biome; } ScienceSubject subj = ResearchAndDevelopment.GetExperimentSubject(exp, situation, v.mainBody, currentBiome, null); if (((subj.scienceCap - subj.science) > 0.1 || mod.collectEmpty) && mod.results.Find(r => r.subjectID == subj.id) == null) { ScienceAIData result = new ScienceAIData(exp.baseValue * exp.dataScale, experiment.xmitDataScalar, 0f, subj.id, subj.title); mod.results.Add(result); if (experiment.rerunnable == false) { experiment.inoperable = true; } } }
private static string currentBiome(ScienceExperiment e, Vessel v) { if (e == null) { return(""); } if (v == null) { return(""); } if (!e.BiomeIsRelevantWhile(ExperimentSituations.SrfLanded)) { return(""); } if (string.IsNullOrEmpty(v.landedAt)) { return(ScienceUtil.GetExperimentBiome(v.mainBody, v.latitude, v.longitude)); } return(Vessel.GetLandedAtString(v.landedAt)); }
private static string currentDisplayBiome(ScienceExperiment e, Vessel v) { if (e == null) { return(""); } if (v == null) { return(""); } if (!e.BiomeIsRelevantWhile(ExperimentSituations.SrfLanded)) { return(""); } if (string.IsNullOrEmpty(v.displaylandedAt)) { return(Localizer.Format(ScienceUtil.GetExperimentBiomeLocalized(v.mainBody, v.latitude, v.longitude))); } return(Localizer.Format(v.displaylandedAt)); }
private string getBiomeForExperiment(ScienceExperiment experiment) { if (experiment.BiomeIsRelevantWhile(currentSituation)) { Utilities.debug(modName, Utilities.LogMode.Debug, experiment.id + ": BiomeIsRelevantWhile: " + currentSituation); return currentBiome(); } Utilities.debug(modName, Utilities.LogMode.Debug, experiment.id + ": BiomeIsNotRelevantWhile: " + currentSituation); return string.Empty; }
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)) { return biomes.Where(biome => !(BiomeTracker.IsDifficult(body, biome, sit) || experiment.id == "asteroidSample") ^ difficult) .Select(biome => ScienceSubject(experiment, sit, body, biome)) .Union(body.isHomeWorld && 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 (!biomesFiltered && !difficult) { return new ScienceSubject[] { ScienceSubject(experiment, sit, body, "") }; } else { return Enumerable.Empty<ScienceSubject>(); } }); }
public virtual bool UpdateStatus(ExperimentSituations experimentSituation, out bool newReport) { newReport = false; if (FlightGlobals.ActiveVessel == null) { Available = false; lastAvailableId = ""; return(false); } if (!settings.Enabled || (requireControllable && !FlightGlobals.ActiveVessel.IsControllable)) { Available = false; lastAvailableId = ""; return(false); } bool lastStatus = Available; var vessel = FlightGlobals.ActiveVessel; if (!storage.IsBusy && IsReadyOnboard) { // does this experiment even apply in the current situation? if (experiment.IsAvailableWhile(experimentSituation, vessel.mainBody)) { var biome = string.Empty; if (experiment.BiomeIsRelevantWhile(experimentSituation)) { // biome matters; check to make sure we have biome data available if (scanInterface.HaveScanData(vessel.latitude, vessel.longitude, vessel.mainBody)) { if (biomeFilter.GetBiome(vessel.latitude, vessel.longitude, out biome)) { lastBiomeQuery = biome; } else { biome = lastBiomeQuery; // use last good known value } } else { // no biome data available Available = false; lastAvailableId = ""; return(false); } } try { var subject = ResearchAndDevelopment.GetExperimentSubject(experiment, experimentSituation, vessel.mainBody, biome, null); List <ScienceData> data = null; float scienceTotal = GetScienceTotal(subject, out data); switch (settings.Filter) { case ExperimentSettings.FilterMethod.Unresearched: // Fairly straightforward: total science + potential should be zero Available = scienceTotal < 0.0005f; break; case ExperimentSettings.FilterMethod.NotMaxed: // <98% of science cap Available = scienceTotal < subject.scienceCap * 0.98f * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; break; case ExperimentSettings.FilterMethod.LessThanFiftyPercent: Available = scienceTotal < subject.scienceCap * 0.5f * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; break; case ExperimentSettings.FilterMethod.LessThanNinetyPercent: Available = scienceTotal < subject.scienceCap * 0.9f * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; break; default: // this should NEVER occur, but nice to have a safety measure // in place if I add a filter option and forget to add its logic Log.Error("Unrecognized experiment filter!"); data = new List <ScienceData>(); break; } nextReportValue = subject.CalculateNextReport(experiment, data); Available = Available && nextReportValue > 0.01f; Available = Available && nextReportValue > ScienceAlertProfileManager.ActiveProfile.ScienceThreshold; if (Available) { if (lastAvailableId != subject.id) { lastStatus = false; // force a refresh, in case we're going from available -> available in different subject id newReport = true; // we've available on a brand new report } lastAvailableId = subject.id; } } catch (NullReferenceException e) { Log.Error( "Failed to create {0} ScienceSubject. If you can manage to reproduce this error, let me know.", experiment.id); Log.Error("Exception was: {0}", e); Available = lastStatus; } } else { Available = false; } } else { Available = false; // no experiments ready } return(Available != lastStatus && Available); }
/// <summary> /// Returns true if the status just changed to available (so that /// ScienceAlert can play a sound when the experiment /// status changes) /// </summary> /// <returns></returns> public virtual bool UpdateStatus(ExperimentSituations experimentSituation, out bool newReport) { newReport = false; if (FlightGlobals.ActiveVessel == null) { Available = false; lastAvailableId = ""; Log.Debug("Observer.UpdateStatus: active vessel is null!"); return(false); } if (!settings.Enabled || (requireControllable && !FlightGlobals.ActiveVessel.IsControllable)) { Available = false; lastAvailableId = ""; return(false); } bool lastStatus = Available; var vessel = FlightGlobals.ActiveVessel; if (!storage.IsBusy && IsReadyOnboard) { // does this experiment even apply in the current situation? if (experiment.IsAvailableWhile(experimentSituation, vessel.mainBody)) { var biome = string.Empty; // note: apparently simply providing the biome name whether its // relevant or not will result in the biome being INCORRECTLY applied // to the experiment id. This causes all kinds of confusion because // R&D will report incorrect science values based on the wrong id // // Supplying an empty string if the biome doesn't matter seems to work if (experiment.BiomeIsRelevantWhile(experimentSituation)) { // biome matters; check to make sure we have biome data available if (scanInterface.HaveScanData(vessel.latitude, vessel.longitude, vessel.mainBody)) { if (biomeFilter.GetBiome(vessel.latitude * Mathf.Deg2Rad, vessel.longitude * Mathf.Deg2Rad, out biome)) { lastBiomeQuery = biome; } else { biome = lastBiomeQuery; // use last good known value } } else { // no biome data available Available = false; lastAvailableId = ""; return(false); } } try { var subject = ResearchAndDevelopment.GetExperimentSubject(experiment, experimentSituation, vessel.mainBody, biome); List <ScienceData> data = null; float scienceTotal = GetScienceTotal(subject, out data); switch (settings.Filter) { case ProfileData.ExperimentSettings.FilterMethod.Unresearched: // Fairly straightforward: total science + potential should be zero Available = scienceTotal < 0.0005f; break; case ProfileData.ExperimentSettings.FilterMethod.NotMaxed: // <98% of science cap Available = scienceTotal < subject.scienceCap * 0.98f * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; break; case ProfileData.ExperimentSettings.FilterMethod.LessThanFiftyPercent: // important note for these last two filters: we can only accurately // predict science for up to two of the same reports. After that, // it'll be highly overestimated Available = scienceTotal < subject.scienceCap * 0.5f * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; break; case ProfileData.ExperimentSettings.FilterMethod.LessThanNinetyPercent: Available = scienceTotal < subject.scienceCap * 0.9f * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; break; default: // this should NEVER occur, but nice to have a safety measure // in place if I add a filter option and forget to add its logic Log.Error("Unrecognized experiment filter!"); data = new List <ScienceData>(); break; } // bugfix: also ensure the experiment will generate >0 science, else // we could produce alerts for reports that won't generate any science //nextReportValue = CalculateNextReportValue(subject, experimentSituation, data); nextReportValue = subject.CalculateNextReport(experiment, data); Available = Available && nextReportValue > 0.01f; // check the science threshold Available = Available && nextReportValue > ScienceAlertProfileManager.ActiveProfile.ScienceThreshold; if (Available) { if (lastAvailableId != subject.id) { lastStatus = false; // force a refresh, in case we're going from available -> available in different subject id newReport = true; // we've available on a brand new report } lastAvailableId = subject.id; if (Available != lastStatus && Available) { Log.Normal("Experiment {0} just became available! Total potential science onboard currently: {1} (Cap is {2}, threshold is {3}, current sci is {4}, expected next report value: {5})", lastAvailableId, scienceTotal, subject.scienceCap * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier, settings.Filter, subject.science, nextReportValue); //Log.Debug("Transmission value: {0}", CalculateTransmissionValue(subject)); #if DEBUG if (GetNextOnboardExperimentModule() != null) { Log.Debug("Transmission value: {0}", API.AlertUtil.GetNextReportValue(subject, experiment, data, GetNextOnboardExperimentModule().xmitDataScalar)); } #endif if (data.Count() > 0) { Log.Debug("Raw dataAmount = {0}, nextScience = {1}", data.First().dataAmount, ResearchAndDevelopment.GetScienceValue(data.First().dataAmount, subject) * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier); Log.Debug("Total science value = {0}", GetScienceTotal(subject, out data)); } } } } catch (NullReferenceException e) { // note to self: even with all the logging I did when // I could sometimes reproduce the exception, nothing // looked wrong except that biome string becomes null Log.Error("Failed to create {0} ScienceSubject. If you can manage to reproduce this error, let me know.", experiment.id); Log.Error("Exception was: {0}", e); Available = lastStatus; } } else { // experiment isn't available under this situation #if DEBUG //if (GetNextOnboardExperimentModule()) //Log.Verbose("{0} is onboard but not applicable in this situation {1} (vessel situation {2})", ExperimentTitle, experimentSituation, vessel.situation); #endif Available = false; } } else { Available = false; // no experiments ready } return(Available != lastStatus && Available); }
ScienceSubject currentScienceSubject(ScienceExperiment experiment) { string fixBiome = string.Empty; // some biomes don't have 4th string, so we just put an empty in to compare strings later if (experiment.BiomeIsRelevantWhile(currentSituation())) fixBiome = currentBiome();// for those that do, we add it to the string return ResearchAndDevelopment.GetExperimentSubject(experiment, currentSituation(), currentBody(), fixBiome);//ikr!, we pretty much did all the work already, jeez }
/// <summary> /// Performs actions on experiments. Run/Transfer/Review/Reset /// </summary> /// <param name="moduleScienceExperiment"></param> /// <returns>false if nothing is left to do, true otherwise</returns> private bool RunExperiment(ModuleScienceExperiment moduleScienceExperiment) { Log.Write($" {moduleScienceExperiment.part.partInfo.title}/{moduleScienceExperiment.experiment.experimentTitle}"); Log.Write($" rerunnable:{moduleScienceExperiment.rerunnable} resettable:{moduleScienceExperiment.resettable} deployed:{moduleScienceExperiment.Deployed} inpoerable:{moduleScienceExperiment.Inoperable}"); // // If the experiment is already deployed but not yet handled, don't try to re-run it // if (moduleScienceExperiment.Deployed && !moduleScienceExperiment.Inoperable) // return false; // Filter by mode if (!moduleScienceExperiment.rerunnable) { switch (mode) { case Modes.RerunnableOnly: Log.Write($" We haven't unlocked the mode to run this experiment yet"); return(false); case Modes.RerunnableAndResettableWithScientist: if (currentVessel.GetVesselCrew().Find(x => x.trait == "Scientist") == null) { Log.Write($" We either need to unlock the next mode or bring a scientist along with us for this"); return(false); } break; } } //ScienceExperiment scienceExperiment = moduleScienceExperiment.experiment; ScienceExperiment scienceExperiment = ResearchAndDevelopment.GetExperiment(moduleScienceExperiment.experimentID); // lookup from R&D instead of pulling from ModuleScienceExperiment.experiment becuase DMagic is misbehaving. // Log.Write($"Using science experiment:{1}[{5}] with biomeMask: {2} situationMask: {3} baseValue: {4}", scienceExperiment.id, scienceExperiment.biomeMask, scienceExperiment.situationMask, scienceExperiment.baseValue, scienceExperiment.experimentTitle); // Review data? if (moduleScienceExperiment.Deployed && !moduleScienceExperiment.Inoperable) { if (KerbalismAPI.KerbalismInstalled) { Log.Write($" Kerbalism installed, attempting to send science data straight to hard drive"); // file or sample? (as per kerbalisms definition) bool sample = moduleScienceExperiment.xmitDataScalar < 0.666f; Log.Write($" {moduleScienceExperiment.experimentID} is a {(sample ? "sample" : "file")}"); ScienceData[] data = moduleScienceExperiment.GetDataUsingReflection(); for (int i = 0; i < data.Count(); i++) { Log.Write($" Storing {data[i].subjectID} in hard drive"); if (sample) { KerbalismAPI.StoreSample(currentVessel, data[i].subjectID, data[i].dataAmount); } else { KerbalismAPI.StoreFile(currentVessel, data[i].subjectID, data[i].dataAmount); } // get rid of the data in the experiment now Log.Write($" Dumping {data[i].subjectID} from experiment"); moduleScienceExperiment.DumpDataUsingReflection(data[i]); } } else { Log.Write($" Attempting to review data to force collection..."); moduleScienceExperiment.ReviewDataUsingReflection(); } return(true); } // Reset inoperable experiments if (moduleScienceExperiment.resettable && moduleScienceExperiment.Inoperable) { Log.Write($" Resetting experiment"); // Log.Write($"Science AI is cleaning {scienceExperiment.experimentTitle}", DebugFormat.Screen, true); moduleScienceExperiment.ResetExperimentUsingReflection(); return(true); } // check if we can even run this experiment now if (!scienceExperiment.IsAvailableWhile(currentSituation, currentVessel.mainBody)) { Log.Write($" Cannot run in {currentSituation} on {currentVessel.mainBody}."); return(false); } string experimentSpecificBiome = string.Empty; if (scienceExperiment.BiomeIsRelevantWhile(currentSituation)) { experimentSpecificBiome = currentBiome; } // check science value of experiment based on what is returned to KSC R&D and what is presently stored on the vessel (including science containers and kerbalism data drives) ScienceSubject subject = ResearchAndDevelopment.GetExperimentSubject(scienceExperiment, currentSituation, currentVessel.mainBody, experimentSpecificBiome, null); List <ScienceData> storedData; int numberOfExperimentsOnBoard = GetNumberOfExperimentsOnBoard(subject, out storedData); // Check for duplicate experiments if (numberOfExperimentsOnBoard > 0) { Log.Write($" We already have this experiment on board"); return(false); } float scienceValue = GetScienceValue(scienceExperiment, subject, storedData); if (scienceValue < 0.01) { Log.Write($" Science value is too low ({scienceValue} science). Not running."); return(false); } // run the experiment Log.Write($" Running experiment {moduleScienceExperiment.part.partInfo.title}/{moduleScienceExperiment.experiment.experimentTitle} for {scienceValue} science in biome {currentSituation.ToString()} {currentBiome}."); moduleScienceExperiment.DeployExperimentUsingReflection(); // Log.Write($"<color=#BBBB00><b>Science AI</b></color>\nRunning <b>{scienceExperiment.experimentTitle}</b>\n<i>Hold onto your knickers!</i>", DebugFormat.Screen, true); return(true); }
public void Update() { if (Input.GetMouseButtonUp(0)) { resizingWindow = false; } if (resizingWindow) { windowPosition.width = Input.mousePosition.x - windowPosition.x + 10; windowPosition.height = (Screen.height - Input.mousePosition.y) - windowPosition.y + 10; } // using "while" for possibility to "break". So we dont have to use GOTO. using timer to skip frames. while (drawWindow && (lateUpdateTimer < Time.time || lateUpdateTimerCounter > 3)) { lateUpdateTimer = Time.time + 1; ExperimentSituations experimentSituation = ScienceUtil.GetExperimentSituation(FlightGlobals.ActiveVessel); CelestialBody mainbody = FlightGlobals.ActiveVessel.mainBody; string biome; if (FlightGlobals.ActiveVessel.landedAt != string.Empty) { biome = FlightGlobals.ActiveVessel.landedAt; } else { biome = ScienceUtil.GetExperimentBiome(FlightGlobals.ActiveVessel.mainBody, FlightGlobals.ActiveVessel.latitude, FlightGlobals.ActiveVessel.longitude); } if (mainbody == lastMainBody && biome == lastBiome && lastExperimentSituation == experimentSituation && lateUpdateTimerCounter <= 3) { lateUpdateTimer = 0; lateUpdateTimerCounter++; break; } lateUpdateTimerCounter = 0; lastBiome = biome; lastMainBody = mainbody; lastExperimentSituation = experimentSituation; Output.Clear(); OnShip.Clear(); //List<ScienceExperiment> PossibleExperiments = new List<ScienceExperiment>(); //Search for all Science Experiment Modules on vessel, Check experiment available and add in "Output" and "OnShip" foreach (ModuleScienceExperiment moduleScienceExperiment in FlightGlobals.ActiveVessel.FindPartModulesImplementing <ModuleScienceExperiment>()) { string firstExperimentId = moduleScienceExperiment.experimentID; ScienceExperiment scienceExperiment = ResearchAndDevelopment.GetExperiment(firstExperimentId); bool available = scienceExperiment.IsAvailableWhile(experimentSituation, mainbody); if (available) { if (moduleScienceExperiment.Deployed) { foreach (ScienceData scienceData in moduleScienceExperiment.GetData()) { ExperimentView experimentView = new ExperimentView(scienceData); if (!Output.Contains(experimentView)) { Output.Add(experimentView); } OnShip.Add(experimentView); } } { ScienceSubject scienceSubject = LibraryUtils.GetExperimentSubject(scienceExperiment, experimentSituation, mainbody, scienceExperiment.BiomeIsRelevantWhile(experimentSituation) ? biome : ""); ExperimentView experimentView = new ExperimentView(scienceSubject); if (!Output.Contains(experimentView)) { Output.Add(experimentView); } } } } // Check for Kerbals on board. That means we can also use "evaReport", "surfaceSample", "asteroidSample" in EVA. if (FlightGlobals.ActiveVessel.GetCrewCount() > 0) { { string firstExperimentId = "evaReport"; ScienceExperiment scienceExperiment = ResearchAndDevelopment.GetExperiment(firstExperimentId); bool available = scienceExperiment.IsAvailableWhile(experimentSituation, mainbody); if (available) { ScienceSubject scienceSubject = LibraryUtils.GetExperimentSubject(scienceExperiment, experimentSituation, mainbody, scienceExperiment.BiomeIsRelevantWhile(experimentSituation) ? biome : ""); ExperimentView experimentView = new ExperimentView(scienceSubject); if (!Output.Contains(experimentView)) { Output.Add(experimentView); } } } { string firstExperimentId = "surfaceSample"; ScienceExperiment scienceExperiment = ResearchAndDevelopment.GetExperiment(firstExperimentId); bool available = scienceExperiment.IsAvailableWhile(experimentSituation, mainbody); if (available) { ScienceSubject scienceSubject = LibraryUtils.GetExperimentSubject(scienceExperiment, experimentSituation, mainbody, scienceExperiment.BiomeIsRelevantWhile(experimentSituation) ? biome : ""); ExperimentView experimentView = new ExperimentView(scienceSubject); if (!Output.Contains(experimentView)) { Output.Add(experimentView); } } } // Find asteroid that could be used for science. (I hope it will not be too many asteroids, because of linear complexity of this code) ModuleAsteroid[] asteroids = FindObjectsOfType <ModuleAsteroid>(); foreach (ModuleAsteroid asteroid in asteroids) { Vector3 destination3 = asteroid.gameObject.transform.position - FlightGlobals.ActiveVessel.gameObject.transform.position; float unfocusedRange = asteroid.Events["TakeSampleEVAEvent"].unfocusedRange; unfocusedRange *= unfocusedRange; if (destination3.sqrMagnitude < unfocusedRange) { string firstExperimentId = "asteroidSample"; ScienceExperiment scienceExperiment = ResearchAndDevelopment.GetExperiment(firstExperimentId); bool available = scienceExperiment.IsAvailableWhile(experimentSituation, mainbody); if (available) { string asteroidname = asteroid.part.partInfo.name + asteroid.part.flightID; ScienceSubject scienceSubject = LibraryUtils.GetExperimentSubject(scienceExperiment, experimentSituation, asteroidname, "", mainbody, scienceExperiment.BiomeIsRelevantWhile(experimentSituation) ? biome : ""); ExperimentView experimentView = new ExperimentView(scienceSubject); if (!Output.Contains(experimentView)) { Output.Add(experimentView); } } } } } //Search for all Science Containers on vessel and write all found experiments into OnShip list foreach (ModuleScienceContainer moduleScienceContainer in FlightGlobals.ActiveVessel.FindPartModulesImplementing <ModuleScienceContainer>()) { foreach (ScienceData scienceData in moduleScienceContainer.GetData()) { ExperimentView experimentView = new ExperimentView(scienceData); //if (!Output.Contains(experimentView)) Output.Add(experimentView); OnShip.Add(experimentView); } } Output.Sort(); break; } }
public void GetSciData() { if (ResearchAndDevelopment.Instance == null) { return; } dataOutputList = new List <Experiment>(); List <ScienceSubject> newExperiments = new List <ScienceSubject>(); List <string> exIds = ResearchAndDevelopment.GetExperimentIDs(); List <ScienceSubject> subjectslist = ResearchAndDevelopment.GetSubjects(); //I am glad this code runs only once! Too expensive! foreach (string id in exIds) { foreach (ExperimentSituations experimentSituation in Enum.GetValues(typeof(ExperimentSituations))) { foreach (CelestialBody body in FlightGlobals.Bodies) { bool ocean = body.ocean; if (ExperimentSituations.SrfSplashed == experimentSituation && !ocean) { continue; } if ((ExperimentSituations.FlyingHigh == experimentSituation || ExperimentSituations.FlyingLow == experimentSituation) && !body.atmosphere) { continue; } ScienceExperiment experiment = ResearchAndDevelopment.GetExperiment(id); bool available = experiment.IsAvailableWhile(experimentSituation, body); if (available) { bool shouldHaveBiome = experiment.BiomeIsRelevantWhile(experimentSituation); if (shouldHaveBiome) { foreach (string biome in ResearchAndDevelopment.GetBiomeTags(body)) { if (KSPScienceSettings.getBoolSetting("ShowOnlyKnownBiomes")) { bool foundBiome = subjectslist.Any(subject => subject.id.Contains("@" + body.name) && subject.id.Contains(biome.Replace(" ", ""))); if (!foundBiome) { continue; } } ScienceSubject ssj = new ScienceSubject(experiment, experimentSituation, body, biome); if (id == "asteroidSample") { ssj.scienceCap = experiment.scienceCap; } newExperiments.Add(ssj); } if (body.BiomeMap == null || body.BiomeMap.Attributes.Length == 0) { ScienceSubject ssj = new ScienceSubject(experiment, experimentSituation, body, ""); if (id == "asteroidSample") { ssj.scienceCap = experiment.scienceCap; } newExperiments.Add(ssj); } } else { ScienceSubject ssj = new ScienceSubject(experiment, experimentSituation, body, ""); if (id == "asteroidSample") { ssj.scienceCap = experiment.scienceCap; } newExperiments.Add(ssj); } } } } } foreach (ScienceSubject scienceSubject in subjectslist) { newExperiments.RemoveAll(subject => subject.id == scienceSubject.id); string title = scienceSubject.id; double earned = Math.Round(scienceSubject.science, 1); double remain = Math.Round(scienceSubject.scienceCap - scienceSubject.science, 1); string body = LibraryUtils.FindExperimentBody(scienceSubject.id.Split('@')[1]); string type = scienceSubject.id.Split('@')[0]; Experiment experiment = new Experiment(title, earned, remain, body, type); dataOutputList.Add(experiment); } foreach (ScienceSubject newExperiment in newExperiments) { newExperiment.scientificValue = 1f; CelestialBody thisBody = FlightGlobals.Bodies.Find(celestialBody => newExperiment.id.Split('@')[1].StartsWith(celestialBody.name)); Experiment ex = new Experiment(newExperiment.id, 0, Math.Round(newExperiment.scienceCap, 1), thisBody.name, newExperiment.id.Split('@')[0]); dataOutputList.Add(ex); } dataOutputList.Sort(SortByName); if (KSPScienceSettings.getBoolSetting("ShowOnlyKnownExperiments")) { allExperimentTypes = GetKnownExperimentTypes(); } else { allExperimentTypes = GetAllExperimentTypes(); } }
// create a new subject entry in the RnD // - experiment: experiment_id // - situation: an arbitrary situation, can insert biome at the end // - body: celestial body involved // - biome: biome involved, or empty // - multiplier: science multiplier for the body/situation public static string Generate_subject(ScienceExperiment experiment, CelestialBody body, ExperimentSituations sit, string biome) { // generate subject id string subject_id = Lib.BuildString(experiment.id, "@", body.name, sit + (experiment.BiomeIsRelevantWhile(sit) ? biome : "")); // in sandbox, do nothing else if (ResearchAndDevelopment.Instance == null) { return(subject_id); } // if the subject id was never added to RnD if (ResearchAndDevelopment.GetSubjectByID(subject_id) == null) { // get subjects container using reflection // - we tried just changing the subject.id instead, and // it worked but the new id was obviously used only after // putting RnD through a serialization->deserialization cycle var subjects = Lib.ReflectionValue <Dictionary <string, ScienceSubject> > ( ResearchAndDevelopment.Instance, "scienceSubjects" ); float multiplier = Multiplier(body, sit); var cap = multiplier * experiment.baseValue; // create new subject ScienceSubject subject = new ScienceSubject ( subject_id, Lib.BuildString(experiment.experimentTitle, " (", Lib.SpacesOnCaps(sit + biome), ")"), experiment.dataScale, multiplier, cap ); // add it to RnD subjects.Add(subject_id, subject); } return(subject_id); }