diff --git a/CachedEngineState.cs b/CachedEngineState.cs new file mode 100644 index 0000000..47b4354 --- /dev/null +++ b/CachedEngineState.cs @@ -0,0 +1,33 @@ +namespace TestFlight +{ + public class CachedEngineState : IConfigNode + { + [Persistent] public bool allowShutdown; + [Persistent] public bool allowRestart; + [Persistent] public int numIgnitions; + + public CachedEngineState() { } + + public CachedEngineState(ConfigNode node) + { + Load(node); + } + + public CachedEngineState(EngineModuleWrapper engine) + { + allowShutdown = engine.allowShutdown; + allowRestart = engine.allowRestart; + numIgnitions = engine.GetIgnitionCount(); + } + + public void Load(ConfigNode node) + { + ConfigNode.LoadObjectFromConfig(this, node); + } + + public void Save(ConfigNode node) + { + ConfigNode.CreateConfigFromObject(this, node); + } + } +} diff --git a/TestFlight.csproj b/TestFlight.csproj index 2888c3b..95eda4d 100644 --- a/TestFlight.csproj +++ b/TestFlight.csproj @@ -67,6 +67,7 @@ + diff --git a/TestFlightAPI/TestFlightAPI/EngineModuleWrapper.cs b/TestFlightAPI/TestFlightAPI/EngineModuleWrapper.cs index 091f459..92801be 100644 --- a/TestFlightAPI/TestFlightAPI/EngineModuleWrapper.cs +++ b/TestFlightAPI/TestFlightAPI/EngineModuleWrapper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using KSP.Localization; using UnityEngine; using TestFlightAPI; @@ -107,6 +108,23 @@ public bool allowShutdown } } + public bool allowRestart + { + get + { + if (engineType == EngineModuleType.UNKNOWN) + return false; + + return moduleEngine.allowRestart; + } + set + { + if (engineType == EngineModuleType.UNKNOWN) + return; + moduleEngine.allowRestart = value; + } + } + public bool throttleLocked { get @@ -332,7 +350,7 @@ public void DisableRestart() return; // Need to disable this to prevent other mods from restarting the engine. - moduleEngine.allowRestart = false; + allowRestart = false; // For some reason, need to disable GUI as well Events["Activate"].active = false; @@ -341,6 +359,12 @@ public void DisableRestart() Events["Shutdown"].guiActive = false; } + public void ResetStatus() + { + Status = Localizer.Format("#autoLOC_219034"); + StatusL2 = string.Empty; + } + // Reduce fuel flow public void SetFuelFlowMult(float multiplier) { diff --git a/TestFlightAPI/TestFlightAPI/TestFlightAPI.cs b/TestFlightAPI/TestFlightAPI/TestFlightAPI.cs index e27fdb9..1c034f0 100644 --- a/TestFlightAPI/TestFlightAPI/TestFlightAPI.cs +++ b/TestFlightAPI/TestFlightAPI/TestFlightAPI.cs @@ -720,7 +720,13 @@ string Configuration /// /// The current burn time for scope or 0 if this module does not track burn time. float GetScopedRunTime(RatingScope ratingScope); - + + /// + /// Sets the current burn time for the given scope. + /// Does nothing if this module does not track burn time. + /// + void SetScopedRunTime(RatingScope ratingScope, float time); + /// /// Should return a string if the module wants to report any information to the user in the TestFlight Editor window. /// @@ -959,6 +965,8 @@ bool DebugEnabled float GetRunTime(RatingScope ratingScope); + void ResetRunTime(); + /// /// Called whenever an Interop value is added, changed, or removed to allow the modules on the part to update to the proper config /// diff --git a/TestFlightAPI/TestFlightAPI/TestFlightReliability.cs b/TestFlightAPI/TestFlightAPI/TestFlightReliability.cs index 0f0dfd2..cb1c263 100644 --- a/TestFlightAPI/TestFlightAPI/TestFlightReliability.cs +++ b/TestFlightAPI/TestFlightAPI/TestFlightReliability.cs @@ -256,6 +256,10 @@ public virtual float GetScopedRunTime(RatingScope ratingScope) { return 0f; } + + public virtual void SetScopedRunTime(RatingScope ratingScope, float time) + { + } } } diff --git a/TestFlightCore/TestFlightCore/TestFlightCore.cs b/TestFlightCore/TestFlightCore/TestFlightCore.cs index 3ed4468..8d6e7a9 100644 --- a/TestFlightCore/TestFlightCore/TestFlightCore.cs +++ b/TestFlightCore/TestFlightCore/TestFlightCore.cs @@ -228,6 +228,7 @@ internal void Log(string message) { TestFlightUtil.Log($"TestFlightCore({Alias}[{Configuration}]): {message}", true); } + private void CalculateMaximumData() { if (maxData > 0f) @@ -244,6 +245,7 @@ private void CalculateMaximumData() } } } + // Retrieves the maximum amount of data a part can gain public float GetMaximumData() { @@ -269,6 +271,7 @@ public double GetBaseFailureRate() baseFailureRate = Math.Max(totalBFR, TestFlightUtil.MIN_FAILURE_RATE); return baseFailureRate; } + // Get the Reliability Curve for the part public FloatCurve GetBaseReliabilityCurve() { @@ -282,6 +285,7 @@ public FloatCurve GetBaseReliabilityCurve() return null; } + public float GetRunTime(RatingScope ratingScope) { float burnTime = 0f; @@ -292,6 +296,18 @@ public float GetRunTime(RatingScope ratingScope) return burnTime; } + + public void ResetRunTime() + { + List reliabilityModules = TestFlightUtil.GetReliabilityModules(this.part, Alias); + + foreach (ITestFlightReliability rm in reliabilityModules) + { + rm.SetScopedRunTime(RatingScope.Continuous, 0); + rm.SetScopedRunTime(RatingScope.Cumulative, 0); + } + } + // Get the momentary (IE current dynamic) failure rates (Can vary per reliability/failure modules) // These methods will let you get a list of all momentary rates or you can get the best (lowest chance of failure)/worst (highest chance of failure) rates public MomentaryFailureRate GetWorstMomentaryFailureRate() @@ -324,6 +340,7 @@ public MomentaryFailureRate GetWorstMomentaryFailureRate() return mfrIndex > -1 ? momentaryFailureRates[mfrIndex] : new MomentaryFailureRate(); } + public MomentaryFailureRate GetBestMomentaryFailureRate() { MomentaryFailureRate bestMFR = new MomentaryFailureRate @@ -339,14 +356,17 @@ public MomentaryFailureRate GetBestMomentaryFailureRate() return bestMFR; } + public List GetAllMomentaryFailureRates() { return momentaryFailureRates; } + public double GetMomentaryFailureRateForTrigger(String trigger) { return GetMomentaryFailureRate(trigger).failureRate; } + // The momentary failure rate is tracked per named "trigger" which allows multiple Reliability or FailureTrigger modules to cooperate // Returns the total modified failure rate back to the caller for convenience // IMPORTANT: For performance reasons a module should only set its Momentary Modifier WHEN IT CHANGES. The core will cache the value. @@ -365,6 +385,7 @@ internal MomentaryFailureModifier GetMomentaryFailureModifier(string trigger, st return new MomentaryFailureModifier(); } + internal MomentaryFailureRate GetMomentaryFailureRate(string trigger) { trigger = trigger.Trim(); @@ -404,6 +425,7 @@ public double SetTriggerMomentaryFailureModifier(string trigger, double multipli return CalculateMomentaryFailureRate(trigger); } } + internal double CalculateMomentaryFailureRate(String trigger) { trigger = trigger.Trim(); @@ -433,6 +455,7 @@ internal double CalculateMomentaryFailureRate(String trigger) } return momentaryRate; } + // simply converts the failure rate into a MTBF string. Convenience method // Returned string will be of the format "123 units" // units should be one of: @@ -441,10 +464,12 @@ public String FailureRateToMTBFString(double failureRate, TestFlightUtil.MTBFUni { return FailureRateToMTBFString(failureRate, units, false, int.MaxValue); } + public String FailureRateToMTBFString(double failureRate, TestFlightUtil.MTBFUnits units, int maximum) { return FailureRateToMTBFString(failureRate, units, false, maximum); } + // Short version of MTBFString uses a single letter to denote (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears // The returned string will be of the format "12.00s" or "0.20d" public String FailureRateToMTBFString(double failureRate, TestFlightUtil.MTBFUnits units, bool shortForm) @@ -475,6 +500,7 @@ public float GetFlightData() { return Mathf.Min(maxData, currentFlightData + researchData + transferData); } + public float GetInitialFlightData() { if (initialFlightData > maxData) @@ -482,6 +508,7 @@ public float GetInitialFlightData() return initialFlightData; } + public float GetFlightTime() { if (TestFlightManagerScenario.Instance != null) @@ -492,6 +519,7 @@ public float GetFlightTime() else return 0f; } + public float GetMaximumFlightData() { return maxData; @@ -504,12 +532,14 @@ public float SetDataRateLimit(float limit) dataRateLimiter = limit; return oldRate; } + public float SetDataCap(float cap) { float oldCap = dataCap; dataCap = cap; return oldCap; } + // Set the FlightData for FlightTime or the part - this is an absolute set and replaces the previous FlightData. // This will NOT apply any global TestFlight modifiers! // Be sure these are the methods you want to use. 99% of the time you want to use ModifyFlightData instead @@ -520,6 +550,7 @@ public void SetFlightData(float data) currentFlightData = data; } + public void SetFlightTime(float flightTime) { if (TestFlightManagerScenario.Instance != null) @@ -632,10 +663,12 @@ internal float ApplyFlightDataMultiplier(float baseData) float mult = TestFlightManagerScenario.Instance == null ? 1 : TestFlightManagerScenario.Instance.userSettings.flightDataMultiplier; return baseData * mult; } + public ITestFlightFailure TriggerFailure() { return TriggerFailure("any"); } + // Cause a failure to occur, either a random failure or a specific one // If fallbackToRandom is true, then if the specified failure can't be found or can't be triggered, a random failure will be triggered instead // Returns the triggered failure module, or null if none @@ -678,10 +711,12 @@ public ITestFlightFailure TriggerFailure(string severity) Debug.LogError($"Failed to fail! {failureModules.Count} options for severity: {severity}, chose {chosenWeight} from {totalWeight}?"); return null; } + public ITestFlightFailure TriggerNamedFailure(String failureModuleName) { return TriggerNamedFailure(failureModuleName, false); } + public ITestFlightFailure TriggerNamedFailure(String failureModuleName, bool fallbackToRandom) { failureModuleName = failureModuleName.ToLower().Trim(); @@ -697,6 +732,7 @@ public ITestFlightFailure TriggerNamedFailure(String failureModuleName, bool fal fm = TriggerFailure(); return fm; } + // Returns a list of all available failures on the part public List GetAvailableFailures() { @@ -705,12 +741,14 @@ public List GetAvailableFailures() failureModulesString.Add((fm as PartModule).moduleName); return failureModulesString; } + // Enable a failure so it can be triggered (this is the default state) public void EnableFailure(String failureModuleName) { failureModuleName = failureModuleName.ToLowerInvariant().Trim(); disabledFailures.Remove(failureModuleName); } + // Disable a failure so it can not be triggered public void DisableFailure(String failureModuleName) { @@ -718,6 +756,7 @@ public void DisableFailure(String failureModuleName) if (!disabledFailures.Contains(failureModuleName)) disabledFailures.Add(failureModuleName); } + // Returns the Operational Time or the time, in MET, since the last time the part was fully functional. // If a part is currently in a failure state, return will be -1 and the part should not fail again // This counts from mission start time until a failure, at which point it is reset to the time the @@ -742,10 +781,19 @@ private void OnEngineActiveChange(ModuleEngines data) OnFlightStart(); } + private void OnVesselSituationChange(GameEvents.HostedFromToAction ev) + { + if (ev.from == Vessel.Situations.PRELAUNCH && ev.host == FlightGlobals.ActiveVessel) + { + OnFlightStart(); + } + } + private void OnFlightStart() { GameEvents.onStageActivate.Remove(OnStageActivate); GameEvents.onEngineActiveChange.Remove(OnEngineActiveChange); + GameEvents.onVesselSituationChange.Remove(OnVesselSituationChange); firstStaged = true; missionStartTime = Planetarium.GetUniversalTime(); } @@ -800,6 +848,7 @@ public IEnumerator InitializeData(float du=0) InitializeFlightData(data); } } + public override void Start() { if (!TestFlightEnabled) @@ -822,13 +871,22 @@ public override void Start() if (HighLogic.LoadedSceneIsFlight) { + PollExistingFailuresOnStart(); + GameEvents.onCrewTransferred.Add(OnCrewChange); _OnCrewChange(); firstStaged = vessel.situation != Vessel.Situations.PRELAUNCH; - if (vessel.situation == Vessel.Situations.PRELAUNCH) + + if (!firstStaged && part.isEngine()) + { + firstStaged = part.FindModulesImplementing().Find(e => e.staged) != null; + } + + if (!firstStaged) { GameEvents.onStageActivate.Add(OnStageActivate); GameEvents.onEngineActiveChange.Add(OnEngineActiveChange); + GameEvents.onVesselSituationChange.Add(OnVesselSituationChange); } else missionStartTime = Planetarium.GetUniversalTime(); @@ -841,6 +899,7 @@ public override void OnDestroy() GameEvents.onCrewTransferred.Remove(OnCrewChange); GameEvents.onStageActivate.Remove(OnStageActivate); GameEvents.onEngineActiveChange.Remove(OnEngineActiveChange); + GameEvents.onVesselSituationChange.Remove(OnVesselSituationChange); } public override void OnAwake() @@ -852,16 +911,6 @@ public override void OnAwake() { configs = pm.configs; } - - // poll failure modules for any existing failures - foreach (ITestFlightFailure failure in TestFlightUtil.GetFailureModules(this.part, Alias)) - { - if (failure.Failed) - { - failures.Add(failure); - hasMajorFailure |= failure.GetFailureDetails().severity.ToLowerInvariant() == "major"; - } - } } private TestFlightCore GetCoreFromPrefab() @@ -982,6 +1031,7 @@ public float ForceRepair(ITestFlightFailure failure) return 0; failure.ForceRepair(); + failures.Remove(failure); // update our major failure flag in case this repair changes things hasMajorFailure = HasMajorFailure(); @@ -995,7 +1045,20 @@ private bool HasMajorFailure() return true; return false; } - + + private void PollExistingFailuresOnStart() + { + List m = TestFlightUtil.GetFailureModules(this.part, Alias); + foreach (ITestFlightFailure failure in m) + { + if (failure.Failed) + { + failures.Add(failure); + hasMajorFailure |= failure.GetFailureDetails().severity.ToLowerInvariant() == "major"; + } + } + } + public void HighlightPart(bool doHighlight) { // Color highlightColor; diff --git a/TestFlightCore/TestFlightCore/TestFlightInterface.cs b/TestFlightCore/TestFlightCore/TestFlightInterface.cs index 3ebac6b..fe49389 100644 --- a/TestFlightCore/TestFlightCore/TestFlightInterface.cs +++ b/TestFlightCore/TestFlightCore/TestFlightInterface.cs @@ -78,13 +78,61 @@ public static bool TestFlightAvailable(Part part) else return true; } + + public static void ResetAllFailuresOnVessel(Vessel vessel) + { + foreach (Part part in vessel.parts) + { + ITestFlightCore core = GetCore(part); + if (core == null) continue; + + List failures = core.GetActiveFailures(); + for (int i = failures.Count - 1; i >= 0; i--) + { + core.ForceRepair(failures[i]); + } + } + } + + public static void ResetAllRunTimesOnVessel(Vessel vessel) + { + foreach (Part part in vessel.parts) + { + ITestFlightCore core = GetCore(part); + if (core == null) continue; + + core.ResetRunTime(); + } + } + /// - /// 0 = OK, 1 = Minor Failure, 2 = Failure, 3 = Major Failure, -1 = Could not find TestFlight Core on Part + /// 0 = OK, 1 = Has failure, -1 = Could not find TestFlight Core on Part + /// + /// The part status. + public static int GetVesselStatus(Vessel vessel) + { + int retVal = -1; + foreach (Part part in vessel.parts) + { + int statusForPart; + ITestFlightCore core = GetCore(part); + if (core == null) + statusForPart = - 1; + else + statusForPart = core.GetPartStatus(); + retVal = Math.Max(retVal, statusForPart); + } + + return retVal; + } + + /// + /// 0 = OK, 1 = Has failure, -1 = Could not find TestFlight Core on Part /// /// The part status. public static int GetPartStatus(Part part, string alias) { - ITestFlightCore core = TestFlightInterface.GetCore(part, alias); + ITestFlightCore core = GetCore(part, alias); if (core == null) return -1; @@ -346,6 +394,11 @@ public static bool IsPartOperating(Part part, string alias) } // Methods for accessing the TestFlight modules on a given part + // Get the active Core Module - can only ever be one. + public static ITestFlightCore GetCore(Part part) + { + return TestFlightUtil.GetCore(part); + } // Get the active Core Modules that are bound to a given alias public static ITestFlightCore GetCore(Part part, string alias) { diff --git a/TestFlightFailure_Engine.cs b/TestFlightFailure_Engine.cs index def6983..dcbe554 100644 --- a/TestFlightFailure_Engine.cs +++ b/TestFlightFailure_Engine.cs @@ -20,6 +20,9 @@ protected class EngineHandler protected List engines = new List(); protected ITestFlightCore core = null; + protected Dictionary engineStates; + + public bool IsMajor => string.Equals(severity, "major", StringComparison.OrdinalIgnoreCase); public new bool TestFlightEnabled { @@ -45,6 +48,43 @@ public override void OnStart(StartState state) Startup(); } + public override void OnLoad(ConfigNode node) + { + base.OnLoad(node); + + ConfigNode[] cNodes = node.GetNodes("ENGINESTATE"); + if (cNodes.Length > 0 && engineStates == null) + engineStates = new Dictionary(); + + foreach (ConfigNode cNode in cNodes) + { + int id = 0; + if (!cNode.TryGetValue("id", ref id)) + { + Debug.LogError("[TestFlight] Invalid ENGINESTATE data in OnLoad:" + cNode); + continue; + } + var state = new CachedEngineState(cNode); + engineStates.Add(id, state); + } + } + + public override void OnSave(ConfigNode node) + { + base.OnSave(node); + + if (engineStates?.Count > 0) + { + foreach (KeyValuePair kvp in engineStates) + { + var cn = new ConfigNode("ENGINESTATE"); + kvp.Value.Save(cn); + cn.AddValue("id", kvp.Key); + node.AddNode(cn); + } + } + } + private void AddEngine(EngineModuleWrapper engine) { var engineHandler = new EngineHandler(); @@ -114,6 +154,15 @@ public override void SetActiveConfig(string alias) currentConfig.TryGetValue("engineID", ref engineID); } + public override float DoRepair() + { + foreach (EngineHandler engine in engines) + { + engine.engine.ResetStatus(); + } + return base.DoRepair(); + } + private readonly WaitForFixedUpdate _wait = new WaitForFixedUpdate(); public IEnumerator UpdateEngineStatus() { diff --git a/TestFlightFailure_IgnitionFail.cs b/TestFlightFailure_IgnitionFail.cs index 01e8a1f..8d1babb 100644 --- a/TestFlightFailure_IgnitionFail.cs +++ b/TestFlightFailure_IgnitionFail.cs @@ -127,7 +127,23 @@ public List RestartCurveDescription() public override void OnStart(StartState state) { base.OnStart(state); + verboseDebugging = core.DebugEnabled; + + if (Failed && IsMajor) + { + for (int i = 0; i < engines.Count; i++) + { + EngineHandler engine = engines[i]; + CachedEngineState engineState; + // Ignition failure can only trigger on one engine PM out of many + if (engineStates?.TryGetValue(i, out engineState) ?? false) + { + engine.engine.DisableRestart(); + } + } + } + TestFlightGameSettings tfSettings = HighLogic.CurrentGame.Parameters.CustomParams(); preLaunchFailures = tfSettings.preLaunchFailures; dynPressurePenalties = tfSettings.dynPressurePenalties; @@ -324,13 +340,20 @@ public override void DoFailure() core.LogCareerFailure(vessel, failureTitle); } + if (engineStates == null) + engineStates = new Dictionary(); + engineStates.Clear(); + Log($"IgnitionFail: Failing {engines.Count} engine(s)"); for (int i = 0; i < engines.Count; i++) { EngineHandler engine = engines[i]; if (engine.failEngine) { - if (severity.ToLowerInvariant() == "major") + var engineState = new CachedEngineState(engine.engine); + engineStates.Add(i, engineState); + + if (IsMajor) { engine.engine.DisableRestart(); } @@ -339,28 +362,38 @@ public override void DoFailure() if (restoreIgnitionCharge || this.vessel.situation == Vessel.Situations.PRELAUNCH) RestoreIgnitor(); - engines[i].failEngine = false; + engine.failEngine = false; } } } public override float DoRepair() { - base.DoRepair(); for (int i = 0; i < engines.Count; i++) { EngineHandler engine = engines[i]; + // Prevent auto-ignition on repair + engine.engine.Shutdown(); + engine.engine.Events["Activate"].active = true; + engine.engine.Events["Activate"].guiActive = true; + engine.engine.Events["Shutdown"].guiActive = true; + engine.engine.allowRestart = true; + + CachedEngineState engineState = null; + if (engineStates?.TryGetValue(i, out engineState) ?? false) { - // Prevent auto-ignition on repair - engine.engine.Shutdown(); - engine.engine.Events["Activate"].active = true; - engine.engine.Events["Activate"].guiActive = true; - engine.engine.Events["Shutdown"].guiActive = true; - if (restoreIgnitionCharge || this.vessel.situation == Vessel.Situations.PRELAUNCH) - RestoreIgnitor(); - engines[i].failEngine = false; + engine.engine.allowShutdown = engineState.allowShutdown; + engine.engine.allowRestart = engineState.allowRestart; + engine.engine.SetIgnitionCount(engineState.numIgnitions); } + + if (restoreIgnitionCharge || this.vessel.situation == Vessel.Situations.PRELAUNCH) + RestoreIgnitor(); + engine.failEngine = false; + engine.engine.failed = false; + engine.engine.failMessage = ""; } + base.DoRepair(); return 0; } diff --git a/TestFlightFailure_ShutdownEngine.cs b/TestFlightFailure_ShutdownEngine.cs index 2f99792..a9bf077 100644 --- a/TestFlightFailure_ShutdownEngine.cs +++ b/TestFlightFailure_ShutdownEngine.cs @@ -4,13 +4,20 @@ namespace TestFlight { public class TestFlightFailure_ShutdownEngine : TestFlightFailure_Engine { - protected struct CachedEngineState + public override void OnStart(StartState state) { - public bool allowShutdown; - public int numIgnitions; - } + base.OnStart(state); - Dictionary engineStates; + if (Failed && IsMajor) + { + foreach (EngineHandler engine in engines) + { + engine.engine.DisableRestart(); + engine.engine.failed = true; + engine.engine.failMessage = failureTitle; + } + } + } /// /// Triggers the failure controlled by the failure module @@ -23,18 +30,15 @@ public override void DoFailure() engineStates.Clear(); foreach (EngineHandler engine in engines) { - int id = engine.engine.Module.GetInstanceID(); - CachedEngineState engineState = new CachedEngineState(); - engineState.allowShutdown = engine.engine.allowShutdown; - engineState.numIgnitions = engine.engine.GetIgnitionCount(); + int id = engines.IndexOf(engine); + var engineState = new CachedEngineState(engine.engine); engine.engine.Shutdown(); var numIgnitionsToRemove = 1; - if (severity.ToLowerInvariant() == "major") + if (IsMajor) { numIgnitionsToRemove = -1; engine.engine.DisableRestart(); - engine.engine.failed = true; engine.engine.failMessage = failureTitle; } @@ -45,24 +49,26 @@ public override void DoFailure() public override float DoRepair() { - base.DoRepair(); // for each engine restore it foreach (EngineHandler engine in engines) { - int id = engine.engine.Module.GetInstanceID(); - if (engineStates.ContainsKey(id)) + int id = engines.IndexOf(engine); + CachedEngineState engineState = null; + if (engineStates?.TryGetValue(id, out engineState) ?? false) { engine.engine.enabled = true; engine.engine.Events["Activate"].active = true; engine.engine.Events["Activate"].guiActive = true; engine.engine.Events["Shutdown"].guiActive = true; - engine.engine.allowShutdown = engineStates[id].allowShutdown; - engine.engine.SetIgnitionCount(engineStates[id].numIgnitions); + engine.engine.allowShutdown = engineState.allowShutdown; + engine.engine.allowRestart = engineState.allowRestart; + engine.engine.SetIgnitionCount(engineState.numIgnitions); engine.engine.failed = false; engine.engine.failMessage = ""; } } engineStates.Clear(); + base.DoRepair(); return 0; } } diff --git a/TestFlightReliability_EngineCycle.cs b/TestFlightReliability_EngineCycle.cs index f6f40d5..7a8d4c5 100644 --- a/TestFlightReliability_EngineCycle.cs +++ b/TestFlightReliability_EngineCycle.cs @@ -378,6 +378,21 @@ public override float GetScopedRunTime(RatingScope ratingScope) } } + public override void SetScopedRunTime(RatingScope ratingScope, float time) + { + switch (ratingScope) + { + case RatingScope.Cumulative: + engineOperatingTime = time; + break; + case RatingScope.Continuous: + currentRunTime = time; + break; + default: + break; + } + } + public override void OnAwake() { base.OnAwake();