Skip to content

Commit

Permalink
Add one-time reminder about ignition restart window penalties
Browse files Browse the repository at this point in the history
  • Loading branch information
siimav committed Nov 5, 2023
1 parent 9e7bdd8 commit b71745f
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 52 deletions.
153 changes: 101 additions & 52 deletions TestFlightFailure_IgnitionFail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class TestFlightFailure_IgnitionFail : TestFlightFailure_Engine
private readonly Dictionary<uint, EngineRunData> engineRunData = new Dictionary<uint, EngineRunData>(8);

private static bool dynPressureReminderShown;
private static bool restartWindowPenaltyReminderShown;
private bool preLaunchFailures;
private bool dynPressurePenalties;
private bool verboseDebugging;
Expand Down Expand Up @@ -137,6 +138,12 @@ public override void OnStart(StartState state)
tfSettings.dynPressurePenaltyReminderShown = true;
}
dynPressureReminderShown |= tfSettings.dynPressurePenaltyReminderShown;

if (restartWindowPenaltyReminderShown)
{
tfSettings.restartWindowPenaltyReminderShown = true;
}
restartWindowPenaltyReminderShown |= tfSettings.restartWindowPenaltyReminderShown;
}

public override void OnLoad(ConfigNode node)
Expand Down Expand Up @@ -192,36 +199,25 @@ public override void OnUpdate()
{
EngineHandler engine = engines[i];
EngineModuleWrapper.EngineIgnitionState currentIgnitionState = engine.engine.IgnitionState;
var engineData = GetEngineRunDataForID(engine.engine.Module.PersistentId);
EngineRunData engineData = GetEngineRunDataForID(engine.engine.Module.PersistentId);

double initialFlightData = core.GetInitialFlightData();
float ignitionChance = 1f;
float pressureModifier = 1f;
float restartWindowModifier = 1f;

// Check to see if the vessel has not launched and if the player disabled pad failures
if (this.vessel.situation == Vessel.Situations.PRELAUNCH && !preLaunchFailures) {
ignitionChance = 1.0f;
} else {
ignitionChance = baseIgnitionChance.Evaluate((float)initialFlightData);
if (ignitionChance <= 0)
ignitionChance = 1f;
}

if (dynPressurePenalties)
float ignitionChance;
// Check to see if the vessel has not launched and if the player disabled pad failures
if (this.vessel.situation == Vessel.Situations.PRELAUNCH && !preLaunchFailures)
{
pressureModifier = Mathf.Clamp(pressureCurve.Evaluate((float)(part.dynamicPressurekPa * 1000d)), 0, 1);
if (pressureModifier <= 0f)
pressureModifier = 1f;
ignitionChance = 1.0f;
}

// if this engine has run before, and our config defines a restart window, we need to check against that and modify our ignition chance accordingly
if (hasRestartWindow && engineData.hasBeenRun)
else
{
engineIdleTime = engineData.timeSinceLastShutdown;
restartWindowModifier = Mathf.Clamp(restartWindowPenalty.Evaluate(engineIdleTime), 0, 1);
ignitionChance = baseIgnitionChance.Evaluate((float)initialFlightData);
if (ignitionChance <= 0)
ignitionChance = 1f;
}

float pressureModifier = GetDynPressureModifier();
float restartWindowModifier = GetRestartWindowModifier(engineData);

if (this.vessel.situation != Vessel.Situations.PRELAUNCH)
ignitionChance = ignitionChance * pressureModifier * ignitionUseMultiplier.Evaluate(numIgnitions) * restartWindowModifier;
Expand All @@ -231,15 +227,6 @@ public override void OnUpdate()
restartPenalty = 1f - restartWindowModifier;
engineHasRun = engineData.hasBeenRun;

if (currentIgnitionState == EngineModuleWrapper.EngineIgnitionState.IGNITED)
{
engineData.timeSinceLastShutdown = 0;
}
else
{
engineData.timeSinceLastShutdown += (float)deltaTime;
}

// If we are transitioning from not ignited to ignited, we do our check
// The ignitionFailureRate defines the failure rate per flight data
if (currentIgnitionState == EngineModuleWrapper.EngineIgnitionState.IGNITED)
Expand All @@ -250,12 +237,12 @@ public override void OnUpdate()
{
Log($"IgnitionFail: Engine {engine.engine.Module.GetInstanceID()} transitioning to INGITED state");
Log("IgnitionFail: Checking curves...");
}
}
numIgnitions++;

double failureRoll = core.RandomGenerator.NextDouble();
restartRollString = $"Roll: {failureRoll:P}, Chance: {ignitionChance:P}";

if (verboseDebugging)
{
Log($"IgnitionFail: Engine {engine.engine.Module.GetInstanceID()} ignition chance {ignitionChance:F4}, roll {failureRoll:F4}");
Expand All @@ -276,6 +263,15 @@ public override void OnUpdate()
}
}
}

if (currentIgnitionState == EngineModuleWrapper.EngineIgnitionState.IGNITED)
{
engineData.timeSinceLastShutdown = 0;
}
else
{
engineData.timeSinceLastShutdown += (float)deltaTime;
}
engine.ignitionState = currentIgnitionState;
}
Profiler.EndSample();
Expand All @@ -287,7 +283,6 @@ public override void DoFailure()
if (!TestFlightEnabled)
return;
Failed = true;
float multiplier = 1f;
ITestFlightCore core = TestFlightUtil.GetCore(this.part, Configuration);
if (core != null)
{
Expand All @@ -297,12 +292,7 @@ public override void DoFailure()
}

