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 static void LoadConfig() { if (loaded) { return; } Log("Loading config...", LogLevel.Important); BodyTravelTimes = new Dictionary <CelestialBody, double>(FlightGlobals.Bodies.Count); CelestialBody homePlanet = GetPlanet(Planetarium.fetch.Home); foreach (CelestialBody body in FlightGlobals.Bodies) { if (body.isHomeWorld) { BodyTravelTimes[body] = 0; } else if (body == Planetarium.fetch.Sun) { BodyTravelTimes[body] = homePlanet.orbit.period; } else if (body.HasParent(homePlanet)) { BodyTravelTimes[body] = body.orbit.period / 5; } else { BodyTravelTimes[body] = TimeBetweenLaunchWindows(homePlanet.orbit, GetPlanet(body).orbit) + HohmannMultiplier * HohmannTransferTime(homePlanet.orbit, GetPlanet(body).orbit); } Core.Log("Travel time for " + body.name + " is " + KSPUtil.PrintDateDeltaCompact(BodyTravelTimes[body], true, false), LogLevel.Important); } ConfigNode[] cfgArray = GameDatabase.Instance.GetConfigNodes("URGENT_CONTRACTS_CONFIG"); foreach (ConfigNode cfg in cfgArray) { foreach (ConfigNode n in cfg.GetNodes("CONTRACT_RULE")) { ContractRule rule = new ContractRule(n); ContractRules.Add(rule); Core.Log("Added contract from config file: " + rule, LogLevel.Important); } foreach (ConfigNode n in cfg.GetNodes("TRAVEL_TIME")) { CelestialBody body = FlightGlobals.GetBodyByName(GetString(n, "Name")); if (body == null) { continue; } BodyTravelTimes[body] = n.HasValue("TravelTime") ? GetDouble(n, "TravelTime") : (GetDouble(n, "TravelDays") * 21600); Core.Log("Overriding travel time for " + body.name + " to be " + KSPUtil.PrintDateDeltaCompact(BodyTravelTimes[body], true, false), LogLevel.Important); } } if (cfgArray.Length == 0) { Core.Log("Config file not found!", LogLevel.Error); } loaded = true; }
void LogContractInfo(Contract c) { if (!Core.IsLogging(Core.LogLevel.Debug)) { return; } Core.Log("Title: " + c.Title); Core.Log("Type: " + c.GetType().Name); Core.Log("State: " + c.ContractState); Core.Log("Target body: " + (ContractRule.GetTargetBody(c)?.name ?? "N/A")); Core.Log("Deadline: " + KSPUtil.PrintDateDeltaCompact(c.TimeDeadline, true, true)); }
public override string ToString() { string res = "Types = { "; bool needComma = false; foreach (string t in Types) { if (needComma) { res += ", "; } res += t; needComma = true; } res += " } GracePeriod = '" + KSPUtil.PrintDateDeltaCompact(GracePeriod, true, false) + "' TravelTimeMultiplier = " + TravelTimeMultiplier.ToString("N1"); return(res); }
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); }
public void DrawInfo(double target_inclination = -1) { GUILayout.BeginHorizontal(); { GUILayout.BeginVertical(); { GUILayout.Label("Inclination:"); GUILayout.Label("Apoapsis:"); GUILayout.Label("Time to Apoapsis:"); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { if (target_inclination >= 0) { GUILayout.Label(string.Format("{0:F3}° ► {1:F3}° Err: {2:F3}°", VesselOrbit.inclination, target_inclination, norm_correction.LastError)); } else { GUILayout.Label(string.Format("{0:F3}° Err: {1:F3}°", VesselOrbit.inclination, norm_correction.LastError)); } GUILayout.Label(string.Format("{0} ► {1}", Utils.formatBigValue((float)VesselOrbit.ApA, "m", "F3"), Utils.formatBigValue((float)(TargetR - Body.Radius), "m", "F3"))); GUILayout.Label(string.Format("{0} ► {1}", KSPUtil.PrintDateDeltaCompact(TimeToClosestApA, true, true), KSPUtil.PrintDateDeltaCompact(TimeToApA, true, true))); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); }
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); } }
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; Debug.Log("[VR] 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("[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; int numFlightsDone = pcm.careerLog.Entries.Count(e => e.type == "Recover"); foreach (FlightLog.Entry e in pcm.careerLog.Entries) { if (e.type == "TRAINING_mission") { SetExpiration(pcm.name, e, Planetarium.GetUniversalTime()); } if (e.flight != curFlight || e.type == "Nationality") { continue; } Debug.Log($"[VR] processing flight entry: {e.type}; {e.target}"); bool isOther = false; if (!string.IsNullOrEmpty(e.target) && e.target != Planetarium.fetch.Home.name) { Debug.Log($"[VR] flight is beyond Earth"); 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; Debug.Log($"[VR] has space, mult {settings.recSpace.x}; constant {settings.recSpace.y}"); } if (hasOrbit) { multiplier += settings.recOrbit.x; constant += settings.recOrbit.y; Debug.Log($"[VR] has orbit, mult {settings.recOrbit.x}; constant {settings.recOrbit.y}"); } if (hasOther) { multiplier += settings.recOtherBody.x; constant += settings.recOtherBody.y; Debug.Log($"[VR] has other body, mult {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; Debug.Log($"[VR] has EVA, mult {settings.recEVA.x}; constant {settings.recEVA.y}"); } if (hasEVAOther) { multiplier += settings.recEVAOther.x; constant += settings.recEVAOther.y; Debug.Log($"[VR] has EVA at another body, mult {settings.recEVAOther.x}; constant {settings.recEVAOther.y}"); } if (hasOrbitOther) { multiplier += settings.recOrbitOther.x; constant += settings.recOrbitOther.y; Debug.Log($"[VR] has orbit around another body, mult {settings.recOrbitOther.x}; constant {settings.recOrbitOther.y}"); } if (hasLandOther) { multiplier += settings.recLandOther.x; constant += settings.recLandOther.y; Debug.Log($"[VR] has landed on another body, mult {settings.recLandOther.x}; constant {settings.recLandOther.y}"); } Debug.Log("[VR] multiplier: " + multiplier); Debug.Log("[VR] AC multiplier: " + (ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1d)); Debug.Log("[VR] constant: " + constant); double retTime; if (kerbalRetireTimes.TryGetValue(pcm.name, out retTime)) { double offset = constant * 86400d * settings.retireOffsetBaseMult / (1 + Math.Pow(Math.Max(numFlightsDone + settings.retireOffsetFlightNumOffset, 0d), settings.retireOffsetFlightNumPow) * UtilMath.Lerp(settings.retireOffsetStupidMin, settings.retireOffsetStupidMax, pcm.stupidity)); if (offset > 0d) { Debug.Log("[VR] retire date increased by: " + KSPUtil.PrintDateDeltaCompact(offset, true, false)); Debug.Log($"[VR] constant: {constant}; curFlight: {numFlightsDone}; stupidity: {pcm.stupidity}"); 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; Debug.Log("[VR] 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) { 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 CheckAndApply(Contract c, double chance = 1) { double minDeadline = GetMinDeadline(c); double d = c.TimeDeadline / minDeadline; if (((d < 1) || (d > 1 + UrgentContractsSettings.RandomFactor)) && (Core.rand.NextDouble() < chance)) { d = minDeadline * (1 + Core.rand.NextDouble() * UrgentContractsSettings.RandomFactor) + UrgentContractsSettings.AddGraceDays * 21600; double m = 1; if (d >= 21600) { m = 60; } if (d >= 21600 * 10) { m = 3600; } if (d >= 21600 * 426) { m = 21600; } d = Math.Round(d / m) * m; Core.Log("Deadline for " + c.GetType().Name + " (\"" + c.Title + "\") adjusted from " + KSPUtil.PrintDateDeltaCompact(c.TimeDeadline, true, false) + " to " + KSPUtil.PrintDateDeltaCompact(d, true, false), Core.LogLevel.Important); c.TimeDeadline = d; } else { Core.Log("Deadline is fine."); } }
private static string PrepareNotBuildMessage(ShipTemplate shipTemplate) { return($"<color=orange>Build in {KSPUtil.PrintDateDeltaCompact(ConstructScenario.Instance.ConstructionFinishAt(shipTemplate), true, false)}</color>"); }
private static string PrepareStartedMessage(ShipTemplate shipTemplate) { return($"<color=yellow>Ready in {KSPUtil.PrintDateDeltaCompact(ConstructScenario.Instance.ConstructionFinishAt(shipTemplate), true, false)}</color>"); }