/// <summary> /// Resets the failure state and age tracker. /// This must be called only at the beginning of the flight to initialize the age tracking. /// Put your reset logic in DI_Reset() /// </summary> protected void Reset() { Debug.Log("Reset(), HasInitted: " + HasInitted.ToString()); try { this.FailureLog("Resetting"); float now = DangIt.Now(); #region Internal state this.Age = 0; this.TimeOfLastReset = now; this.LastFixedUpdate = now; this.TimeOfLastInspection = float.NegativeInfinity; this.CurrentMTBF = this.MTBF * HighLogic.CurrentGame.Parameters.CustomParams <DangItCustomParams1>().MTBF_Multiplier; this.LifeTimeSecs = this.LifeTime * HighLogic.CurrentGame.Parameters.CustomParams <DangItCustomParams1>().Lifetime_Multiplier * 3600f; this.HasFailed = false; #endregion // Run the custom reset of the subclasses this.DI_Reset(); this.HasInitted = true; } catch (Exception e) { OnError(e); } }
public void Inspect() { StringBuilder sb = new StringBuilder(); List <FailureModule> failModules = part.Modules.OfType <FailureModule>().ToList(); // The part doesn't have any failure module: // instead of a black message, return a placeholder if (failModules.Count == 0) { sb.AppendLine("This part seems to be as good as new"); } else { foreach (FailureModule fm in failModules) { fm.TimeOfLastInspection = DangIt.Now(); // set the time of inspection so that the module gains the inspection bonus sb.AppendLine(fm.ScreenName + ":"); sb.AppendLine(fm.InspectionMessage()); sb.AppendLine(""); } } DangIt.PostMessage("Inspection results", sb.ToString(), MessageSystemButton.MessageButtonColor.BLUE, MessageSystemButton.ButtonIcons.MESSAGE, overrideMute: true); }
/// <summary> /// Module re-start logic. OnStart will be called usually once for each scene, editor included. /// Put your custom start logic in DI_Start(): if you need to act on other part's /// variable, this is the place to do it, not DI_Reset() /// </summary> public override void OnStart(PartModule.StartState state) { Logger.Info("FailureModule.OnStart"); try { if (HighLogic.LoadedSceneIsFlight) // nothing to do in editor { this.FailureLog("Starting in flight: last reset " + TimeOfLastReset + ", now " + DangIt.Now()); if (!DangIt.Instance.CurrentSettings.EnabledForSave) { //Disable if we've disabled DangIt foreach (var e in this.Events) { e.guiActive = false; } } #region Fail and repair events this.Events["Fail"].guiName = this.FailGuiName; this.Events["EvaRepair"].guiName = this.EvaRepairGuiName; this.Events["Maintenance"].guiName = this.MaintenanceString; #endregion // Reset the internal state at the beginning of the flight // this condition also catches a revert to launch (+1 second for safety) if (DangIt.Now() < (this.TimeOfLastReset + 1)) { this.Reset(); } // If the part was saved when it was failed, // re-run the failure logic to disable it // ONLY THE DISABLING PART IS RUN! if (this.HasFailed) { this.DI_Disable(); } this.SetFailureState(this.HasFailed); } if (DangIt.Instance.CurrentSettings.EnabledForSave) { this.DI_Start(state); this.StartCoroutine("RuntimeFetch"); } } catch (Exception e) { OnError(e); } }
/// <summary> /// Multiplier that reduces the chance of failure right after an inspection. /// </summary> private float InspectionLambdaMultiplier() { float elapsed = (DangIt.Now() - this.TimeOfLastInspection); // Constrain it between 0 and 1 float f = Math.Max(0f, Math.Min(elapsed / this.InspectionBonus, 1f)); #if DEBUG if (printChances) { print("InspectionLambdaMultiplier: " + f.ToString()); } #endif return(f); }
/// <summary> /// Update logic on every physics frame update. /// Place your custom update logic in DI_Update() /// </summary> public void FixedUpdate() { if (streamMultiplier > 0 && Planetarium.GetUniversalTime() - lastDecayTime > 1) { streamMultiplier = Math.Max(0, streamMultiplier - decayPerMinute); lastDecayTime = Planetarium.GetUniversalTime(); } try { // Only update the module during flight and after the re-initialization has run if (HighLogic.LoadedSceneIsFlight && this.HasInitted && this.vessel == FlightGlobals.ActiveVessel) { // Highlighting the part, which contains this updating FailureModule if it is in a 'failed' state, // it is not in 'silent' state and 'glow' is globally enabled // Actually, there is not any place in a code of the whole mod where that 'silent' state is turning on // (maybe some FailureModules can be defined as 'silent' by editing files) if (this.HasFailed && !this.Silent && (DangIt.Instance.CurrentSettings.Glow && (AlarmManager.visibleUI || !DangIt.Instance.CurrentSettings.DisableGlowOnF2))) { this.part.SetHighlightDefault(); this.part.SetHighlightColor(Color.red); this.part.SetHighlightType(Part.HighlightType.AlwaysOn); this.part.highlighter.ConstantOn(Color.red); this.part.highlighter.SeeThroughOn(); this.part.SetHighlight(true, false); } else // Turning off the highlighting of the part, which contains this updating FailureModule // if it is not in a 'failed' state, or it is in 'silent' state, or if 'glow' is globally disabled // if (!this.HasFailed || this.Silent || !DangIt.Instance.CurrentSettings.Glow || (!visibleUI && DangIt.Instance.CurrentSettings.DisableGlowOnF2)) { if (!AlarmManager.partFailures.ContainsKey(this.part)) { this.part.SetHighlightDefault(); } } float now = DangIt.Now(); float dt = now - LastFixedUpdate; this.LastFixedUpdate = now; // The temperature aging is independent from the use of the part this.Age += (dt * this.TemperatureMultiplier()); if (!PartIsActive() || !DangIt.Instance.CurrentSettings.EnabledForSave) { return; } else { this.Age += dt; this.CurrentMTBF = this.MTBF * HighLogic.CurrentGame.Parameters.CustomParams <DangItCustomParams1>().MTBF_Multiplier *this.ExponentialDecay(); // If the part has not already failed, toss the dice if (!this.HasFailed) { float f = this.Lambda(); #if DEBUG // if (printChances) // Logger.Debug("this.Lambda: " + f.ToString()); #endif if (UnityEngine.Random.Range(0f, 1f) < f) { streamMultiplier = 0; this.Fail(); } } // Run custom update logic this.DI_Update(); } } } catch (Exception e) { OnError(e); } }
/// <summary> /// Module re-start logic. OnStart will be called usually once for each scene, editor included. /// Put your custom start logic in DI_Start(): if you need to act on other part's /// variable, this is the place to do it, not DI_Reset() /// </summary> public override void OnStart(PartModule.StartState state) { Log.Info("FailureModule.OnStart, part: " + this.part.partInfo.title); try { if (HighLogic.LoadedSceneIsFlight) // nothing to do in editor { this.FailureLog("Starting in flight: last reset " + TimeOfLastReset + ", now " + DangIt.Now()); if (!DangIt.Instance.CurrentSettings.EnabledForSave) { //Disable if we've disabled DangIt foreach (var e in this.Events) { e.guiActive = false; } } #region Fail and repair events this.Events["Fail"].guiName = this.FailGuiName; this.Events["EvaRepair"].guiName = this.EvaRepairGuiName; this.Events["Maintenance"].guiName = this.MaintenanceString; #endregion // Reset the internal state at the beginning of the flight // this condition also catches a revert to launch (+1 second for safety) if (DangIt.Now() < (this.TimeOfLastReset + 1)) { this.Reset(); } // If the part was saved when it was failed, // re-run the failure logic to disable it // ONLY THE DISABLING PART IS RUN! if (this.HasFailed) { this.DI_Disable(); } this.SetFailureState(this.HasFailed); if (!vesselHighlightDict.ContainsKey(vessel.id)) { var failedHighlightID = phl.CreateHighlightList(0); if (failedHighlightID < 0) { return; } if (DangIt.Instance.CurrentSettings.FlashingGlow) { phl.SetFlashInterval(failedHighlightID, HighLogic.CurrentGame.Parameters.CustomParams <DangItCustomParams1>().flashingInterval); } vesselHighlightDict[vessel.id] = failedHighlightID; } phl.UpdateHighlightColors(vesselHighlightDict[vessel.id], Color.red); if (DangIt.Instance.CurrentSettings.EnabledForSave) { this.DI_Start(state); this.StartCoroutine("RuntimeFetch"); } } } catch (Exception e) { OnError(e); } }