string met = KSPUtil.PrintTimeCompact((int)Math.Floor(this.vessel.missionTime), false);
if (dynPressurePenalties)
{
multiplier = pressureCurve.Evaluate((float)(part.dynamicPressurekPa * 1000d));
if (multiplier <= 0f)
multiplier = 1f;
}
float multiplier = GetDynPressureModifier();

if (multiplier < 0.99)
{
Expand All @@ -311,26 +301,29 @@ public override void DoFailure()

if (!dynPressureReminderShown && multiplier < 0.95)
{
string msg = $"High dynamic pressure caused a {sPenaltyPercent} reduction in normal ignition reliability. Consider lighting the engine on the ground or higher up in the atmosphere.\nThese penalties are listed in both the flight log (F3) and in the Part Action Window.";
PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
"IgnitionDynPressurePenaltyTip",
"Ignition Failure",
msg,
"OK",
false,
HighLogic.UISkin);
TestFlightGameSettings tfSettings = HighLogic.CurrentGame.Parameters.CustomParams<TestFlightGameSettings>();
tfSettings.dynPressurePenaltyReminderShown = dynPressureReminderShown = true;
ShowDynPressurePenaltyInfo(sPenaltyPercent);
}
}
else
{
FlightLogger.eventLog.Add($"[{met}] {core.Title} failed: Ignition Failure.");
}

EngineHandler engine = engines.Find(e => e.failEngine);
if (!restartWindowPenaltyReminderShown && engine != null)
{
EngineRunData engineData = GetEngineRunDataForID(engine.engine.Module.PersistentId);
float restartWindowModifier = GetRestartWindowModifier(engineData);
if (restartWindowModifier < 0.95)
{
string sPenaltyPercent = $"{(1f - restartWindowModifier) * 100f:0.#}%";
ShowRestartWindowPenaltyInfo(sPenaltyPercent);
}
}

core.LogCareerFailure(vessel, failureTitle);
}

Log($"IgnitionFail: Failing {engines.Count} engine(s)");
for (int i = 0; i < engines.Count; i++)
{
Expand All @@ -349,8 +342,8 @@ public override void DoFailure()
engines[i].failEngine = false;
}
}

}

public override float DoRepair()
{
base.DoRepair();
Expand All @@ -370,6 +363,7 @@ public override float DoRepair()
}
return 0;
}

public void RestoreIgnitor()
{
// part.Modules["ModuleEngineIgnitor"].GetType().GetField("ignitionsRemained").GetValue(part.Modules["ModuleEngineIgnitor"]));
Expand Down Expand Up @@ -566,6 +560,61 @@ private void GetIgnitionChance(ref float currentIgnitionChance, ref float maxIgn
}
}
}

private float GetDynPressureModifier()
{
float pressureModifier = 1f;
if (dynPressurePenalties)
{
pressureModifier = Mathf.Clamp(pressureCurve.Evaluate((float)(part.dynamicPressurekPa * 1000d)), 0, 1);
if (pressureModifier <= 0f)
pressureModifier = 1f;
}

return pressureModifier;
}

private float GetRestartWindowModifier(EngineRunData engineData)
{
// if this engine has run before, and our config defines a restart window, we need to check against that and modify our ignition chance accordingly
if (hasRestartWindow && engineData.hasBeenRun)
{
engineIdleTime = engineData.timeSinceLastShutdown;
return Mathf.Clamp(restartWindowPenalty.Evaluate(engineIdleTime), 0, 1);
}

return 1f;
}

private static void ShowDynPressurePenaltyInfo(string sPenaltyPercent)
{
string msg = $"High dynamic pressure caused a {sPenaltyPercent} reduction in normal ignition reliability. Consider lighting the engine on the ground or higher up in the atmosphere.\nThese penalties are listed in both the flight log (F3) and in the Part Action Window.";
PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
"IgnitionDynPressurePenaltyTip",
"Ignition Failure",
msg,
"OK",
false,
HighLogic.UISkin);
TestFlightGameSettings tfSettings = HighLogic.CurrentGame.Parameters.CustomParams<TestFlightGameSettings>();
tfSettings.dynPressurePenaltyReminderShown = dynPressureReminderShown = true;
}

private void ShowRestartWindowPenaltyInfo(string sPenaltyPercent)
{
string msg = $"{core.Title} has restart window modifiers which caused a {sPenaltyPercent} reduction in normal ignition reliability. Please refer to the Part Action Window to see the current penalty in-flight or middle click on the engine while in editor.";
PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
"RestartWindowPressurePenaltyTip",
"Ignition Failure",
msg,
"OK",
false,
HighLogic.UISkin);
TestFlightGameSettings tfSettings = HighLogic.CurrentGame.Parameters.CustomParams<TestFlightGameSettings>();
tfSettings.restartWindowPenaltyReminderShown = restartWindowPenaltyReminderShown = true;
}
}
}

1 change: 1 addition & 0 deletions TestFlightSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class TestFlightGameSettings : GameParameters.CustomParameterNode

// The following values are persisted to the savegame but are not shown in the difficulty settings UI
public bool dynPressurePenaltyReminderShown = false;
public bool restartWindowPenaltyReminderShown = false;

public override void SetDifficultyPreset(GameParameters.Preset preset)
{
Expand Down

0 comments on commit b71745f

Please sign in to comment.