public string GetTrainingString(ProtoCrewMember pcm) { bool found = false; string trainingStr = "\n\nTraining:"; foreach (FlightLog.Entry ent in pcm.careerLog.Entries) { string pretty = GetPrettyCourseName(ent.type); if (!string.IsNullOrEmpty(pretty)) { if (ent.type == "TRAINING_proficiency") { found = true; trainingStr += $"\n {pretty}{ent.target}"; } else if (ent.type == "TRAINING_mission") { double exp = GetExpiration(pcm.name, ent); if (exp > 0d) { trainingStr += $"\n {pretty}{ent.target}. Expires {KSPUtil.PrintDate(exp, false)}"; } } } } if (found) { return(trainingStr); } else { return(string.Empty); } }
public SaveGameInfo(string saveFile) { SaveFile = new FileInfo(saveFile); MetaData = new Dictionary <string, string>(); var metaFile = Path.ChangeExtension(saveFile, "loadmeta"); if (File.Exists(metaFile)) { var content = File.ReadAllLines(metaFile); foreach (var line in content) { var idx = line.IndexOf("="); var key = line.Substring(0, idx).Trim(); var value = line.Substring(idx + 1).Trim(); MetaData[key] = value; } } string funds = ""; if (MetaData.TryGetValue("funds", out funds)) { double fundsAmount; if (double.TryParse(funds, out fundsAmount)) { fundsAmount /= 1000.0; string suffix = "k"; if (fundsAmount > 1000) { fundsAmount /= 1000.0; suffix = "m"; } if (fundsAmount > 1000) { fundsAmount /= 1000.0; suffix = "b"; } funds = Math.Round(fundsAmount, 1).ToString() + suffix + " funds"; } } string gameTime = ""; if (MetaData.TryGetValue("UT", out gameTime)) { double gameTimeVal; if (double.TryParse(gameTime, out gameTimeVal)) { GameTime = gameTimeVal; GameTimeText = KSPUtil.PrintDate(GameTime, includeTime: true); } } ButtonText = String.Format(" {0}\n {1}\n {2}\n {3}", SaveFile.LastWriteTime, Path.GetFileNameWithoutExtension(SaveFile.Name), funds, GameTimeText); }
public tabs newCourseTab() { GUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); GUILayout.Label(selectedCourse.name); GUILayout.FlexibleSpace(); } finally { GUILayout.EndHorizontal(); } GUILayout.Label(selectedCourse.description); summaryBody(tabs.NewCourse); if (selectedCourse.seatMax > 0) { GUILayout.Label(selectedCourse.seatMax - selectedCourse.Students.Count + " remaining seat(s)."); } if (selectedCourse.seatMin > selectedCourse.Students.Count) { GUILayout.Label(selectedCourse.seatMin - selectedCourse.Students.Count + " more student(s) required."); } GUILayout.Label("Will take " + KSPUtil.PrintDateDeltaCompact(selectedCourse.GetTime(), false, false)); GUILayout.Label("and finish on " + KSPUtil.PrintDate(selectedCourse.CompletionTime(), false)); if (GUILayout.Button("Start Course", GUILayout.ExpandWidth(false))) { if (selectedCourse.StartCourse()) { CrewHandler.Instance.ActiveCourses.Add(selectedCourse); selectedCourse = null; } } return(selectedCourse == null ? tabs.Training : tabs.NewCourse); }
public void nautTab() { updateActiveMap(); GUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); GUILayout.Label(selectedNaut.name); GUILayout.FlexibleSpace(); } finally { GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); try { GUILayout.Label($"{selectedNaut.trait} {selectedNaut.experienceLevel.ToString():D}"); if (CrewHandler.Instance.RetirementEnabled && CrewHandler.Instance.KerbalRetireTimes.ContainsKey(selectedNaut.name)) { GUILayout.Space(8); GUILayout.Label($"Retires NET {KSPUtil.PrintDate(CrewHandler.Instance.KerbalRetireTimes[selectedNaut.name], false)}", rightLabel); } } finally { GUILayout.EndHorizontal(); } double nlt = CrewHandler.Instance.GetLatestRetireTime(selectedNaut); if (nlt > 0) { GUILayout.BeginHorizontal(); GUILayout.Label(string.Empty, GUILayout.ExpandWidth(true)); GUILayout.Label($"Retires NLT {KSPUtil.PrintDate(nlt, false)}", rightLabel); GUILayout.EndHorizontal(); } if (activeMap.ContainsKey(selectedNaut)) { ActiveCourse currentCourse = activeMap[selectedNaut]; GUILayout.BeginHorizontal(); try { GUILayout.Label($"Studying {currentCourse.name} until {KSPUtil.PrintDate(currentCourse.CompletionTime(), false)}"); if (currentCourse.seatMin > 1) { if (GUILayout.Button("Cancel", GUILayout.ExpandWidth(false))) { cancelCourse(currentCourse); } } else { if (GUILayout.Button("Remove", GUILayout.ExpandWidth(false))) { leaveCourse(currentCourse, selectedNaut); } } } finally { GUILayout.EndHorizontal(); } } GUILayout.Label(CrewHandler.Instance.GetTrainingString(selectedNaut)); }
public void FixedUpdate() { if (!isCompatible) { return; } if (!(HighLogic.LoadedSceneIsFlight || HighLogic.LoadedScene == GameScenes.SPACECENTER)) { return; } if (!dumpOrbits) { return; } counter += TimeWarp.fixedDeltaTime; if (counter < 3600) { return; } counter = 0; if (FlightGlobals.Bodies == null) { print("**RSS OBTDUMP*** - null body list!"); return; } print("**RSS OBTDUMP***"); int time = (int)Planetarium.GetUniversalTime(); print("At time " + time + ", " + KSPUtil.PrintDate(time, true, true)); for (int i = 0; i < FlightGlobals.Bodies.Count; i++) { CelestialBody body = FlightGlobals.Bodies[i]; if (body == null || body.orbitDriver == null) { continue; } if (body.orbitDriver.orbit == null) { continue; } Orbit o = body.orbitDriver.orbit; print("********* BODY **********"); print("name = " + body.name + "(" + i + ")"); Type oType = o.GetType(); foreach (FieldInfo f in oType.GetFields()) { if (f == null || f.GetValue(o) == null) { continue; } print(f.Name + " = " + f.GetValue(o)); } } }
private void ScheduleStorm() { try { nextStorm = Planetarium.GetUniversalTime() + 3600 * 6 * 2 + Core.Instance.mRandom.Next(3600 * 6 * 98); Logging.Log("Next storm scheduled for " + KSPUtil.PrintDate((int)nextStorm, true, true)); } catch (NullReferenceException exc) { Logging.Log("Failed to schedule storm: " + exc.Message + "\n" + exc.StackTrace); } }
public string GetTrainingString(ProtoCrewMember pcm) { HashSet <string> expiredProfs = new HashSet <string>(); bool found = false; string trainingStr = "\n\nTraining:"; int lastFlight = pcm.careerLog.Last() == null ? 0 : pcm.careerLog.Last().flight; foreach (FlightLog.Entry ent in pcm.careerLog.Entries) { string pretty = GetPrettyCourseName(ent.type); if (!string.IsNullOrEmpty(pretty)) { if (ent.type == "expired_TRAINING_proficiency") { found = true; expiredProfs.Add(ent.target); } else { if (ent.type == "TRAINING_mission" && ent.flight != lastFlight) { continue; } found = true; trainingStr += "\n " + pretty + ent.target; double exp = GetExpiration(pcm.name, ent); if (exp > 0d) { trainingStr += ". Expires " + KSPUtil.PrintDate(exp, false); } } } } if (expiredProfs.Count > 0) { trainingStr += "\n Expired proficiencies:"; } foreach (string s in expiredProfs) { trainingStr += "\n " + s; } if (found) { return(trainingStr); } else { return(string.Empty); } }
internal static void Display() { _scrollDetailsPosition = GUILayout.BeginScrollView(_scrollDetailsPosition, RMStyle.ScrollStyle, GUILayout.Height(230), GUILayout.Width(WindowRoster.ViewerWidth)); GUILayout.Label(WindowRoster.SelectedKerbal.IsNew ? "Create a Kerbal" : "Kerbal Attributes", RMStyle.LabelStyleBold); GUILayout.BeginHorizontal(); if (RMSettings.EnableKerbalRename) { GUILayout.Label("Name:", GUILayout.Width(80)); WindowRoster.SelectedKerbal.Name = GUILayout.TextField(WindowRoster.SelectedKerbal.Name, GUILayout.Width(230)); GUILayout.Label(" - (" + WindowRoster.SelectedKerbal.Kerbal.trait + ")"); if (RMLifeSpan.Instance.RMGameSettings.EnableAging) { GUILayout.Label("Age: " + WindowRoster.SelectedKerbal.Age.ToString("##0")); GUILayout.Label("Next Bday: " + KSPUtil.PrintDate((int)WindowRoster.SelectedKerbal.TimeNextBirthday, false)); } } else { GUILayout.Label(WindowRoster.SelectedKerbal.Name + " - (" + WindowRoster.SelectedKerbal.Trait + ")", RMStyle.LabelStyleBold, GUILayout.Width(300)); if (RMLifeSpan.Instance.RMGameSettings.EnableAging) { GUILayout.Label("Age: " + WindowRoster.SelectedKerbal.Age.ToString("##0")); GUILayout.Label("Next Bday: " + KSPUtil.PrintDate((int)WindowRoster.SelectedKerbal.TimeNextBirthday, false)); } } GUILayout.EndHorizontal(); if (!string.IsNullOrEmpty(RMAddon.SaveMessage)) { GUILayout.Label(RMAddon.SaveMessage, RMStyle.ErrorLabelRedStyle); } if (RMSettings.EnableKerbalRename) { WindowRoster.DisplaySelectProfession(); } WindowRoster.DisplaySelectGender(); WindowRoster.DisplaySelectSuit(ref WindowRoster.SelectedKerbal.Suit); GUILayout.Label("Courage"); WindowRoster.SelectedKerbal.Courage = GUILayout.HorizontalSlider(WindowRoster.SelectedKerbal.Courage, 0, 1, GUILayout.Width(300)); GUILayout.Label("Stupidity"); WindowRoster.SelectedKerbal.Stupidity = GUILayout.HorizontalSlider(WindowRoster.SelectedKerbal.Stupidity, 0, 1, GUILayout.Width(300)); WindowRoster.SelectedKerbal.Badass = GUILayout.Toggle(WindowRoster.SelectedKerbal.Badass, "Badass"); GUILayout.EndScrollView(); WindowRoster.DisplayActionButtonsEdit(); }
/// <summary> /// Deduct the appropriate life support /// when first loading a vessel /// </summary> /// <param name="part">The Part with the life support PartModule</param> /// <param name="resource_name">The resource to drain</param> /// <param name="resource_rate">The resource drain rate (per second)</param> /// <returns>Returns the number of seconds remaining after LifeSupport is deducted</returns> public static double StartupRequest(PartModule module, string resource_name, double resource_rate) { if (module.part.protoModuleCrew.Count == 0) { Util.Log("Part " + module.part.name + " has no crew - skipping LSM startup"); return(0.0); } if (Util.BreathableAir(module.vessel)) { Util.Log("Vessel " + module.vessel.name + " is O2 atmo at " + module.vessel.altitude); Util.Log("Startup resource will not be drained"); return(0.0); } // Universal Time in seconds double lastUT = module.vessel.lastUT; double currUT = HighLogic.CurrentGame.UniversalTime; // Integer logic could overflow after 233 Kerbin years, // so maintain double values for arithmetic double delta = currUT - lastUT; double request = module.part.protoModuleCrew.Count * resource_rate * delta; // Startup should not be zero unless user is REALLY quick with the mouse // (i.e. never). if (request < C.DOUBLE_MARGIN) { Util.Log("CheckThis -> Startup request is zero. This is unexpected. Factors:"); Util.Log(" Crew count = " + module.part.protoModuleCrew.Count); Util.Log(" Resource rate = " + resource_rate); Util.Log(" Time delta = " + delta); return(0.0); } Util.Log("LastUT = " + lastUT + " (" + KSPUtil.PrintDate((int)lastUT, true, true) + ")"); Util.Log("CurrUT = " + currUT + " (" + KSPUtil.PrintDate((int)currUT, true, true) + ")"); Util.Log("Time elapsed: " + delta + " (" + KSPUtil.PrintDateDelta((int)delta, true, true) + ")"); Util.Log("Initial resource request (" + resource_name + "): " + request); // If user has disabled flow of LifeSupport to crewed part, assume this was in error // Re-enable so Kerbals don't immediately die upon vessel load module.part.Resources[resource_name].flowState = true; double obtained = module.part.RequestResource(resource_name, request, C.FLOWMODE_LIFESUPPORT); // Calculate remaining time that needs to be deducted from EVA LifeSupport (if applicable) return(((request - obtained) / request) * delta); }
public void nautTab() { updateActiveMap(); GUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); GUILayout.Label(selectedNaut.name); GUILayout.FlexibleSpace(); } finally { GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); try { GUILayout.Label(String.Format("{0} {1:D}", selectedNaut.trait, selectedNaut.experienceLevel.ToString())); if (CrewHandler.Instance.retirementEnabled && CrewHandler.Instance.kerbalRetireTimes.ContainsKey(selectedNaut.name)) { GUILayout.Space(8); GUILayout.Label(String.Format("Retires NET {0}", KSPUtil.PrintDate(CrewHandler.Instance.kerbalRetireTimes[selectedNaut.name], false)), rightLabel); } } finally { GUILayout.EndHorizontal(); } if (activeMap.ContainsKey(selectedNaut)) { ActiveCourse currentCourse = activeMap[selectedNaut]; GUILayout.BeginHorizontal(); try { GUILayout.Label("Studying " + currentCourse.name + " until " + KSPUtil.PrintDate(currentCourse.CompletionTime(), false)); if (currentCourse.seatMin > 1) { if (GUILayout.Button("Cancel", GUILayout.ExpandWidth(false))) { cancelCourse(currentCourse); } } else { if (GUILayout.Button("Remove", GUILayout.ExpandWidth(false))) { leaveCourse(currentCourse, selectedNaut); } } } finally { GUILayout.EndHorizontal(); } } GUILayout.Label(CrewHandler.Instance.GetTrainingString(selectedNaut)); }
public Tabs newCourseTab() { if (tempCourseLblStyle == null) { tempCourseLblStyle = new GUIStyle(GUI.skin.label); tempCourseLblStyle.normal.textColor = Color.yellow; } GUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); GUILayout.Label(selectedCourse.name); GUILayout.FlexibleSpace(); } finally { GUILayout.EndHorizontal(); } if (!string.IsNullOrEmpty(selectedCourse.description)) { GUILayout.Label(selectedCourse.description); } if (selectedCourse.isTemporary) { GUILayout.Label("Tech for this part is still being researched", tempCourseLblStyle); } summaryBody(Tabs.NewCourse); if (selectedCourse.seatMax > 0) { GUILayout.Label(selectedCourse.seatMax - selectedCourse.Students.Count + " remaining seat(s)."); } if (selectedCourse.seatMin > selectedCourse.Students.Count) { GUILayout.Label(selectedCourse.seatMin - selectedCourse.Students.Count + " more student(s) required."); } GUILayout.Label("Will take " + KSPUtil.PrintDateDeltaCompact(selectedCourse.GetTime(), true, false)); GUILayout.Label("and finish on " + KSPUtil.PrintDate(selectedCourse.CompletionTime(), false)); if (GUILayout.Button("Start Course", GUILayout.ExpandWidth(false))) { if (selectedCourse.StartCourse()) { CrewHandler.Instance.ActiveCourses.Add(selectedCourse); selectedCourse = null; MaintenanceHandler.Instance?.UpdateUpkeep(); } } return(selectedCourse == null ? Tabs.Training : Tabs.NewCourse); }
public UITab RenderNewCourseTab() { if (_tempCourseLblStyle == null) { _tempCourseLblStyle = new GUIStyle(GUI.skin.label); _tempCourseLblStyle.normal.textColor = Color.yellow; } GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label(_selectedCourse.name); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (!string.IsNullOrEmpty(_selectedCourse.description)) { GUILayout.Label(_selectedCourse.description); } if (_selectedCourse.isTemporary) { GUILayout.Label("Tech for this part is still being researched", _tempCourseLblStyle); } RenderSummaryBody(UITab.NewCourse); if (_selectedCourse.seatMax > 0) { GUILayout.Label($"{_selectedCourse.seatMax - _selectedCourse.Students.Count} remaining seat(s)."); } if (_selectedCourse.seatMin > _selectedCourse.Students.Count) { GUILayout.Label($"{_selectedCourse.seatMin - _selectedCourse.Students.Count} more student(s) required."); } GUILayout.Label($"Will take {KSPUtil.PrintDateDeltaCompact(_selectedCourse.GetTime(), true, false)}"); GUILayout.Label($"and finish on {KSPUtil.PrintDate(_selectedCourse.CompletionTime(), false)}"); if (GUILayout.Button("Start Course", HighLogic.Skin.button, GUILayout.ExpandWidth(false))) { if (_selectedCourse.StartCourse()) { CrewHandler.Instance.ActiveCourses.Add(_selectedCourse); _selectedCourse = null; MaintenanceHandler.Instance?.UpdateUpkeep(); } } return(_selectedCourse == null ? UITab.Training : UITab.NewCourse); }
/// <summary> /// Replaces the common tokens like "[year]" with their appropriate values as gathered from KSP /// </summary> /// <param name="sourceString">The source string to act on</param> /// <returns>The string post replacements</returns> public static string ReplaceStandardTokens(string sourceString) { string str = sourceString; str = ReplaceToken(str, "UT", Planetarium.fetch != null ? Math.Round(Planetarium.GetUniversalTime()).ToString() : "0"); str = ReplaceToken(str, "save", HighLogic.SaveFolder != null && HighLogic.SaveFolder.Trim().Length > 0 ? HighLogic.SaveFolder : "NA"); str = ReplaceToken(str, "version", Versioning.GetVersionString()); str = ReplaceToken(str, "vessel", HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null ? FlightGlobals.ActiveVessel.vesselName : "NA"); str = ReplaceToken(str, "body", Planetarium.fetch != null ? Planetarium.fetch.CurrentMainBody.GetDisplayName() : "NA"); str = ReplaceToken(str, "situation", HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null ? FlightGlobals.ActiveVessel.situation.ToString() : "NA"); str = ReplaceToken(str, "biome", HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null ? ScienceUtil.GetExperimentBiome(FlightGlobals.ActiveVessel.mainBody, FlightGlobals.ActiveVessel.latitude, FlightGlobals.ActiveVessel.longitude) : "NA"); double ut = 0; int[] times = { 0, 0, 0, 0, 0 }; if (Planetarium.fetch != null) { ut = Planetarium.GetUniversalTime(); times = Utilities.ConvertUT(ut); } str = ReplaceToken(str, "year", times[0].ToString()); str = ReplaceToken(str, "year0", times[0].ToString("D3")); str = ReplaceToken(str, "day", times[1].ToString()); str = ReplaceToken(str, "day0", times[1].ToString("D3")); str = ReplaceToken(str, "hour", times[2].ToString()); str = ReplaceToken(str, "hour0", times[2].ToString("D2")); str = ReplaceToken(str, "min", times[3].ToString()); str = ReplaceToken(str, "min0", times[3].ToString("D2")); str = ReplaceToken(str, "sec", times[4].ToString()); str = ReplaceToken(str, "sec0", times[4].ToString("D2")); str = ReplaceToken(str, "kspDate", KSPUtil.PrintDate(ut, false).Trim()); string time = KSPUtil.PrintTimeCompact(0, false); if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null) { time = KSPUtil.PrintTimeCompact((int)FlightGlobals.ActiveVessel.missionTime, false); } time = time.Replace(":", "-"); //Can't use colons in filenames on Windows, so we'll replace them with "-" str = ReplaceToken(str, "MET", time); return(str); }
private void FixTooltip(CrewListItem cli) { ProtoCrewMember pcm = cli.GetCrewRef(); if (RetirementEnabled && KerbalRetireTimes.TryGetValue(pcm.name, out double retTime)) { cli.SetTooltip(pcm); var ttc = _cliTooltip.GetValue(cli) as TooltipController_CrewAC; ttc.descriptionString += $"\n\nRetires no earlier than {KSPUtil.PrintDate(retTime, false)}"; // Training string trainingStr = GetTrainingString(pcm); if (!string.IsNullOrEmpty(trainingStr)) { ttc.descriptionString += trainingStr; } } }
public static void Log(string message, bool msg = true) { string ut = ""; try { int t = (int)Planetarium.GetUniversalTime(); ut = KSPUtil.PrintDate(t, true, true); } catch (NullReferenceException) { } UnityEngine.Debug.Log("kapparay: [" + ut + "] " + (msg ? "" : "Log: ") + message); #if DEBUG if (msg) { Message("kapparay: debug: " + message, false); } #endif }
protected void FixTooltip(KSP.UI.CrewListItem cli) { ProtoCrewMember pcm = cli.GetCrewRef(); double retTime; if (retirementEnabled && kerbalRetireTimes.TryGetValue(pcm.name, out retTime)) { cli.SetTooltip(pcm); KSP.UI.TooltipTypes.TooltipController_CrewAC ttc = cliTooltip.GetValue(cli) as KSP.UI.TooltipTypes.TooltipController_CrewAC; ttc.descriptionString += "\n\nRetires no earlier than " + KSPUtil.PrintDate(retTime, false); // Training string trainingStr = GetTrainingString(pcm); if (!string.IsNullOrEmpty(trainingStr)) { ttc.descriptionString += trainingStr; } } }
private void ProcessFirstLoad() { var newHires = new List <string>(); foreach (ProtoCrewMember pcm in HighLogic.CurrentGame.CrewRoster.Crew) { if ((pcm.rosterStatus == ProtoCrewMember.RosterStatus.Assigned || pcm.rosterStatus == ProtoCrewMember.RosterStatus.Available) && !KerbalRetireTimes.ContainsKey(pcm.name)) { if (pcm.trait != KerbalRoster.pilotTrait) { KerbalRoster.SetExperienceTrait(pcm, KerbalRoster.pilotTrait); } newHires.Add(pcm.name); OnCrewHired(pcm, int.MinValue); } } if (newHires.Count > 0) { StringBuilder sb = new StringBuilder(); sb.Append("Earliest crew retirement dates:"); foreach (string s in newHires) { sb.Append($"\n{s}, {KSPUtil.PrintDate(KerbalRetireTimes[s], false)}"); } sb.Append($"\n\nInteresting flights will delay retirement up to an additional {Math.Round(Settings.retireIncreaseCap / 31536000)} years."); PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InitialRetirementDateNotification", "Initial Retirement Dates", sb.ToString(), "OK", false, HighLogic.UISkin); } }
private void ProcessFirstLoad() { var newHires = new List <string>(); foreach (ProtoCrewMember pcm in HighLogic.CurrentGame.CrewRoster.Crew) { if ((pcm.rosterStatus == ProtoCrewMember.RosterStatus.Assigned || pcm.rosterStatus == ProtoCrewMember.RosterStatus.Available) && !KerbalRetireTimes.ContainsKey(pcm.name)) { if (pcm.trait != KerbalRoster.pilotTrait) { KerbalRoster.SetExperienceTrait(pcm, KerbalRoster.pilotTrait); } newHires.Add(pcm.name); OnCrewHired(pcm, int.MinValue); } } if (newHires.Count > 0) { StringBuilder sb = new StringBuilder(); sb.Append("Crew will retire as follows:"); foreach (string s in newHires) { sb.Append($"\n{s}, no earlier than {KSPUtil.PrintDate(KerbalRetireTimes[s], false)}"); } sb.Append("\n(Retirement will be delayed the more interesting flights they fly.)"); PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InitialRetirementDateNotification", "Initial Retirement Date", sb.ToString(), "OK", false, HighLogic.UISkin); } }
private void nautList() { GUILayout.BeginHorizontal(); try { GUILayout.Space(20); GUILayout.Label("Name", HighLogic.Skin.label, GUILayout.Width(144)); GUILayout.Label("Retires NET", HighLogic.Skin.label, GUILayout.Width(160)); } finally { GUILayout.EndHorizontal(); } foreach (string name in Crew.CrewHandler.Instance.kerbalRetireTimes.Keys) { GUILayout.BeginHorizontal(); try { GUILayout.Space(20); double rt = Crew.CrewHandler.Instance.kerbalRetireTimes[name]; GUILayout.Label(name, HighLogic.Skin.label, GUILayout.Width(144)); GUILayout.Label(Crew.CrewHandler.Instance.retirementEnabled ? KSPUtil.PrintDate(rt, false) : "(n/a)", HighLogic.Skin.label, GUILayout.Width(160)); } finally { GUILayout.EndHorizontal(); } } }
public string GetTrainingString(ProtoCrewMember pcm) { bool found = false; StringBuilder sb = new StringBuilder(); sb.Append("\n\nTraining:"); foreach (FlightLog.Entry ent in pcm.careerLog.Entries) { string pretty = GetPrettyCourseName(ent.type); if (!string.IsNullOrEmpty(pretty)) { if (ent.type == TrainingType_Proficiency) { found = true; sb.Append($"\n {pretty}{ent.target}"); } else if (ent.type == TrainingType_Mission) { double exp = GetExpiration(pcm.name, ent); if (exp > 0d) { sb.Append($"\n {pretty}{ent.target}. Expires {KSPUtil.PrintDate(exp, false)}"); } } } } if (found) { return(sb.ToString()); } else { return(string.Empty); } }
private void FixAstronauComplexUI() { if (_astronautComplex == null) { AstronautComplex[] mbs = FindObjectsOfType <AstronautComplex>(); int maxCount = -1; foreach (AstronautComplex c in mbs) { int count = c.ScrollListApplicants.Count + c.ScrollListAssigned.Count + c.ScrollListAvailable.Count + c.ScrollListKia.Count; if (count > maxCount) { maxCount = count; _astronautComplex = c; } } if (_astronautComplex == null) { return; } } int newAv = _astronautComplex.ScrollListAvailable.Count; int newAsgn = _astronautComplex.ScrollListAssigned.Count; int newKIA = _astronautComplex.ScrollListKia.Count; if (newAv != _countAvailable || newKIA != _countKIA || newAsgn != _countAssigned) { _countAvailable = newAv; _countAssigned = newAsgn; _countKIA = newKIA; foreach (UIListData <UIListItem> u in _astronautComplex.ScrollListAvailable) { CrewListItem cli = u.listItem.GetComponent <CrewListItem>(); if (cli == null) { continue; } FixTooltip(cli); if (cli.GetCrewRef().inactive) { cli.MouseoverEnabled = false; bool notTraining = true; for (int i = ActiveCourses.Count; i-- > 0 && notTraining;) { foreach (ProtoCrewMember pcm in ActiveCourses[i].Students) { if (pcm == cli.GetCrewRef()) { notTraining = false; cli.SetLabel("Training, done " + KSPUtil.PrintDate(ActiveCourses[i].startTime + ActiveCourses[i].GetTime(ActiveCourses[i].Students), false)); break; } } } if (notTraining) { cli.SetLabel("Recovering"); } } } foreach (UIListData <UIListItem> u in _astronautComplex.ScrollListAssigned) { CrewListItem cli = u.listItem.GetComponent <CrewListItem>(); if (cli != null) { FixTooltip(cli); } } foreach (UIListData <UIListItem> u in _astronautComplex.ScrollListKia) { CrewListItem cli = u.listItem.GetComponent <CrewListItem>(); if (cli != null) { if (_retirees.Contains(cli.GetName())) { cli.SetLabel("Retired"); cli.MouseoverEnabled = false; } } } } }
private void OnCrewHired(ProtoCrewMember pcm, int idx) { double retireTime; // Skip updating the retirement time if this is an existing kerbal. if (KerbalRetireTimes.ContainsKey(pcm.name)) { retireTime = KerbalRetireTimes[pcm.name]; } else { retireTime = KSPUtils.GetUT() + GetServiceTime(pcm); KerbalRetireTimes[pcm.name] = retireTime; } if (RetirementEnabled && idx != int.MinValue) { PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InitialRetirementDateNotification", "Initial Retirement Date", $"{pcm.name} will retire no earlier than {KSPUtil.PrintDate(retireTime, false)}\n(Retirement will be delayed the more interesting flights they fly.)", "OK", false, HighLogic.UISkin); } }
private void VesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog mrDialog, float data) { Debug.Log("[RP-0] - Vessel recovery processing"); var retirementChanges = new List <string>(); var inactivity = new List <string>(); double UT = KSPUtils.GetUT(); // normally we would use v.missionTime, but that doesn't seem to update // when you're not actually controlling the vessel double elapsedTime = UT - v.launchTime; Debug.Log($"[RP-0] mission elapsedTime: {KSPUtil.PrintDateDeltaCompact(elapsedTime, true, true)}"); // When flight duration was too short, mission training should not be set as expired. // This can happen when an on-the-pad failure occurs and the vessel is recovered. // We could perhaps override this if they're not actually in flight // (if the user didn't recover right from the pad I think this is a fair assumption) if (elapsedTime < Settings.minFlightDurationSecondsForTrainingExpire) { Debug.Log($"[RP-0] - mission time too short for crew to be inactive (elapsed time was {elapsedTime}, settings set for {Settings.minFlightDurationSecondsForTrainingExpire})"); return; } var validStatuses = new List <string> { FlightLog.EntryType.Flight.ToString(), Situation_FlightHigh, FlightLog.EntryType.Suborbit.ToString(), FlightLog.EntryType.Orbit.ToString(), FlightLog.EntryType.ExitVessel.ToString(), FlightLog.EntryType.Land.ToString(), FlightLog.EntryType.Flyby.ToString() }; foreach (ProtoCrewMember pcm in v.GetVesselCrew()) { Debug.Log("[RP-0] - Found ProtoCrewMember: " + pcm.displayName); var allFlightsDict = new Dictionary <string, int>(); int curFlight = pcm.careerLog.Last().flight; double inactivityMult = 0; double retirementMult = 0; foreach (FlightLog.Entry e in pcm.careerLog.Entries) { if (e.type == "Nationality") { continue; } if (e.type == TrainingType_Mission) { SetExpiration(pcm.name, e, KSPUtils.GetUT()); } if (validStatuses.Contains(e.type)) { int situationCount; var key = $"{e.target}-{e.type}"; if (allFlightsDict.ContainsKey(key)) { situationCount = allFlightsDict[key]; allFlightsDict[key] = ++situationCount; } else { situationCount = 1; allFlightsDict.Add(key, situationCount); } if (e.flight != curFlight) { continue; } if (TryGetBestSituationMatch(e.target, e.type, "Retire", out double situationMult)) { double countMult = 1 + Math.Pow(situationCount - 1, Settings.retireOffsetFlightNumPow); retirementMult += situationMult / countMult; } if (TryGetBestSituationMatch(e.target, e.type, "Inactive", out double inactivMult)) { inactivityMult += inactivMult; } } } Debug.Log("[RP-0] retirementMult: " + retirementMult); Debug.Log("[RP-0] inactivityMult: " + inactivityMult); double acMult = ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1; Debug.Log("[RP-0] AC multiplier: " + acMult); if (KerbalRetireTimes.TryGetValue(pcm.name, out double retTime)) { double stupidityPenalty = UtilMath.Lerp(Settings.retireOffsetStupidMin, Settings.retireOffsetStupidMax, pcm.stupidity); Debug.Log($"[RP-0] stupidityPenalty for {pcm.stupidity}: {stupidityPenalty}"); double retireOffset = retirementMult * 86400 * Settings.retireOffsetBaseMult / stupidityPenalty; if (retireOffset > 0) { KerbalRetireIncreases.TryGetValue(pcm.name, out double retIncreaseTotal); retIncreaseTotal += retireOffset; if (retIncreaseTotal > Settings.retireIncreaseCap) { // Cap the total retirement increase at a specific number of years retireOffset -= retIncreaseTotal - Settings.retireIncreaseCap; retIncreaseTotal = Settings.retireIncreaseCap; } KerbalRetireIncreases[pcm.name] = retIncreaseTotal; string sRetireOffset = KSPUtil.PrintDateDelta(retireOffset, false, false); Debug.Log("[RP-0] retire date increased by: " + sRetireOffset); retTime += retireOffset; KerbalRetireTimes[pcm.name] = retTime; retirementChanges.Add($"\n{pcm.name}, +{sRetireOffset}, no earlier than {KSPUtil.PrintDate(retTime, false)}"); } } inactivityMult = Math.Max(1, inactivityMult); double elapsedTimeDays = elapsedTime / 86400; double inactiveTimeDays = Math.Pow(Math.Max(Settings.inactivityMinFlightDurationDays, elapsedTimeDays), Settings.inactivityFlightDurationExponent) * Math.Min(Settings.inactivityMaxSituationMult, inactivityMult) / acMult; double inactiveTime = inactiveTimeDays * 86400; Debug.Log("[RP-0] inactive for: " + KSPUtil.PrintDateDeltaCompact(inactiveTime, true, false)); pcm.SetInactive(inactiveTime, false); inactivity.Add($"\n{pcm.name}, until {KSPUtil.PrintDate(inactiveTime + UT, true, false)}"); } if (inactivity.Count > 0) { StringBuilder sb = new StringBuilder(); sb.Append("The following crew members will be on leave:"); foreach (string s in inactivity) { sb.Append(s); } if (RetirementEnabled && retirementChanges.Count > 0) { sb.Append("\n\nThe following retirement changes have occurred:"); foreach (string s in retirementChanges) { sb.Append(s); } } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewUpdateNotification", "Crew Updates", sb.ToString(), "OK", true, HighLogic.UISkin); } }
protected void OnCrewHired(ProtoCrewMember pcm, int idx) { double retireTime = Planetarium.GetUniversalTime() + GetServiceTime(pcm); kerbalRetireTimes[pcm.name] = retireTime; if (retirementEnabled && idx != int.MinValue) { PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InitialRetirementDateNotification", "Initial Retirement Date", pcm.name + " will retire no earlier than " + KSPUtil.PrintDate(retireTime, false) + "\n(Retirement will be delayed the more interesting flights they fly.)", "OK", false, HighLogic.UISkin); } }
private void VesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog mrDialog, float data) { Debug.Log("[VR] - Vessel recovery processing"); List <string> retirementChanges = new List <string>(); List <string> inactivity = new List <string>(); double UT = Planetarium.GetUniversalTime(); // normally we would use v.missionTime, but that doesn't seem to update // when you're not actually controlling the vessel double elapsedTime = UT - v.launchTime; // When flight duration was too short, mission training should not be set as expired. // This can happen when an on-the-pad failure occurs and the vessel is recovered. // We could perhaps override this if they're not actually in flight // (if the user didn't recover right from the pad I think this is a fair assumption) if (elapsedTime < settings.minFlightDurationSecondsForTrainingExpire) { Debug.Log("[VR] - mission time too short for crew to be inactive (elapsed time was " + elapsedTime + ", settings set for " + settings.minFlightDurationSecondsForTrainingExpire + ")"); return; } foreach (ProtoCrewMember pcm in v.GetVesselCrew()) { Debug.Log("[VR] - Found ProtoCrewMember: " + pcm.displayName); bool hasSpace = false; bool hasOrbit = false; bool hasEVA = false; bool hasEVAOther = false; bool hasOther = false; bool hasOrbitOther = false; bool hasLandOther = false; int curFlight = pcm.careerLog.Last().flight; foreach (FlightLog.Entry e in pcm.careerLog.Entries) { if (e.type == "TRAINING_mission") { SetExpiration(pcm.name, e, Planetarium.GetUniversalTime()); } if (e.flight != curFlight) { continue; } bool isOther = false; if (!string.IsNullOrEmpty(e.target) && e.target != Planetarium.fetch.Home.name) { isOther = hasOther = true; } if (!string.IsNullOrEmpty(e.type)) { switch (e.type) { case "Suborbit": hasSpace = true; break; case "Orbit": if (isOther) { hasOrbitOther = true; } else { hasOrbit = true; } break; case "ExitVessel": if (isOther) { hasEVAOther = true; } else { hasEVA = true; } break; case "Land": if (isOther) { hasLandOther = true; } break; default: break; } } } double multiplier = 1d; double constant = 0.5d; if (hasSpace) { multiplier += settings.recSpace.x; constant += settings.recSpace.y; } if (hasOrbit) { multiplier += settings.recOrbit.x; constant += settings.recOrbit.y; } if (hasOther) { multiplier += settings.recOtherBody.x; constant += settings.recOtherBody.y; } if (hasOrbit && hasEVA) // EVA should only count while in orbit, not when walking on Earth { multiplier += settings.recEVA.x; constant += settings.recEVA.y; } if (hasEVAOther) { multiplier += settings.recEVAOther.x; constant += settings.recEVAOther.y; } if (hasOrbitOther) { multiplier += settings.recOrbitOther.x; constant += settings.recOrbitOther.y; } if (hasLandOther) { multiplier += settings.recLandOther.x; constant += settings.recLandOther.y; } double retTime; if (kerbalRetireTimes.TryGetValue(pcm.name, out retTime)) { double offset = constant * 86400d * settings.retireOffsetBaseMult / (1 + Math.Pow(Math.Max(curFlight + settings.retireOffsetFlightNumOffset, 0d), settings.retireOffsetFlightNumPow) * UtilMath.Lerp(settings.retireOffsetStupidMin, settings.retireOffsetStupidMax, pcm.stupidity)); if (offset > 0d) { retTime += offset; kerbalRetireTimes[pcm.name] = retTime; retirementChanges.Add("\n" + pcm.name + ", no earlier than " + KSPUtil.PrintDate(retTime, false)); } } multiplier /= (ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1d); double inactiveTime = elapsedTime * multiplier + constant * 86400d; pcm.SetInactive(inactiveTime, false); inactivity.Add("\n" + pcm.name + ", until " + KSPUtil.PrintDate(inactiveTime + UT, true, false)); } if (inactivity.Count > 0) { Debug.Log("[VR] - showing on leave message"); string msgStr = "The following crew members will be on leave:"; foreach (string s in inactivity) { msgStr += s; } if (retirementEnabled && retirementChanges.Count > 0) { msgStr += "\n\nThe following retirement changes have occurred:"; foreach (string s in retirementChanges) { msgStr += s; } } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewUpdateNotification", "Crew Updates", msgStr, "OK", true, HighLogic.UISkin); } }
public void Update() { if (HighLogic.CurrentGame == null || HighLogic.CurrentGame.CrewRoster == null) { return; } // Catch earlies if (firstLoad) { firstLoad = false; List <string> newHires = new List <string>(); foreach (ProtoCrewMember pcm in HighLogic.CurrentGame.CrewRoster.Crew) { if ((pcm.rosterStatus == ProtoCrewMember.RosterStatus.Assigned || pcm.rosterStatus == ProtoCrewMember.RosterStatus.Available) && !kerbalRetireTimes.ContainsKey(pcm.name)) { newHires.Add(pcm.name); OnCrewHired(pcm, int.MinValue); } } if (newHires.Count > 0) { string msgStr = "Crew will retire as follows:"; foreach (string s in newHires) { msgStr += "\n" + s + ", no earlier than " + KSPUtil.PrintDate(kerbalRetireTimes[s], false); } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InitialRetirementDateNotification", "Initial Retirement Date", msgStr + "\n(Retirement will be delayed the more interesting flights they fly.)", "OK", false, HighLogic.UISkin); } } // Retirements double time = Planetarium.GetUniversalTime(); if (nextUpdate < time) { // Ensure that CrewHandler updates happen at predictable times so that accurate KAC alarms can be set. do { nextUpdate += updateInterval; }while (nextUpdate < time); if (retirementEnabled) { foreach (KeyValuePair <string, double> kvp in kerbalRetireTimes) { ProtoCrewMember pcm = HighLogic.CurrentGame.CrewRoster[kvp.Key]; if (pcm == null) { toRemove.Add(kvp.Key); } else { if (pcm.rosterStatus != ProtoCrewMember.RosterStatus.Available) { if (pcm.rosterStatus != ProtoCrewMember.RosterStatus.Assigned) { toRemove.Add(kvp.Key); } continue; } if (pcm.inactive) { continue; } if (time > kvp.Value) { toRemove.Add(kvp.Key); retirees.Add(kvp.Key); pcm.rosterStatus = ProtoCrewMember.RosterStatus.Dead; } } } } bool anyCourseEnded = false; for (int i = ActiveCourses.Count; i-- > 0;) { ActiveCourse course = ActiveCourses[i]; if (course.ProgressTime(time)) //returns true when the course completes { ActiveCourses.RemoveAt(i); anyCourseEnded = true; } } for (int i = expireTimes.Count; i-- > 0;) { TrainingExpiration e = expireTimes[i]; if (time > e.expiration) { ProtoCrewMember pcm = HighLogic.CurrentGame.CrewRoster[e.pcmName]; if (pcm != null) { for (int j = pcm.careerLog.Entries.Count; j-- > 0;) { int eC = e.entries.Count; if (eC == 0) { break; } FlightLog.Entry ent = pcm.careerLog[j]; for (int k = eC; k-- > 0;) { // Allow only mission trainings to expire. // This check is actually only needed for old savegames as only these can have expirations on proficiencies. if (ent.type == "TRAINING_mission" && e.Compare(k, ent)) { ScreenMessages.PostScreenMessage(pcm.name + ": Expired: " + GetPrettyCourseName(ent.type) + ent.target); ent.type = "expired_" + ent.type; e.entries.RemoveAt(k); } } } } expireTimes.RemoveAt(i); } } // TODO remove from courses? Except I think they won't retire if inactive either so that's ok. if (toRemove.Count > 0) { string msgStr = string.Empty; foreach (string s in toRemove) { kerbalRetireTimes.Remove(s); if (HighLogic.CurrentGame.CrewRoster[s] != null) { msgStr += "\n" + s; } } if (!string.IsNullOrEmpty(msgStr)) { PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewRetirementNotification", "Crew Retirement", "The following retirements have occurred:\n" + msgStr, "OK", true, HighLogic.UISkin); } toRemove.Clear(); } if (anyCourseEnded || toRemove.Count > 0) { MaintenanceHandler.Instance.UpdateUpkeep(); } } // UI fixing if (inAC) { if (astronautComplex == null) { KSP.UI.Screens.AstronautComplex[] mbs = GameObject.FindObjectsOfType <KSP.UI.Screens.AstronautComplex>(); int maxCount = -1; foreach (KSP.UI.Screens.AstronautComplex c in mbs) { int count = c.ScrollListApplicants.Count + c.ScrollListAssigned.Count + c.ScrollListAvailable.Count + c.ScrollListKia.Count; if (count > maxCount) { maxCount = count; astronautComplex = c; } } if (astronautComplex == null) { return; } } int newAv = astronautComplex.ScrollListAvailable.Count; int newAsgn = astronautComplex.ScrollListAssigned.Count; int newKIA = astronautComplex.ScrollListKia.Count; if (newAv != countAvailable || newKIA != countKIA || newAsgn != countAssigned) { countAvailable = newAv; countAssigned = newAsgn; countKIA = newKIA; foreach (KSP.UI.UIListData <KSP.UI.UIListItem> u in astronautComplex.ScrollListAvailable) { KSP.UI.CrewListItem cli = u.listItem.GetComponent <KSP.UI.CrewListItem>(); if (cli != null) { FixTooltip(cli); if (cli.GetCrewRef().inactive) { cli.MouseoverEnabled = false; bool notTraining = true; for (int i = ActiveCourses.Count; i-- > 0 && notTraining;) { foreach (ProtoCrewMember pcm in ActiveCourses[i].Students) { if (pcm == cli.GetCrewRef()) { notTraining = false; cli.SetLabel("Training, done " + KSPUtil.PrintDate(ActiveCourses[i].startTime + ActiveCourses[i].GetTime(ActiveCourses[i].Students), false)); break; } } } if (notTraining) { cli.SetLabel("Recovering"); } } } } foreach (KSP.UI.UIListData <KSP.UI.UIListItem> u in astronautComplex.ScrollListAssigned) { KSP.UI.CrewListItem cli = u.listItem.GetComponent <KSP.UI.CrewListItem>(); if (cli != null) { FixTooltip(cli); } } foreach (KSP.UI.UIListData <KSP.UI.UIListItem> u in astronautComplex.ScrollListKia) { KSP.UI.CrewListItem cli = u.listItem.GetComponent <KSP.UI.CrewListItem>(); if (cli != null) { if (retirees.Contains(cli.GetName())) { cli.SetLabel("Retired"); cli.MouseoverEnabled = false; } } } } } }
private static void DisplayKerbal(RMKerbal kerbal) { GUIStyle labelStyle; if (kerbal.Status == ProtoCrewMember.RosterStatus.Dead || kerbal.Status == ProtoCrewMember.RosterStatus.Missing || (kerbal.SalaryContractDispute && kerbal.Trait == "Tourist")) { labelStyle = RMStyle.LabelStyleRed; } else if (kerbal.SalaryContractDispute && kerbal.Trait != "Tourist") { labelStyle = RMStyle.LabelStyleMagenta; } else if (kerbal.Status == ProtoCrewMember.RosterStatus.Assigned) { labelStyle = RMStyle.LabelStyleYellow; } else { labelStyle = RMStyle.LabelStyle; } if (InstalledMods.IsDfInstalled && kerbal.Type == ProtoCrewMember.KerbalType.Unowned) { labelStyle = RMStyle.LabelStyleCyan; } string buttonToolTip = "Crew Member Name."; GUILayout.Label(new GUIContent(kerbal.Name, buttonToolTip), labelStyle, GUILayout.Width(130)); Rect rect = GUILayoutUtility.GetLastRect(); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } buttonToolTip = "Crew Member's Current Salary."; GUILayout.Label(new GUIContent(kerbal.Salary.ToString("###,##0"), buttonToolTip), labelStyle, GUILayout.Width(55)); rect = GUILayoutUtility.GetLastRect(); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } buttonToolTip = "Crew Member's Current Outstanding/Owing Salary."; GUILayout.Label(new GUIContent(kerbal.OwedSalary.ToString("###,##0"), buttonToolTip), labelStyle, GUILayout.Width(60)); rect = GUILayoutUtility.GetLastRect(); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } buttonToolTip = "How many Pay periods salary has been in dispute."; GUILayout.Label(new GUIContent(kerbal.SalaryContractDisputePeriods.ToString("#0"), buttonToolTip), labelStyle, GUILayout.Width(15)); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } buttonToolTip = "Payrise Requested."; GUILayout.Label(new GUIContent(kerbal.PayriseRequired.ToString("###,##0"), buttonToolTip), labelStyle, GUILayout.Width(55)); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } buttonToolTip = "Kerbals usual Profession."; GUILayout.Label(new GUIContent(kerbal.RealTrait, buttonToolTip), labelStyle, GUILayout.Width(75)); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } buttonToolTip = "Next Salary payment is due on:"; GUILayout.Label(new GUIContent(KSPUtil.PrintDate((int)kerbal.TimeSalaryDue, false), buttonToolTip), labelStyle, GUILayout.Width(65)); if (Event.current.type == EventType.Repaint && ShowToolTips) { ToolTip = RMToolTips.SetActiveToolTip(rect, GUI.tooltip, ref ToolTipActive, 10); } }
protected void VesselRecoveryRequested(Vessel v) { double elapsedTime = v.missionTime; List <string> retirementChanges = new List <string>(); List <string> inactivity = new List <string>(); double UT = Planetarium.GetUniversalTime(); foreach (ProtoCrewMember pcm in v.GetVesselCrew()) { bool hasSpace = false; bool hasOrbit = false; bool hasEVA = false; bool hasEVAOther = false; bool hasOther = false; bool hasOrbitOther = false; bool hasLandOther = false; int curFlight = pcm.careerLog.Last().flight; foreach (FlightLog.Entry e in pcm.careerLog.Entries) { if (e.type == "TRAINING_mission") { SetExpiration(pcm.name, e, Planetarium.GetUniversalTime()); } if (e.flight != curFlight) { continue; } bool isOther = false; if (!string.IsNullOrEmpty(e.target) && e.target != Planetarium.fetch.Home.name) { isOther = hasOther = true; } if (!string.IsNullOrEmpty(e.type)) { switch (e.type) { case "Suborbit": hasSpace = true; break; case "Orbit": if (isOther) { hasOrbitOther = true; } else { hasOrbit = true; } break; case "ExitVessel": if (isOther) { hasEVAOther = true; } else { hasEVA = true; } break; case "Land": if (isOther) { hasLandOther = true; } break; default: break; } } } double multiplier = 1d; double constant = 0.5d; if (hasSpace) { multiplier += settings.recSpace.x; constant += settings.recSpace.y; } if (hasOrbit) { multiplier += settings.recOrbit.x; constant += settings.recOrbit.y; } if (hasOther) { multiplier += settings.recOtherBody.x; constant += settings.recOtherBody.y; } if (hasEVA) { multiplier += settings.recEVA.x; constant += settings.recEVA.y; } if (hasEVAOther) { multiplier += settings.recEVAOther.x; constant += settings.recEVAOther.y; } if (hasOrbitOther) { multiplier += settings.recOrbitOther.x; constant += settings.recOrbitOther.y; } if (hasLandOther) { multiplier += settings.recLandOther.x; constant += settings.recLandOther.y; } double retTime; if (kerbalRetireTimes.TryGetValue(pcm.name, out retTime)) { double offset = constant * 86400d * settings.retireOffsetBaseMult / (1 + Math.Pow(Math.Max(curFlight + settings.retireOffsetFlightNumOffset, 0d), settings.retireOffsetFlightNumPow) * UtilMath.Lerp(settings.retireOffsetStupidMin, settings.retireOffsetStupidMax, pcm.stupidity)); if (offset > 0d) { retTime += offset; kerbalRetireTimes[pcm.name] = retTime; retirementChanges.Add("\n" + pcm.name + ", no earlier than " + KSPUtil.PrintDate(retTime, false)); } } multiplier /= (ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1d); double inactiveTime = elapsedTime * multiplier + constant * 86400d; pcm.SetInactive(inactiveTime, false); inactivity.Add("\n" + pcm.name + ", until " + KSPUtil.PrintDate(inactiveTime + UT, true, false)); } if (inactivity.Count > 0) { string msgStr = "The following crew members will be on leave:"; foreach (string s in inactivity) { msgStr += s; } if (retirementEnabled && retirementChanges.Count > 0) { msgStr += "\n\nThe following retirement changes have occurred:"; foreach (string s in retirementChanges) { msgStr += s; } } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewUpdateNotification", "Crew Updates", msgStr, "OK", true, HighLogic.UISkin); } }
protected void nautListRow(tabs currentTab, ProtoCrewMember student) { GUIStyle style = HighLogic.Skin.label; ActiveCourse currentCourse = null; if (activeMap.ContainsKey(student)) { currentCourse = activeMap[student]; } bool onSelectedCourse = selectedCourse != null && currentCourse != null && currentCourse.id == selectedCourse.id; if (onSelectedCourse) { style = boldLabel; } bool selectedForCourse = selectedCourse != null && selectedCourse.Students.Contains(student); GUILayout.BeginHorizontal(); try { GUILayout.Label(String.Format("{0} {1}", student.trait.Substring(0, 1), student.experienceLevel), GUILayout.Width(24)); if (currentCourse == null && selectedCourse != null && (selectedForCourse || selectedCourse.MeetsStudentReqs(student))) { if (toggleButton(student.name, selectedForCourse, GUILayout.Width(144))) { if (selectedForCourse) { selectedCourse.RemoveStudent(student); } else { selectedCourse.AddStudent(student); } } } else if (currentTab == tabs.Training) { if (GUILayout.Button(student.name, GUILayout.Width(144))) { selectedNaut = student; } } else { GUILayout.Label(student.name, GUILayout.Width(144)); } string course, complete, retires; if (currentCourse == null) { if (student.inactive) { course = "(inactive)"; complete = KSPUtil.PrintDate(student.inactiveTimeEnd, false); } else { course = "(free)"; complete = "(n/a)"; } } else { course = currentCourse.name; complete = KSPUtil.PrintDate(currentCourse.CompletionTime(), false); } GUILayout.Label(course, GUILayout.Width(96)); GUILayout.Label(complete, GUILayout.Width(80)); if (CrewHandler.Instance.kerbalRetireTimes.ContainsKey(student.name)) { retires = CrewHandler.Instance.retirementEnabled ? KSPUtil.PrintDate(CrewHandler.Instance.kerbalRetireTimes[student.name], false) : "(n/a)"; } else { retires = "(unknown)"; } GUILayout.Label(retires, GUILayout.Width(80)); if (currentCourse != null) { if (currentCourse.seatMin > 1) { if (GUILayout.Button("X", GUILayout.ExpandWidth(false))) { cancelCourse(currentCourse); } } else { if (GUILayout.Button("X", GUILayout.ExpandWidth(false))) { leaveCourse(currentCourse, student); } } } } finally { GUILayout.EndHorizontal(); } }
protected void nautListRow(tabs currentTab, ProtoCrewMember student) { GUIStyle style = HighLogic.Skin.label; ActiveCourse currentCourse = null; if (activeMap.ContainsKey(student)) { currentCourse = activeMap[student]; } bool onSelectedCourse = selectedCourse != null && currentCourse != null && currentCourse.id == selectedCourse.id; if (onSelectedCourse) { style = boldLabel; } bool selectedForCourse = selectedCourse != null && selectedCourse.Students.Contains(student); GUILayout.BeginHorizontal(); try { GUILayout.Label(String.Format("{0} {1}", student.trait.Substring(0, 1), student.experienceLevel), GUILayout.Width(24)); if (currentCourse == null && selectedCourse != null && (selectedForCourse || selectedCourse.MeetsStudentReqs(student))) { if (toggleButton(student.name, selectedForCourse, GUILayout.Width(144))) { if (selectedForCourse) { selectedCourse.RemoveStudent(student); } else { selectedCourse.AddStudent(student); } } } else if (currentTab == tabs.Training) { if (GUILayout.Button(student.name, GUILayout.Width(144))) { selectedNaut = student; } } else { GUILayout.Label(student.name, GUILayout.Width(144)); } string course, complete, retires; if (currentCourse == null) { if (student.inactive) { course = "(inactive)"; complete = KSPUtil.PrintDate(student.inactiveTimeEnd, false); } else { course = "(free)"; complete = "(n/a)"; } } else { course = currentCourse.name; complete = KSPUtil.PrintDate(currentCourse.CompletionTime(), false); } GUILayout.Label(course, GUILayout.Width(96)); GUILayout.Label(complete, GUILayout.Width(80)); if (CrewHandler.Instance.kerbalRetireTimes.ContainsKey(student.name)) { retires = CrewHandler.Instance.retirementEnabled ? KSPUtil.PrintDate(CrewHandler.Instance.kerbalRetireTimes[student.name], false) : "(n/a)"; } else { retires = "(unknown)"; } GUILayout.Label(retires, GUILayout.Width(80)); if (currentCourse != null) { if (currentCourse.seatMin > 1) { if (GUILayout.Button("X", GUILayout.ExpandWidth(false))) { cancelCourse(currentCourse); } } else { if (GUILayout.Button("X", GUILayout.ExpandWidth(false))) { leaveCourse(currentCourse, student); } } if (KACWrapper.APIReady && GUILayout.Button(nautRowAlarmBtnContent, GUILayout.ExpandWidth(false))) { // CrewHandler processes trainings every 3600 seconds. Need to account for that to set up accurate KAC alarms. double completeUT = currentCourse.CompletionTime(); double timeDiff = completeUT - CrewHandler.Instance.nextUpdate; double timesChRun = Math.Ceiling(timeDiff / CrewHandler.Instance.updateInterval); double alarmUT = CrewHandler.Instance.nextUpdate + timesChRun * CrewHandler.Instance.updateInterval; string alarmTxt = $"{currentCourse.name} - {student.name}"; KACWrapper.KAC.CreateAlarm(KACWrapper.KACAPI.AlarmTypeEnum.Crew, alarmTxt, alarmUT); } } } finally { GUILayout.EndHorizontal(); } }