diff --git a/GameData/RP-1/Resources/KCT_repair.truecolor b/GameData/RP-1/Resources/KCT_repair.truecolor
new file mode 100644
index 00000000000..185036e1364
Binary files /dev/null and b/GameData/RP-1/Resources/KCT_repair.truecolor differ
diff --git a/Source/RP0/Harmony/FlightInputHandler.cs b/Source/RP0/Harmony/FlightInputHandler.cs
new file mode 100644
index 00000000000..fcaa0fd8e46
--- /dev/null
+++ b/Source/RP0/Harmony/FlightInputHandler.cs
@@ -0,0 +1,22 @@
+using HarmonyLib;
+
+namespace RP0.Harmony
+{
+ [HarmonyPatch(typeof(FlightInputHandler))]
+ internal class PatchFlightInputHandler
+ {
+ ///
+ /// Makes sure that throttle stays at 0 when repairs were done and vessel comes off rails.
+ ///
+ [HarmonyPostfix]
+ [HarmonyPatch("SetLaunchCtrlState")]
+ internal static void Postfix_SetLaunchCtrlState()
+ {
+ bool b = SpaceCenterManagement.Instance?.DoingVesselRepair ?? false;
+ if (b)
+ {
+ FlightInputHandler.state.mainThrottle = 0;
+ }
+ }
+ }
+}
diff --git a/Source/RP0/ModIntegrations/TFInterop.cs b/Source/RP0/ModIntegrations/TFInterop.cs
new file mode 100644
index 00000000000..d72b3e67543
--- /dev/null
+++ b/Source/RP0/ModIntegrations/TFInterop.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace RP0
+{
+ public static class TFInterop
+ {
+ private static bool? _isTestFlightInstalled = null;
+ private static bool? _hasSupportForReset = null;
+ private static Assembly _assembly;
+ private static MethodInfo _miGetVesselStatus;
+ private static MethodInfo _miResetAllFailuresOnVessel;
+ private static MethodInfo _miResetAllRunTimesOnVessel;
+
+ public static bool IsTestFlightInstalled
+ {
+ get
+ {
+ EnsureReflectionInitialized();
+ return _isTestFlightInstalled.Value;
+ }
+ }
+ public static bool HasSupportForReset
+ {
+ get
+ {
+ EnsureReflectionInitialized();
+ return _hasSupportForReset.Value;
+ }
+ }
+
+ public static bool VesselHasFailedParts(Vessel v)
+ {
+ if (v == null) return false;
+
+ EnsureReflectionInitialized();
+ var res = (int)_miGetVesselStatus.Invoke(null, new object[] { v });
+ // 0 = OK, 1 = Has failure, -1 = Could not find TestFlight Core on Part
+ return res > 0;
+ }
+
+ public static void ResetAllFailures(Vessel v)
+ {
+ if (v == null) return;
+
+ EnsureReflectionInitialized();
+ _miResetAllFailuresOnVessel.Invoke(null, new object[] { v });
+ _miResetAllRunTimesOnVessel.Invoke(null, new object[] { v });
+ }
+
+ private static void EnsureReflectionInitialized()
+ {
+ if (_isTestFlightInstalled.HasValue) return;
+
+ _assembly = AssemblyLoader.loadedAssemblies.FirstOrDefault((AssemblyLoader.LoadedAssembly la) => string.Equals(la.name, "TestFlightCore", StringComparison.OrdinalIgnoreCase))?.assembly;
+ _isTestFlightInstalled = _assembly != null;
+ _hasSupportForReset = false;
+
+ if (_isTestFlightInstalled.Value)
+ {
+ var type = _assembly.GetType("TestFlightCore.TestFlightInterface");
+ _miGetVesselStatus = type.GetMethod("GetVesselStatus", BindingFlags.Public | BindingFlags.Static);
+ _miResetAllFailuresOnVessel = type.GetMethod("ResetAllFailuresOnVessel", BindingFlags.Public | BindingFlags.Static);
+ _miResetAllRunTimesOnVessel = type.GetMethod("ResetAllRunTimesOnVessel", BindingFlags.Public | BindingFlags.Static);
+ _hasSupportForReset = _miResetAllRunTimesOnVessel != null;
+ }
+ }
+ }
+}
diff --git a/Source/RP0/RP0.csproj b/Source/RP0/RP0.csproj
index b8d7162b7c4..c6f3ccdacf0 100644
--- a/Source/RP0/RP0.csproj
+++ b/Source/RP0/RP0.csproj
@@ -38,7 +38,10 @@
+
+
+
@@ -283,7 +286,6 @@
False
- ..\..\ContractConfigurator\source\ContractConfigurator\bin\Release\ContractConfigurator.dll
False
@@ -291,16 +293,13 @@
False
- ..\..\..\..\..\..\Games\R112\KSP_x64_Data\Managed\Ionic.Zip.dll
False
False
- ..\..\..\..\..\..\..\temp\dlls\Kerbalism112.dll
False
- ..\..\..\..\..\..\Games\R112\GameData\KSPCommunityFixes\Plugins\KSPCommunityFixes.dll
False
@@ -310,7 +309,9 @@
False
- ..\..\..\..\..\..\..\Games\R112\GameData\ROUtils\Plugins\ROUtils.dll
+ False
+
+
False
@@ -322,51 +323,37 @@
False
-
- False
+
False
-
- False
- ..\..\..\KSP DLL\1.12.3\UnityEngine.AssetBundleModule.dll
+
False
-
- False
+
False
-
- False
- ..\..\..\..\..\..\Games\R112\KSP_x64_Data\Managed\UnityEngine.ImageConversionModule.dll
+
False
-
- False
+
False
-
- False
+
False
-
- False
+
False
-
- False
- ..\..\..\..\..\..\Games\R112\KSP_x64_Data\Managed\UnityEngine.ScreenCaptureModule.dll
+
False
-
- False
+
False
False
-
- False
- ..\..\ContractConfigurator\source\ContractConfigurator\bin\Release\UnityEngine.UIModule.dll
+
False
diff --git a/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs b/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs
index 34a466c9ec1..2329b09ae9c 100644
--- a/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs
+++ b/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs
@@ -1,7 +1,8 @@
-using System;
+using ROUtils.DataTypes;
+using System;
+using System.Collections.Generic;
using UniLinq;
using UnityEngine;
-using ROUtils.DataTypes;
namespace RP0
{
@@ -44,6 +45,8 @@ public class LaunchComplex : IConfigNode
public PersistentObservableList PadConstructions = new PersistentObservableList();
[Persistent]
public PersistentObservableList Recon_Rollout = new PersistentObservableList();
+ [Persistent]
+ public PersistentObservableList VesselRepairs = new PersistentObservableList();
private double _rate;
private double _rateHRCapped;
@@ -142,6 +145,7 @@ void AddListeners()
BuildList.Updated += updated;
Warehouse.Updated += updated;
Recon_Rollout.Updated += lcpUpdated;
+ VesselRepairs.Updated += lcpUpdated;
}
#endregion
@@ -207,10 +211,12 @@ public int LaunchPadCount
public bool IsEmpty => LCType == LaunchComplexType.Hangar && BuildList.Count == 0 && Warehouse.Count == 0 && Engineers == 0 && LCData.StartingHangar.Compare(this);
- public bool IsActive => BuildList.Count > 0 || Recon_Rollout.Any(rr => !rr.IsComplete());
- public bool CanDismantle => BuildList.Count == 0 && Warehouse.Count == 0 && !Recon_Rollout.Any(r => r.RRType != ReconRolloutProject.RolloutReconType.Reconditioning);
- public bool CanModifyButton => BuildList.Count == 0 && Warehouse.Count == 0 && Recon_Rollout.Count == 0;
- public bool CanModifyReal => Recon_Rollout.Count == 0;
+ public bool IsActive => BuildList.Count > 0 || GetAllLCOps().Any(op => !op.IsComplete());
+ public bool CanDismantle => BuildList.Count == 0 && Warehouse.Count == 0 &&
+ !Recon_Rollout.Any(r => r.RRType != ReconRolloutProject.RolloutReconType.Reconditioning) &&
+ VesselRepairs.Count == 0;
+ public bool CanModifyButton => BuildList.Count == 0 && Warehouse.Count == 0 && Recon_Rollout.Count == 0 && VesselRepairs.Count == 0;
+ public bool CanModifyReal => Recon_Rollout.Count == 0 && VesselRepairs.Count == 0;
public bool CanIntegrate => ProjectBPTotal == 0d;
private double _projectBPTotal = -1d;
@@ -219,7 +225,7 @@ public int LaunchPadCount
public double RecalculateProjectBP()
{
_projectBPTotal = 0d;
- foreach (var r in Recon_Rollout)
+ foreach (var r in GetAllLCOps())
{
if (!r.IsBlocking || r.IsComplete())
continue;
@@ -250,8 +256,8 @@ public void RecalculateBuildRates()
foreach (var vp in BuildList)
vp.UpdateBuildRate();
- foreach (var rr in Recon_Rollout)
- rr.UpdateBuildRate();
+ foreach (var op in GetAllLCOps())
+ op.UpdateBuildRate();
RecalculateProjectBP();
@@ -418,7 +424,7 @@ public void Load(ConfigNode node)
}
}
- foreach (var rr in Recon_Rollout)
+ foreach (var rr in GetAllLCOps())
rr.LC = this;
foreach (var vp in BuildList)
@@ -447,6 +453,19 @@ public void PostLoad(LCSpaceCenter ksc)
}
}
+ public IEnumerable GetAllLCOps()
+ {
+ foreach (var item in Recon_Rollout)
+ {
+ yield return item;
+ }
+
+ foreach (var item in VesselRepairs)
+ {
+ yield return item;
+ }
+ }
+
private void CalculateAndSetRates()
{
_strategyRateMultiplier = CurrencyUtils.Rate(LCType == LaunchComplexType.Pad ? TransactionReasonsRP0.RateIntegrationVAB : TransactionReasonsRP0.RateIntegrationSPH);
diff --git a/Source/RP0/SpaceCenter/Projects/ISpaceCenterProject.cs b/Source/RP0/SpaceCenter/Projects/ISpaceCenterProject.cs
index e4ccc2d5040..0466f6bf2e9 100644
--- a/Source/RP0/SpaceCenter/Projects/ISpaceCenterProject.cs
+++ b/Source/RP0/SpaceCenter/Projects/ISpaceCenterProject.cs
@@ -9,7 +9,8 @@ public enum ProjectType
Reconditioning,
KSC,
AirLaunch,
- Crew
+ Crew,
+ VesselRepair
};
public interface ISpaceCenterProject
diff --git a/Source/RP0/SpaceCenter/Projects/LCOpsProject.cs b/Source/RP0/SpaceCenter/Projects/LCOpsProject.cs
index 516c3420d53..02fb9164d35 100644
--- a/Source/RP0/SpaceCenter/Projects/LCOpsProject.cs
+++ b/Source/RP0/SpaceCenter/Projects/LCOpsProject.cs
@@ -18,10 +18,12 @@ public abstract class LCOpsProject : ConfigNodePersistenceBase, ISpaceCenterProj
private bool _wasComplete;
protected double _buildRate = -1;
+ public Guid AssociatedIdAsGuid => new Guid(associatedID);
+
public abstract TransactionReasonsRP0 TransactionReason { get; }
protected abstract TransactionReasonsRP0 transactionReasonTime { get; }
- public VesselProject AssociatedVP => KCTUtilities.FindVPByID(LC, new Guid(associatedID));
+ public VesselProject AssociatedVP => KCTUtilities.FindVPByID(LC, AssociatedIdAsGuid);
protected LaunchComplex _lc = null;
public LaunchComplex LC
@@ -42,6 +44,14 @@ public LaunchComplex LC
break;
}
}
+ else if (this is VesselRepairProject vr)
+ {
+ if (lc.VesselRepairs.Contains(vr))
+ {
+ _lc = lc;
+ break;
+ }
+ }
}
}
}
@@ -239,7 +249,7 @@ public double GetTimeLeftEstAll()
public static double GetTotalBlockingProjectTime(LaunchComplex lc)
{
- foreach (var r in lc.Recon_Rollout)
+ foreach (var r in lc.GetAllLCOps())
{
if (r.IsBlocking && !r.IsComplete())
AddLCP(r);
@@ -288,7 +298,7 @@ public static LCOpsProject GetFirstCompleting(LaunchComplex lc)
LCOpsProject lcp = null;
// The blocking LCP with the lowest time left
// doesn't have to worry about build rate changing
- foreach (var r in lc.Recon_Rollout)
+ foreach (var r in lc.GetAllLCOps())
{
if (r.IsComplete())
continue;
diff --git a/Source/RP0/SpaceCenter/Projects/ReconRolloutProject.cs b/Source/RP0/SpaceCenter/Projects/ReconRolloutProject.cs
index 81d613741bc..c577180ef75 100644
--- a/Source/RP0/SpaceCenter/Projects/ReconRolloutProject.cs
+++ b/Source/RP0/SpaceCenter/Projects/ReconRolloutProject.cs
@@ -7,8 +7,8 @@ public class ReconRolloutProject : LCOpsProject
{
public enum RolloutReconType { Reconditioning, Rollout, Rollback, Recovery, None, AirlaunchMount, AirlaunchUnmount };
- public override string Name => KSP.Localization.Localizer.Format("#rp0_LCOps_Type_" + RRType.ToString())
- ;
+ public override string Name => KSP.Localization.Localizer.Format("#rp0_LCOps_Type_" + RRType.ToString());
+
[Persistent]
public string launchPadID = "LaunchPad";
[Persistent]
diff --git a/Source/RP0/SpaceCenter/Projects/VesselRepairProject.cs b/Source/RP0/SpaceCenter/Projects/VesselRepairProject.cs
new file mode 100644
index 00000000000..5c7acce0b6b
--- /dev/null
+++ b/Source/RP0/SpaceCenter/Projects/VesselRepairProject.cs
@@ -0,0 +1,89 @@
+using RealFuels;
+
+namespace RP0
+{
+ public class VesselRepairProject : LCOpsProject
+ {
+ public override string Name => "Repair vessel";
+
+ [Persistent]
+ public string launchPadID = "LaunchPad";
+ [Persistent]
+ public string shipName;
+
+ public override TransactionReasonsRP0 TransactionReason => TransactionReasonsRP0.RocketRollout;
+
+ protected override TransactionReasonsRP0 transactionReasonTime => TransactionReasonsRP0.RateRollout;
+
+ public override ProjectType GetProjectType() => ProjectType.VesselRepair;
+
+ public VesselRepairProject() : base()
+ {
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public VesselRepairProject(Vessel vessel, string launchSite, LaunchComplex lc)
+ {
+ associatedID = vessel.id.ToString();
+ launchPadID = launchSite;
+ RP0Debug.Log("New VesselRepair at launchsite: " + launchPadID);
+ progress = 0;
+ _lc = lc;
+
+ mass = vessel.GetTotalMass();
+ shipName = vessel.vesselName;
+ try
+ {
+ var vp = new VesselProject(vessel, ProjectType.VAB);
+ isHumanRated = vp.humanRated;
+ BP = Formula.GetVesselRepairBP(vp);
+ vesselBP = vp.buildPoints;
+ }
+ catch
+ {
+ RP0Debug.Log("Error while determining BP for VesselRepair");
+ }
+ }
+
+ public bool ApplyRepairs()
+ {
+ Vessel v = FlightGlobals.FindVessel(AssociatedIdAsGuid);
+ if (v != null)
+ {
+ if (!v.loaded) return false;
+
+ v.ctrlState.mainThrottle = 0;
+ TFInterop.ResetAllFailures(v);
+ SpaceCenterManagement.Instance.DoingVesselRepair = true;
+
+ try
+ {
+ ResetIgnitionsOnVessel(v);
+ }
+ catch
+ {
+ // Might be using older RF version that is missing the ResetIgnitions method
+ }
+
+ return true;
+ }
+ else
+ {
+ RP0Debug.LogError($"Failed to find vessel {associatedID} to reset failures on");
+ return false;
+ }
+ }
+
+ private static void ResetIgnitionsOnVessel(Vessel v)
+ {
+ foreach (var merf in v.FindPartModulesImplementing())
+ {
+ merf.ResetIgnitions();
+ }
+ }
+ }
+}
diff --git a/Source/RP0/SpaceCenter/SCMEvents.cs b/Source/RP0/SpaceCenter/SCMEvents.cs
index a6f1dd49fe1..aafa4c103ba 100644
--- a/Source/RP0/SpaceCenter/SCMEvents.cs
+++ b/Source/RP0/SpaceCenter/SCMEvents.cs
@@ -2,12 +2,14 @@
using ROUtils.DataTypes;
using ToolbarControl_NS;
using ROUtils;
+using UnityEngine.SceneManagement;
namespace RP0
{
public class SCMEvents : HostedSingleton
{
new public static SCMEvents Instance { get; private set; }
+ public static bool SceneChangeInProgress { get; private set; }
public SCMEvents(SingletonHost host) : base(host)
{
@@ -71,6 +73,7 @@ public void SubscribeToEvents()
GameEvents.onGameStateLoad.Add(OnGameStateLoad);
GameEvents.OnPartPurchased.Add(OnPartPurchased);
GameEvents.Modifiers.OnCurrencyModified.Add(OnCurrenciesModified);
+ GameEvents.onFlightGlobalsRemoveVessel.Add(OnRemoveVessel);
// Flight
GameEvents.onVesselSituationChange.Add(VesselSituationChange);
@@ -81,7 +84,6 @@ public void SubscribeToEvents()
GameEvents.StageManager.OnGUIStageRemoved.Add(StageCountChangedEvent);
GameEvents.StageManager.OnGUIStageSequenceModified.Add(StagingOrderChangedEvent);
GameEvents.StageManager.OnPartUpdateStageability.Add(PartStageabilityChangedEvent);
- GameEvents.onEditorStarted.Add(OnEditorStarted);
// Space Center
GameEvents.OnKSCFacilityUpgraded.Add(FacilityUpgradedEvent);
@@ -100,11 +102,9 @@ public void SubscribeToEvents()
GameEvents.onGUIMissionControlDespawn.Add(ExitSCSubsceneAndShow);
GameEvents.onGUIRnDComplexDespawn.Add(ExitSCSubsceneAndShow);
GameEvents.onGUIKSPediaDespawn.Add(RestoreAllGUIs);
- }
- private void OnEditorStarted()
- {
- KCTUtilities.HandleEditorButton();
+ GameEvents.onGameSceneLoadRequested.Add(OnGameSceneLoadRequested);
+ SceneManager.sceneLoaded += OnSceneLoaded;
}
public void CreateEvents()
@@ -131,6 +131,20 @@ public void CreateEvents()
ApplyGlobalEffectiveCostMultiplier = new EventData, IEnumerable, Dictionary>("ApplyGlobalEffectiveCostMultiplier");
}
+ private void OnGameSceneLoadRequested(GameScenes data)
+ {
+ SceneChangeInProgress = true;
+ }
+
+ private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
+ {
+ if (mode != LoadSceneMode.Additive &&
+ HighLogic.GetLoadedGameSceneFromBuildIndex(scene.buildIndex) != GameScenes.LOADINGBUFFER)
+ {
+ SceneChangeInProgress = false;
+ }
+ }
+
public void HideAllGUIs()
{
KCT_GUI.BackupUIState();
@@ -203,6 +217,18 @@ private void OnCurrenciesModified(CurrencyModifierQuery query)
KCTUtilities.ProcessSciPointTotalChange(changeDelta);
}
+ private void OnRemoveVessel(Vessel v)
+ {
+ if (SceneChangeInProgress) return;
+
+ RP0Debug.Log($"OnRemoveVessel: {v.vesselName}");
+ VesselRepairProject r = SpaceCenterManagement.Instance.FindRepairForVessel(v);
+ if (r != null)
+ {
+ r.LC.VesselRepairs.Remove(r);
+ }
+ }
+
private void ShipModifiedEvent(ShipConstruct vessel)
{
SpaceCenterManagement.Instance.IsEditorRecalcuationRequired = true;
diff --git a/Source/RP0/SpaceCenter/SpaceCenterManagement.cs b/Source/RP0/SpaceCenter/SpaceCenterManagement.cs
index 702cf5d4035..694ef0bb0f2 100644
--- a/Source/RP0/SpaceCenter/SpaceCenterManagement.cs
+++ b/Source/RP0/SpaceCenter/SpaceCenterManagement.cs
@@ -144,6 +144,8 @@ public static void ClearVesselEditMode()
#region Fields
+ public bool DoingVesselRepair;
+
public bool MergingAvailable;
public List MergedVessels = new List();
@@ -755,7 +757,7 @@ private void PopUpVesselError(List errored)
for (int i = 0; i < currentLC.Recon_Rollout.Count; i++)
{
ReconRolloutProject rr = currentLC.Recon_Rollout[i];
- if (rr.associatedID == vp.shipID.ToString())
+ if (rr.AssociatedIdAsGuid == vp.shipID)
{
currentLC.Recon_Rollout.Remove(rr);
i--;
@@ -845,6 +847,20 @@ public LaunchComplex FindLCFromID(Guid guid)
return LC(guid);
}
+ public VesselRepairProject FindRepairForVessel(Vessel v)
+ {
+ foreach (var ksc in KSCs)
+ {
+ foreach (var lc in ksc.LaunchComplexes)
+ {
+ var r = lc.VesselRepairs.Find(r => r.AssociatedIdAsGuid == v.id);
+ if (r != null) return r;
+ }
+ }
+
+ return null;
+ }
+
#endregion
#region KSCSwitcher section
@@ -1152,7 +1168,7 @@ private void ProcessNewFlight()
FlightGlobals.ActiveVessel.vesselName = vp.shipName;
}
if (vesselLC == null) vesselLC = ActiveSC.ActiveLC;
- if (vesselLC.Recon_Rollout.FirstOrDefault(r => r.associatedID == vp.shipID.ToString()) is ReconRolloutProject rollout)
+ if (vesselLC.Recon_Rollout.FirstOrDefault(r => r.AssociatedIdAsGuid == vp.shipID) is ReconRolloutProject rollout)
vesselLC.Recon_Rollout.Remove(rollout);
LaunchedVessel = new VesselProject();
@@ -1631,13 +1647,24 @@ public void ProgressBuildTime(double UTDiff)
//Reset the associated launchpad id when rollback completes
Profiler.BeginSample("RP0ProgressBuildTime.ReconRollout.FindVPesselByID");
if (rr.RRType == ReconRolloutProject.RolloutReconType.Rollback && rr.IsComplete()
- && KCTUtilities.FindVPByID(rr.LC, new Guid(rr.associatedID)) is VesselProject vp)
+ && KCTUtilities.FindVPByID(rr.LC, rr.AssociatedIdAsGuid) is VesselProject vp)
{
vp.launchSiteIndex = -1;
}
Profiler.EndSample();
}
+ for (int i = currentLC.VesselRepairs.Count; i-- > 0;)
+ {
+ var vr = currentLC.VesselRepairs[i];
+ vr.IncrementProgress(UTDiff);
+ if (vr.IsComplete() && HighLogic.LoadedSceneIsFlight &&
+ vr.ApplyRepairs())
+ {
+ currentLC.VesselRepairs.Remove(vr);
+ }
+ }
+
currentLC.Recon_Rollout.RemoveAll(rr => rr.RRType != ReconRolloutProject.RolloutReconType.Rollout && rr.RRType != ReconRolloutProject.RolloutReconType.AirlaunchMount && rr.IsComplete());
}
@@ -1720,6 +1747,34 @@ private void DoNormalRecovery()
_recoverCallback.Invoke();
}
+ private void QueueRepairFailures()
+ {
+ KCT_Preset_General settings = PresetManager.Instance.ActivePreset.GeneralSettings;
+ if (settings.BuildTimes)
+ {
+ var dataModule = FlightGlobals.ActiveVessel.vesselModules.Find(vm => vm is KCTVesselTracker) as KCTVesselTracker;
+ if (dataModule != null && dataModule.Data.FacilityBuiltIn == EditorFacility.VAB)
+ {
+ string launchSite = FlightDriver.LaunchSiteName;
+ LaunchComplex lc = Instance.FindLCFromID(dataModule.Data.LCID);
+ if (lc != null)
+ {
+ if (lc.LCType == LaunchComplexType.Pad && lc.ActiveLPInstance != null
+ && (launchSite == "LaunchPad" || lc.LaunchPads.Find(p => p.name == launchSite) == null))
+ {
+ launchSite = lc.ActiveLPInstance.name;
+ }
+ var proj = new VesselRepairProject(FlightGlobals.ActiveVessel, launchSite, lc);
+ lc.VesselRepairs.Add(proj);
+ }
+ }
+ }
+ else
+ {
+ // Do immediately?
+ }
+ }
+
private void RecoveryChoiceTS()
{
if (!(_trackingStation != null && _trackingStation.SelectedVessel is Vessel selectedVessel))
@@ -1751,10 +1806,11 @@ private void RecoveryChoiceFlight()
return;
}
- bool isSPHAllowed = KCTUtilities.IsSphRecoveryAvailable(FlightGlobals.ActiveVessel);
- bool isVABAllowed = KCTUtilities.IsVabRecoveryAvailable(FlightGlobals.ActiveVessel);
+ Vessel v = FlightGlobals.ActiveVessel;
+ bool isSPHAllowed = KCTUtilities.IsSphRecoveryAvailable(v);
+ bool isVABAllowed = KCTUtilities.IsVabRecoveryAvailable(v);
var options = new List();
- if (!FlightGlobals.ActiveVessel.isEVA)
+ if (!v.isEVA)
{
string nodeTitle = ResearchAndDevelopment.GetTechnologyTitle(Database.SettingsSC.VABRecoveryTech);
string techLimitText = string.IsNullOrEmpty(nodeTitle) ? string.Empty :
@@ -1777,6 +1833,15 @@ private void RecoveryChoiceFlight()
{
tooltipText = "Vessel will be scrapped and the total value of recovered parts will be refunded."
});
+
+ if (TFInterop.HasSupportForReset && v.GetVesselBuiltAt() != EditorFacility.SPH &&
+ TFInterop.VesselHasFailedParts(v) && FindRepairForVessel(v) == null)
+ {
+ options.Add(new DialogGUIButtonWithTooltip("Repair failures", QueueRepairFailures)
+ {
+ tooltipText = "All failures will be repaired without having to leave the flight scene."
+ });
+ }
}
else
{
diff --git a/Source/RP0/UI/KCT/GUI_BuildList.cs b/Source/RP0/UI/KCT/GUI_BuildList.cs
index dc9a278a648..98d8e53dedc 100644
--- a/Source/RP0/UI/KCT/GUI_BuildList.cs
+++ b/Source/RP0/UI/KCT/GUI_BuildList.cs
@@ -27,7 +27,7 @@ public enum RenameType { None, Vessel, Pad, LaunchComplex };
private static GUIStyle _redText, _yellowText, _greenText, _blobText, _yellowButton, _redButton, _greenButton;
private static GUIContent _settingsTexture, _planeTexture, _rocketTexture, _techTexture, _constructTexture,
- _reconTexture, _rolloutTexture, _rollbackTexture, _airlaunchTexture, _recoveryTexture, _hangarTexture;
+ _reconTexture, _rolloutTexture, _rollbackTexture, _airlaunchTexture, _recoveryTexture, _hangarTexture, _repairTexture;
private const int _width1 = 120;
private const int _width2 = 100;
private const int _butW = 20;
@@ -114,6 +114,7 @@ public static void InitBuildListVars()
_rolloutTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_rollout16", false));
_settingsTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_settings16", false));
_techTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_tech16", false));
+ _repairTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_repair", false));
}
public static void DrawBuildListWindow(int windowID)
@@ -139,19 +140,19 @@ public static void DrawBuildListWindow(int windowID)
}
else if (reconRoll.RRType == ReconRolloutProject.RolloutReconType.Rollout)
{
- VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID.ToString() == reconRoll.associatedID);
+ VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID == reconRoll.AssociatedIdAsGuid);
txt = $"{associated.shipName} Rollout";
locTxt = reconRoll.launchPadID;
}
else if (reconRoll.RRType == ReconRolloutProject.RolloutReconType.Rollback)
{
- VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID.ToString() == reconRoll.associatedID);
+ VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID == reconRoll.AssociatedIdAsGuid);
txt = $"{associated.shipName} Rollback";
locTxt = reconRoll.launchPadID;
}
else if (reconRoll.RRType == ReconRolloutProject.RolloutReconType.Recovery)
{
- VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID.ToString() == reconRoll.associatedID);
+ VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID == reconRoll.AssociatedIdAsGuid);
txt = $"{associated.shipName} Recovery";
locTxt = associated.LC.Name;
}
@@ -237,12 +238,12 @@ public static void DrawBuildListWindow(int windowID)
}
else if (reconRoll.RRType == ReconRolloutProject.RolloutReconType.Rollout)
{
- VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID.ToString() == reconRoll.associatedID);
+ VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID == reconRoll.AssociatedIdAsGuid);
txt += $"{associated.shipName} rollout at {reconRoll.launchPadID}";
}
else if (reconRoll.RRType == ReconRolloutProject.RolloutReconType.Rollback)
{
- VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID.ToString() == reconRoll.associatedID);
+ VesselProject associated = reconRoll.LC.Warehouse.FirstOrDefault(vp => vp.shipID == reconRoll.AssociatedIdAsGuid);
txt += $"{associated.shipName} rollback at {reconRoll.launchPadID}";
}
else
@@ -631,6 +632,7 @@ private static void RenderCombinedList()
_allItems.Add(b);
}
_allItems.AddRange(l.Recon_Rollout);
+ _allItems.AddRange(l.VesselRepairs);
}
accTime = 0d;
foreach (var c in k.Constructions)
@@ -689,6 +691,10 @@ private static void RenderCombinedList()
else
GUILayout.Label(r.GetItemName());
}
+ else if (t is VesselRepairProject)
+ {
+ GUILayout.Label(t.GetItemName());
+ }
else if (t is VesselProject b)
GUILayout.Label($"{b.LC.Name}: {b.GetItemName()}");
else if (t is ConstructionProject constr)
@@ -822,6 +828,9 @@ private static GUIContent GetTypeIcon(ISpaceCenterProject b)
case ProjectType.TechNode:
return _techTexture;
+
+ case ProjectType.VesselRepair:
+ return _repairTexture;
}
return _constructTexture;
@@ -841,7 +850,10 @@ private static void RenderBuildList()
_scrollPos = GUILayout.BeginScrollView(_scrollPos, GUILayout.Height(375));
if (activeLC.LCType == LaunchComplexType.Pad)
+ {
+ RenderRepairs();
RenderRollouts();
+ }
RenderVesselsBeingBuilt(activeLC);
RenderWarehouse();
@@ -867,14 +879,47 @@ private static void RenderRollouts()
{
GUILayout.BeginHorizontal();
double tLeft = reconditioning.GetTimeLeft();
- if (!HighLogic.LoadedSceneIsEditor && reconditioning.GetBuildRate() > 0 && GUILayout.Button(new GUIContent("Warp To", $"√ Gain/Loss:\n{SpaceCenterManagement.Instance.GetBudgetDelta(tLeft):N0}"), GUILayout.Width((_butW + 4) * 3)))
+ if (!HighLogic.LoadedSceneIsEditor && reconditioning.GetBuildRate() > 0 &&
+ GUILayout.Button(new GUIContent("Warp To", $"√ Gain/Loss:\n{SpaceCenterManagement.Instance.GetBudgetDelta(tLeft):N0}"), GUILayout.Width((_butW + 4) * 3)))
{
KCTWarpController.Create(reconditioning);
}
DrawTypeIcon(reconditioning);
GUILayout.Label($"Reconditioning: {reconditioning.launchPadID}");
GUILayout.Label($"{reconditioning.GetFractionComplete():P2}", GetLabelRightAlignStyle(), GUILayout.Width(_width1 / 2));
- GUILayout.Label(RP0DTUtils.GetColonFormattedTimeWithTooltip(tLeft, "recon"+reconditioning.launchPadID), GetLabelRightAlignStyle(), GUILayout.Width(_width2));
+ GUILayout.Label(RP0DTUtils.GetColonFormattedTimeWithTooltip(tLeft, "recon" + reconditioning.launchPadID), GetLabelRightAlignStyle(), GUILayout.Width(_width2));
+
+ GUILayout.EndHorizontal();
+ }
+ }
+
+ private static void RenderRepairs()
+ {
+ LaunchComplex activeLC = SpaceCenterManagement.EditorShipEditingMode ? SpaceCenterManagement.Instance.EditedVessel.LC : SpaceCenterManagement.Instance.ActiveSC.ActiveLC;
+ foreach (VesselRepairProject repair in activeLC.VesselRepairs)
+ {
+ GUILayout.BeginHorizontal();
+ double tLeft = repair.GetTimeLeft();
+ if (!HighLogic.LoadedSceneIsEditor && repair.GetBuildRate() > 0 &&
+ GUILayout.Button(new GUIContent("Warp To", $"√ Gain/Loss:\n{SpaceCenterManagement.Instance.GetBudgetDelta(tLeft):N0}"), GUILayout.Width((_butW + 4) * 3)))
+ {
+ KCTWarpController.Create(repair);
+ }
+
+ if (GUILayout.Button("X", GUILayout.Width(_butW)))
+ {
+ DialogGUIBase[] options = new DialogGUIBase[2];
+ options[0] = new DialogGUIButton("Yes", () => activeLC.VesselRepairs.Remove(repair));
+ options[1] = new DialogGUIButton("No", () => { });
+ MultiOptionDialog diag = new MultiOptionDialog("scrapVesselPopup", $"Are you sure you want to cancel this repair?",
+ "Cancel Repair", null, options: options);
+ PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), diag, false, HighLogic.UISkin).HideGUIsWhilePopup();
+ }
+
+ DrawTypeIcon(repair);
+ GUILayout.Label($"Repair: {repair.shipName}");
+ GUILayout.Label($"{repair.GetFractionComplete():P2}", GetLabelRightAlignStyle(), GUILayout.Width(_width1 / 2));
+ GUILayout.Label(RP0DTUtils.GetColonFormattedTimeWithTooltip(tLeft, "repair" + repair.associatedID), GetLabelRightAlignStyle(), GUILayout.Width(_width2));
GUILayout.EndHorizontal();
}
diff --git a/Source/RP0/Utilities/Formula.cs b/Source/RP0/Utilities/Formula.cs
index 2f6ef2a3065..4f0bf86d8ca 100644
--- a/Source/RP0/Utilities/Formula.cs
+++ b/Source/RP0/Utilities/Formula.cs
@@ -163,6 +163,11 @@ public static double GetReconditioningBP(VesselProject vessel)
return vessel.buildPoints * 0.01d + Math.Max(1, vessel.GetTotalMass() - 20d) * 2000d;
}
+ public static double GetVesselRepairBP(VesselProject vessel)
+ {
+ return GetRolloutBP(vessel) / 7.5;
+ }
+
public static double GetRecoveryBPSPH(VesselProject vessel)
{
double costDeltaHighPow;
diff --git a/Source/RP0/Utilities/KCTUtilities.cs b/Source/RP0/Utilities/KCTUtilities.cs
index 1b551882df3..435fa569fef 100644
--- a/Source/RP0/Utilities/KCTUtilities.cs
+++ b/Source/RP0/Utilities/KCTUtilities.cs
@@ -667,7 +667,7 @@ public static ISpaceCenterProject GetNextThingToFinish()
continue;
foreach (ISpaceCenterProject vp in LC.BuildList)
_checkTime(vp, ref shortestTime, ref thing);
- foreach (ISpaceCenterProject rr in LC.Recon_Rollout)
+ foreach (ISpaceCenterProject rr in LC.GetAllLCOps())
_checkTime(rr, ref shortestTime, ref thing);
}
foreach (ISpaceCenterProject ub in KSC.Constructions)