///<summary> Add reliability sub-panel, including tooltips </summary> private static void AddSubPanelReliability(Panel p) { // evaluate redundancy metric // - 0: no redundancy // - 0.5: all groups have 2 elements // - 1.0: all groups have 3 or more elements double redundancy_metric = 0.0; foreach (KeyValuePair <string, int> pair in vessel_analyzer.redundancy) { switch (pair.Value) { case 1: break; case 2: redundancy_metric += 0.5 / vessel_analyzer.redundancy.Count; break; default: redundancy_metric += 1.0 / vessel_analyzer.redundancy.Count; break; } } // traduce the redundancy metric to string string redundancy_str = string.Empty; if (redundancy_metric <= 0.1) { redundancy_str = "none"; } else if (redundancy_metric <= 0.33) { redundancy_str = "poor"; } else if (redundancy_metric <= 0.66) { redundancy_str = "okay"; } else { redundancy_str = "great"; } // generate redundancy tooltip string redundancy_tooltip = string.Empty; if (vessel_analyzer.redundancy.Count > 0) { StringBuilder sb = new StringBuilder(); foreach (KeyValuePair <string, int> pair in vessel_analyzer.redundancy) { if (sb.Length > 0) { sb.Append("\n"); } sb.Append("<b>"); switch (pair.Value) { case 1: sb.Append("<color=red>"); break; case 2: sb.Append("<color=yellow>"); break; default: sb.Append("<color=green>"); break; } sb.Append(pair.Value.ToString()); sb.Append("</color></b>\t"); sb.Append(pair.Key); } redundancy_tooltip = Lib.BuildString("<align=left />", sb.ToString()); } // generate repair string and tooltip string repair_str = "none"; string repair_tooltip = string.Empty; if (vessel_analyzer.crew_engineer) { repair_str = "engineer"; repair_tooltip = "The engineer on board should\nbe able to handle all repairs"; } else if (vessel_analyzer.crew_capacity == 0) { repair_str = "safemode"; repair_tooltip = "We have a chance of repairing\nsome of the malfunctions remotely"; } // render panel p.AddSection("RELIABILITY", string.Empty, () => { p.Prev(ref special_index, panel_special.Count); update = true; }, () => { p.Next(ref special_index, panel_special.Count); update = true; }); p.AddContent("malfunctions", Lib.HumanReadableAmount(vessel_analyzer.failure_year, "/y"), "average case estimate\nfor the whole vessel"); p.AddContent("high quality", Lib.HumanReadablePerc(vessel_analyzer.high_quality), "percentage of high quality components"); p.AddContent("redundancy", redundancy_str, redundancy_tooltip); p.AddContent("repair", repair_str, repair_tooltip); }
///<summary> Add radiation sub-panel, including tooltips </summary> private static void AddSubPanelRadiation(Panel p) { // get first radiation rule // - guaranteed to exist, as this panel is not rendered if it doesn't // - even without crew, it is safe to evaluate the modifiers that use it Rule rule = Profile.rules.Find(k => k.modifiers.Contains("radiation")); // detect if it use shielding bool use_shielding = rule.modifiers.Contains("shielding"); // calculate various radiation levels double[] levels = new[] { Math.Max(Radiation.Nominal, (env_analyzer.surface_rad + vessel_analyzer.emitted)), // surface Math.Max(Radiation.Nominal, (env_analyzer.magnetopause_rad + vessel_analyzer.emitted)), // inside magnetopause Math.Max(Radiation.Nominal, (env_analyzer.inner_rad + vessel_analyzer.emitted)), // inside inner belt Math.Max(Radiation.Nominal, (env_analyzer.outer_rad + vessel_analyzer.emitted)), // inside outer belt Math.Max(Radiation.Nominal, (env_analyzer.heliopause_rad + vessel_analyzer.emitted)), // interplanetary Math.Max(Radiation.Nominal, (env_analyzer.extern_rad + vessel_analyzer.emitted)), // interstellar Math.Max(Radiation.Nominal, (env_analyzer.storm_rad + vessel_analyzer.emitted)) // storm }; // evaluate modifiers (except radiation) List <string> modifiers_except_radiation = new List <string>(); foreach (string s in rule.modifiers) { if (s != "radiation") { modifiers_except_radiation.Add(s); } } double mod = Modifiers.Evaluate(env_analyzer, vessel_analyzer, resource_sim, modifiers_except_radiation); // calculate life expectancy at various radiation levels double[] estimates = new double[7]; for (int i = 0; i < 7; ++i) { estimates[i] = rule.fatal_threshold / (rule.degeneration * mod * levels[i]); } // generate tooltip RadiationModel mf = Radiation.Info(env_analyzer.body).model; string tooltip = Lib.BuildString ( "<align=left />", String.Format("{0,-20}\t<b>{1}</b>\n", "surface", Lib.HumanReadableDuration(estimates[0])), mf.has_pause ? String.Format("{0,-20}\t<b>{1}</b>\n", "magnetopause", Lib.HumanReadableDuration(estimates[1])) : "", mf.has_inner ? String.Format("{0,-20}\t<b>{1}</b>\n", "inner belt", Lib.HumanReadableDuration(estimates[2])) : "", mf.has_outer ? String.Format("{0,-20}\t<b>{1}</b>\n", "outer belt", Lib.HumanReadableDuration(estimates[3])) : "", String.Format("{0,-20}\t<b>{1}</b>\n", "interplanetary", Lib.HumanReadableDuration(estimates[4])), String.Format("{0,-20}\t<b>{1}</b>\n", "interstellar", Lib.HumanReadableDuration(estimates[5])), String.Format("{0,-20}\t<b>{1}</b>", "storm", Lib.HumanReadableDuration(estimates[6])) ); // render the panel p.AddSection("RADIATION", string.Empty, () => { p.Prev(ref special_index, panel_special.Count); update = true; }, () => { p.Next(ref special_index, panel_special.Count); update = true; }); p.AddContent("surface", Lib.HumanReadableRadiation(env_analyzer.surface_rad + vessel_analyzer.emitted), tooltip); p.AddContent("orbit", Lib.HumanReadableRadiation(env_analyzer.magnetopause_rad), tooltip); if (vessel_analyzer.emitted >= 0.0) { p.AddContent("emission", Lib.HumanReadableRadiation(vessel_analyzer.emitted), tooltip); } else { p.AddContent("active shielding", Lib.HumanReadableRadiation(-vessel_analyzer.emitted), tooltip); } p.AddContent("shielding", rule.modifiers.Contains("shielding") ? Habitat.Shielding_to_string(vessel_analyzer.shielding) : "n/a", tooltip); }