public override void PrepareFrame(ElapsedTime elapsedTime, bool updateFull) { base.PrepareFrame(elapsedTime, updateFull); // Always get train details to pass on to TrackMonitor. var thisInfo = Owner.Viewer.PlayerTrain.GetTrainInfo(); Monitor.StoreInfo(thisInfo); // Update text fields on full update only. if (updateFull) { SpeedCurrent.Text = FormatStrings.FormatSpeedDisplay(Math.Abs(thisInfo.speedMpS), Owner.Viewer.MilepostUnitsMetric); SpeedProjected.Text = FormatStrings.FormatSpeedDisplay(Math.Abs(thisInfo.projectedSpeedMpS), Owner.Viewer.MilepostUnitsMetric); SpeedAllowed.Text = FormatStrings.FormatSpeedLimit(thisInfo.allowedSpeedMpS, Owner.Viewer.MilepostUnitsMetric); var ControlText = ControlModeLabels[thisInfo.ControlMode]; if (thisInfo.ControlMode == Train.TRAIN_CONTROL.AUTO_NODE) { ControlText = FindAuthorityInfo(thisInfo.ObjectInfoForward, ControlText); } else if (thisInfo.ControlMode == Train.TRAIN_CONTROL.OUT_OF_CONTROL) { ControlText = String.Concat(ControlText, OutOfControlLabels[thisInfo.ObjectInfoForward[0].OutOfControlReason]); } ControlMode.Text = String.Copy(ControlText); } }
/// <summary> /// Retrieve a formatted list <see cref="ListLabel"/>s to be displayed as an in-browser Track Monitor. /// </summary> /// <param name="viewer">The Viewer to read train data from.</param> /// <returns>A list of <see cref="ListLabel"/>s, one per row of the popup.</returns> public static IEnumerable <ListLabel> TrainDrivingDisplayList(this Viewer viewer, bool normalTextMode = true) { bool useMetric = viewer.MilepostUnitsMetric; var labels = new List <ListLabel>(); void AddLabel(ListLabel label) { CheckLabel(ref label, normalTextMode); labels.Add(label); } void AddSeparator() => AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Sprtr"), }); TrainCar trainCar = viewer.PlayerLocomotive; Train train = trainCar.Train; string trainBrakeStatus = trainCar.GetTrainBrakeStatus(); string dynamicBrakeStatus = trainCar.GetDynamicBrakeStatus(); string engineBrakeStatus = trainCar.GetEngineBrakeStatus(); MSTSLocomotive locomotive = (MSTSLocomotive)trainCar; string locomotiveStatus = locomotive.GetStatus(); bool combinedControlType = locomotive.CombinedControlType == MSTSLocomotive.CombinedControl.ThrottleDynamic; bool showMUReverser = Math.Abs(train.MUReverserPercent) != 100f; bool showRetainers = train.RetainerSetting != RetainerSetting.Exhaust; bool stretched = train.Cars.Count > 1 && train.NPull == train.Cars.Count - 1; bool bunched = !stretched && train.Cars.Count > 1 && train.NPush == train.Cars.Count - 1; Train.TrainInfo trainInfo = train.GetTrainInfo(); // First Block // Client and server may have a time difference. AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Time"), LastCol = FormatStrings.FormatTime(viewer.Simulator.ClockTime + (MultiPlayer.MPManager.IsClient() ? MultiPlayer.MPManager.Instance().serverTimeDifference : 0)), }); if (viewer.Simulator.IsReplaying) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Replay"), LastCol = FormatStrings.FormatTime(viewer.Log.ReplayEndsAt - viewer.Simulator.ClockTime), }); } Color speedColor; if (locomotive.SpeedMpS < trainInfo.allowedSpeedMpS - 1f) { speedColor = Color.White; } else if (locomotive.SpeedMpS < trainInfo.allowedSpeedMpS) { speedColor = Color.PaleGreen; } else if (locomotive.SpeedMpS < trainInfo.allowedSpeedMpS + 5f) { speedColor = Color.Orange; } else { speedColor = Color.OrangeRed; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Speed"), LastCol = $"{FormatStrings.FormatSpeedDisplay(locomotive.SpeedMpS, useMetric)}{ColorCode[speedColor]}", }); // Gradient info if (normalTextMode) { float gradient = -trainInfo.currentElevationPercent; const float minSlope = 0.00015f; string gradientIndicator; if (gradient < -minSlope) { gradientIndicator = $"{gradient:F1}%{Symbols.GradientDown}{ColorCode[Color.LightSkyBlue]}"; } else if (gradient > minSlope) { gradientIndicator = $"{gradient:F1}%{Symbols.GradientUp}{ColorCode[Color.Yellow]}"; } else { gradientIndicator = $"{gradient:F1}%"; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Gradient"), LastCol = gradientIndicator, }); } // Separator AddSeparator(); // Second block // Direction { UserCommand?reverserCommand = GetPressedKey(UserCommand.ControlBackwards, UserCommand.ControlForwards); string reverserKey; bool moving = Math.Abs(trainCar.SpeedMpS) > 1; bool nonSteamEnd = trainCar.EngineType != TrainCar.EngineTypes.Steam && trainCar.Direction == Direction.N && (trainCar.ThrottlePercent >= 1 || moving); bool steamEnd = locomotive is MSTSSteamLocomotive steamLocomotive2 && steamLocomotive2.CutoffController.MaximumValue == Math.Abs(train.MUReverserPercent / 100); if (reverserCommand != null && (nonSteamEnd || steamEnd)) { reverserKey = Symbols.End + ColorCode[Color.Yellow]; } else if (reverserCommand == UserCommand.ControlBackwards) { reverserKey = Symbols.ArrowDown + ColorCode[Color.Yellow]; } else if (reverserCommand == UserCommand.ControlForwards) { reverserKey = Symbols.ArrowUp + ColorCode[Color.Yellow]; } else { reverserKey = ""; } string reverserIndicator = showMUReverser ? $"{Round(Math.Abs(train.MUReverserPercent))}% " : ""; AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString(locomotive.EngineType == TrainCar.EngineTypes.Steam ? "Reverser" : "Direction"), LastCol = $"{reverserIndicator}{FormatStrings.Catalog.GetParticularString("Reverser", GetStringAttribute.GetPrettyName(locomotive.Direction))}", KeyPressed = reverserKey, SymbolCol = reverserKey, }); } // Throttle { UserCommand?throttleCommand = GetPressedKey(UserCommand.ControlThrottleDecrease, UserCommand.ControlThrottleIncrease); string throttleKey; bool upperLimit = throttleCommand == UserCommand.ControlThrottleIncrease && locomotive.ThrottleController.MaximumValue == trainCar.ThrottlePercent / 100; bool lowerLimit = throttleCommand == UserCommand.ControlThrottleDecrease && trainCar.ThrottlePercent == 0; if (locomotive.DynamicBrakePercent < 1 && (upperLimit || lowerLimit)) { throttleKey = Symbols.End + ColorCode[Color.Yellow]; } else if (locomotive.DynamicBrakePercent > -1) { throttleKey = Symbols.EndLower + ColorCode[Color.Yellow]; } else if (throttleCommand == UserCommand.ControlThrottleIncrease) { throttleKey = Symbols.ArrowUp + ColorCode[Color.Yellow]; } else if (throttleCommand == UserCommand.ControlThrottleDecrease) { throttleKey = Symbols.ArrowDown + ColorCode[Color.Yellow]; } else { throttleKey = ""; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString(locomotive is MSTSSteamLocomotive ? "Regulator" : "Throttle"), LastCol = $"{Round(locomotive.ThrottlePercent)}%", KeyPressed = throttleKey, SymbolCol = throttleKey, }); } // Cylinder Cocks if (locomotive is MSTSSteamLocomotive steamLocomotive) { string cocksIndicator, cocksKey; if (steamLocomotive.CylinderCocksAreOpen) { cocksIndicator = Viewer.Catalog.GetString("Open") + ColorCode[Color.Orange]; cocksKey = Symbols.ArrowToRight + ColorCode[Color.Yellow]; } else { cocksIndicator = Viewer.Catalog.GetString("Closed") + ColorCode[Color.White]; cocksKey = ""; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Cylinder cocks"), LastCol = cocksIndicator, KeyPressed = cocksKey, SymbolCol = cocksKey, }); } // Sander if (locomotive.GetSanderOn()) { bool sanderBlocked = locomotive.AbsSpeedMpS > locomotive.SanderSpeedOfMpS; string sanderKey = Symbols.ArrowToRight + ColorCode[Color.Yellow]; AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Sander"), LastCol = sanderBlocked ? Viewer.Catalog.GetString("Blocked") + ColorCode[Color.OrangeRed] : Viewer.Catalog.GetString("On") + ColorCode[Color.Orange], KeyPressed = sanderKey, SymbolCol = sanderKey, }); } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Sander"), LastCol = Viewer.Catalog.GetString("Off"), KeyPressed = "", SymbolCol = "", }); } AddSeparator(); // Train Brake multi-lines // TODO: A better algorithm //var brakeStatus = Owner.Viewer.PlayerLocomotive.GetTrainBrakeStatus(); //steam loco string brakeInfoValue = ""; int index = 0; if (trainBrakeStatus.Contains(Viewer.Catalog.GetString("EQ"))) { string brakeKey; switch (GetPressedKey(UserCommand.ControlTrainBrakeDecrease, UserCommand.ControlTrainBrakeIncrease)) { case UserCommand.ControlTrainBrakeDecrease: brakeKey = Symbols.ArrowDown + ColorCode[Color.Yellow]; break; case UserCommand.ControlTrainBrakeIncrease: brakeKey = Symbols.ArrowUp + ColorCode[Color.Yellow]; break; default: brakeKey = ""; break; } brakeInfoValue = trainBrakeStatus.Substring(0, trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("EQ"))).TrimEnd(); AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Train brake"), LastCol = $"{brakeInfoValue}{ColorCode[Color.Cyan]}", KeyPressed = brakeKey, SymbolCol = brakeKey, }); index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("EQ")); brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("BC")) - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); if (trainBrakeStatus.Contains(Viewer.Catalog.GetString("EOT"))) { int indexOffset = Viewer.Catalog.GetString("EOT").Length + 1; index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("BC")); brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("EOT")) - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("EOT")) + indexOffset; brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.Length - index).TrimStart(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); } else { index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("BC")); brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.Length - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); } } else if (trainBrakeStatus.Contains(Viewer.Catalog.GetString("Lead"))) { int indexOffset = Viewer.Catalog.GetString("Lead").Length + 1; brakeInfoValue = trainBrakeStatus.Substring(0, trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("Lead"))).TrimEnd(); AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Train brake"), LastCol = $"{brakeInfoValue}{ColorCode[Color.Cyan]}", }); index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("Lead")) + indexOffset; if (trainBrakeStatus.Contains(Viewer.Catalog.GetString("EOT"))) { brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("EOT")) - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("EOT")) + indexOffset; brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.Length - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); } else { brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.Length - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); } } else if (trainBrakeStatus.Contains(Viewer.Catalog.GetString("BC"))) { brakeInfoValue = trainBrakeStatus.Substring(0, trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("BC"))).TrimEnd(); AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Train brake"), LastCol = $"{brakeInfoValue}{ColorCode[Color.Cyan]}", }); index = trainBrakeStatus.IndexOf(Viewer.Catalog.GetString("BC")); brakeInfoValue = trainBrakeStatus.Substring(index, trainBrakeStatus.Length - index).TrimEnd(); AddLabel(new ListLabel { LastCol = brakeInfoValue, }); } if (showRetainers) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Retainers"), LastCol = $"{train.RetainerPercent} {Viewer.Catalog.GetString(GetStringAttribute.GetPrettyName(train.RetainerSetting))}", }); } if (engineBrakeStatus.Contains(Viewer.Catalog.GetString("BC"))) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Engine brake"), LastCol = engineBrakeStatus.Substring(0, engineBrakeStatus.IndexOf("BC")) + ColorCode[Color.Cyan], }); index = engineBrakeStatus.IndexOf(Viewer.Catalog.GetString("BC")); brakeInfoValue = engineBrakeStatus.Substring(index, engineBrakeStatus.Length - index).TrimEnd(); AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString(""), LastCol = $"{brakeInfoValue}{ColorCode[Color.White]}", }); } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Engine brake"), LastCol = $"{engineBrakeStatus}{ColorCode[Color.Cyan]}", }); } if (dynamicBrakeStatus != null && locomotive.IsLeadLocomotive()) { if (locomotive.DynamicBrakePercent >= 0) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Dynamic brake"), LastCol = locomotive.DynamicBrake ? dynamicBrakeStatus : Viewer.Catalog.GetString("Setup") + ColorCode[Color.Cyan], }); } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Dynamic brake"), LastCol = Viewer.Catalog.GetString("Off"), }); } } AddSeparator(); if (locomotiveStatus != null) { foreach (string data in locomotiveStatus.Split('\n').Where((string d) => !string.IsNullOrWhiteSpace(d))) { string[] parts = data.Split(new string[] { " = " }, 2, StringSplitOptions.None); string keyPart = parts[0]; string valuePart = parts?[1]; if (Viewer.Catalog.GetString(keyPart).StartsWith(Viewer.Catalog.GetString("Boiler pressure"))) { MSTSSteamLocomotive steamLocomotive2 = (MSTSSteamLocomotive)locomotive; float bandUpper = steamLocomotive2.PreviousBoilerHeatOutBTUpS * 1.025f; // find upper bandwidth point float bandLower = steamLocomotive2.PreviousBoilerHeatOutBTUpS * 0.975f; // find lower bandwidth point - gives a total 5% bandwidth string heatIndicator; if (steamLocomotive2.BoilerHeatInBTUpS > bandLower && steamLocomotive2.BoilerHeatInBTUpS < bandUpper) { heatIndicator = $"{Symbols.SmallDiamond}{ColorCode[Color.White]}"; } else if (steamLocomotive2.BoilerHeatInBTUpS < bandLower) { heatIndicator = $"{Symbols.SmallArrowDown}{ColorCode[Color.Cyan]}"; } else if (steamLocomotive2.BoilerHeatInBTUpS > bandUpper) { heatIndicator = $"{Symbols.SmallArrowUp}{ColorCode[Color.Orange]}"; } else { heatIndicator = ColorCode[Color.White]; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Boiler pressure"), LastCol = Viewer.Catalog.GetString(valuePart), SymbolCol = heatIndicator, }); } else if (!normalTextMode && Viewer.Catalog.GetString(parts[0]).StartsWith(Viewer.Catalog.GetString("Fuel levels"))) { AddLabel(new ListLabel { FirstCol = keyPart.EndsWith("?") || keyPart.EndsWith("!") ? Viewer.Catalog.GetString(keyPart.Substring(0, keyPart.Length - 3)) : Viewer.Catalog.GetString(keyPart), LastCol = valuePart.Length > 1 ? Viewer.Catalog.GetString(valuePart.Replace(" ", string.Empty)) : "", }); } else if (keyPart.StartsWith(Viewer.Catalog.GetString("Gear"))) { string gearKey; switch (GetPressedKey(UserCommand.ControlGearDown, UserCommand.ControlGearUp)) { case UserCommand.ControlGearDown: gearKey = Symbols.ArrowDown + ColorCode[Color.Yellow]; break; case UserCommand.ControlGearUp: gearKey = Symbols.ArrowUp + ColorCode[Color.Yellow]; break; default: gearKey = ""; break; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString(keyPart), LastCol = valuePart != null ? Viewer.Catalog.GetString(valuePart) : "", KeyPressed = gearKey, SymbolCol = gearKey, }); } else if (parts.Contains(Viewer.Catalog.GetString("Pantographs"))) { string pantoKey; switch (GetPressedKey(UserCommand.ControlPantograph1)) { case UserCommand.ControlPantograph1: string arrow = parts[1].StartsWith(Viewer.Catalog.GetString("Up")) ? Symbols.ArrowUp : Symbols.ArrowDown; pantoKey = arrow + ColorCode[Color.Yellow]; break; default: pantoKey = ""; break; } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString(keyPart), LastCol = valuePart != null ? Viewer.Catalog.GetString(valuePart) : "", KeyPressed = pantoKey, SymbolCol = pantoKey, }); } else if (parts.Contains(Viewer.Catalog.GetString("Engine"))) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString(keyPart), LastCol = valuePart != null ? $"{Viewer.Catalog.GetString(valuePart)}{ColorCode[Color.White]}" : "", }); } else { AddLabel(new ListLabel { FirstCol = keyPart.EndsWith("?") || keyPart.EndsWith("!") ? Viewer.Catalog.GetString(keyPart.Substring(0, keyPart.Length - 3)) : Viewer.Catalog.GetString(keyPart), LastCol = valuePart != null ? Viewer.Catalog.GetString(valuePart) : "", }); } } } AddSeparator(); if (normalTextMode) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("FPS"), LastCol = $"{Math.Floor(viewer.RenderProcess.FrameRate.SmoothedValue)}", }); } // Messages // Autopilot bool autopilot = locomotive.Train.TrainType == Train.TRAINTYPE.AI_PLAYERHOSTING; AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Autopilot"), LastCol = autopilot ? Viewer.Catalog.GetString("On") + ColorCode[Color.Yellow] : Viewer.Catalog.GetString("Off"), }); // Grate limit if (locomotive is MSTSSteamLocomotive steamLocomotive1) { if (steamLocomotive1.IsGrateLimit && steamLocomotive1.GrateCombustionRateLBpFt2 > steamLocomotive1.GrateLimitLBpFt2) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Grate limit"), LastCol = Viewer.Catalog.GetString("Exceeded") + ColorCode[Color.OrangeRed], }); } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Grate limit") + ColorCode[Color.Black], LastCol = Viewer.Catalog.GetString("Normal") + ColorCode[Color.Black], }); } } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Grate limit") + ColorCode[Color.Black], LastCol = Viewer.Catalog.GetString("-") + ColorCode[Color.Black], }); } // Wheel if (train.IsWheelSlip) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Wheel"), LastCol = Viewer.Catalog.GetString("slip") + ColorCode[Color.OrangeRed], }); } else if (train.IsWheelSlipWarninq) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Wheel"), LastCol = Viewer.Catalog.GetString("slip warning") + ColorCode[Color.Yellow], }); } else if (train.IsBrakeSkid) { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Wheel"), LastCol = Viewer.Catalog.GetString("skid") + ColorCode[Color.OrangeRed], }); } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Wheel") + ColorCode[Color.Black], LastCol = Viewer.Catalog.GetString("Normal") + ColorCode[Color.Black], }); } // Doors var wagon = (MSTSWagon)locomotive; if (wagon.DoorLeftOpen || wagon.DoorRightOpen) { var status = new List <string>(); bool flipped = locomotive.GetCabFlipped(); if (wagon.DoorLeftOpen) { status.Add(Viewer.Catalog.GetString(Viewer.Catalog.GetString(flipped ? "Right" : "Left"))); } if (wagon.DoorRightOpen) { status.Add(Viewer.Catalog.GetString(Viewer.Catalog.GetString(flipped ? "Left" : "Right"))); } AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Doors open"), LastCol = string.Join(" ", status) + ColorCode[locomotive.AbsSpeedMpS > 0.1f ? Color.OrangeRed : Color.Yellow], }); } else { AddLabel(new ListLabel { FirstCol = Viewer.Catalog.GetString("Doors open") + ColorCode[Color.Black], LastCol = Viewer.Catalog.GetString("Closed") + ColorCode[Color.Black], }); } AddLabel(new ListLabel()); return(labels); }
public override void LoadFromWagFile(string wagFilePath) { base.LoadFromWagFile(wagFilePath); if (Simulator.Settings.VerboseConfigurationMessages) // Display locomotivve name for verbose error messaging { Trace.TraceInformation("\n\n ================================================= {0} =================================================", LocomotiveName); } NormalizeParams(); // Check to see if Speed of Max Tractive Force has been set - use ORTS value as first priority, if not use MSTS, last resort use an arbitary value. if (SpeedOfMaxContinuousForceMpS == 0) { if (MSTSSpeedOfMaxContinuousForceMpS != 0) { SpeedOfMaxContinuousForceMpS = MSTSSpeedOfMaxContinuousForceMpS; // Use MSTS value if present if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Speed Of Max Continuous Force: set to default value {0}", FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } else if (MaxPowerW != 0 && MaxContinuousForceN != 0) { SpeedOfMaxContinuousForceMpS = MaxPowerW / MaxContinuousForceN; if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Speed Of Max Continuous Force: set to 'calculated' value {0}", FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } else { SpeedOfMaxContinuousForceMpS = 10.0f; // If not defined then set at an "arbitary" value of 22mph if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Speed Of Max Continuous Force: set to 'arbitary' value {0}", FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } } if (DieselEngines == null) { DieselEngines = new DieselEngines(this); } // Create a diesel engine block if none exits, typically for a MSTS or BASIC configuration if (DieselEngines.Count == 0) { DieselEngines.Add(new DieselEngine()); DieselEngines[0].InitFromMSTS(this); DieselEngines[0].Initialize(true); } // Check initialization of power values for diesel engines for (int i = 0; i < DieselEngines.Count; i++) { DieselEngines[i].InitDieselRailPowers(this); } if (GearBox != null && GearBox.IsInitialized) { GearBox.CopyFromMSTSParams(DieselEngines[0]); if (DieselEngines[0].GearBox == null) { DieselEngines[0].GearBox = GearBox; DieselEngines[0].GearBox.UseLocoGearBox(DieselEngines[0]); } for (int i = 1; i < DieselEngines.Count; i++) { if (DieselEngines[i].GearBox == null) { DieselEngines[i].GearBox = new GearBox(GearBox, DieselEngines[i]); } } if (GearBoxController == null) { GearBoxController = new MSTSNotchController(GearBox.NumOfGears + 1); } } InitialMassKg = MassKG; // If traction force curves not set (BASIC configuration) then check that power values are set, otherwise locomotive will not move. if (TractiveForceCurves == null && LocomotiveMaxRailOutputPowerW == 0) { if (MaxPowerW != 0) { LocomotiveMaxRailOutputPowerW = MaxPowerW; // Set to default power value if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("MaxRailOutputPower (BASIC Config): set to default value = {0}", FormatStrings.FormatPower(LocomotiveMaxRailOutputPowerW, IsMetric, false, false)); } } else { LocomotiveMaxRailOutputPowerW = 2500000.0f; // If no default value then set to arbitary value if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("MaxRailOutputPower (BASIC Config): set at arbitary value = {0}", FormatStrings.FormatPower(LocomotiveMaxRailOutputPowerW, IsMetric, false, false)); } } if (MaximumDieselEnginePowerW == 0) { MaximumDieselEnginePowerW = LocomotiveMaxRailOutputPowerW; // If no value set in ENG file, then set the Prime Mover power to same as RailOutputPower (typically the MaxPower value) if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Maximum Diesel Engine Prime Mover Power set the same as MaxRailOutputPower {0} value", FormatStrings.FormatPower(MaximumDieselEnginePowerW, IsMetric, false, false)); } } } // Check force assumptions set for diesel if (Simulator.Settings.VerboseConfigurationMessages) { float ThrottleSetting = 1.0f; // Must be at full throttle for these calculations if (TractiveForceCurves == null) // Basic configuration - ie no force and Power tables, etc { float CalculatedMaxContinuousForceN = ThrottleSetting * LocomotiveMaxRailOutputPowerW / SpeedOfMaxContinuousForceMpS; Trace.TraceInformation("Diesel Force Settings (BASIC Config): Max Starting Force {0}, Calculated Max Continuous Force {1} @ speed of {2}", FormatStrings.FormatForce(MaxForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); Trace.TraceInformation("Diesel Power Settings (BASIC Config): Prime Mover {0}, Max Rail Output Power {1}", FormatStrings.FormatPower(MaximumDieselEnginePowerW, IsMetric, false, false), FormatStrings.FormatPower(LocomotiveMaxRailOutputPowerW, IsMetric, false, false)); if (MaxForceN < MaxContinuousForceN) { Trace.TraceInformation("!!!! Warning: Starting Tractive force {0} is less then Calculated Continuous force {1}, please check !!!!", FormatStrings.FormatForce(MaxForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } else // Advanced configuration - { float StartingSpeedMpS = 0.1f; // Assumed starting speed for diesel - can't be zero otherwise error will occurr float StartingForceN = (float)TractiveForceCurves.Get(ThrottleSetting, StartingSpeedMpS); float CalculatedMaxContinuousForceN = (float)TractiveForceCurves.Get(ThrottleSetting, SpeedOfMaxContinuousForceMpS); Trace.TraceInformation("Diesel Force Settings (ADVANCED Config): Max Starting Force {0} Calculated Max Continuous Force {1}, @ speed of {2}", FormatStrings.FormatForce(StartingForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); Trace.TraceInformation("Diesel Power Settings (ADVANCED Config): Prime Mover {0}, Max Rail Output Power {1} @ {2} rpm", FormatStrings.FormatPower(DieselEngines.MaxPowerW, IsMetric, false, false), FormatStrings.FormatPower(DieselEngines.MaximumRailOutputPowerW, IsMetric, false, false), MaxRPM); if (StartingForceN < MaxContinuousForceN) { Trace.TraceInformation("!!!! Warning: Calculated Starting Tractive force {0} is less then Calculated Continuous force {1}, please check !!!!", FormatStrings.FormatForce(StartingForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } // Check that MaxPower value is realistic - Calculate power - metric - P = F x V float CalculatedContinuousPowerW = MaxContinuousForceN * SpeedOfMaxContinuousForceMpS; if (MaxPowerW < CalculatedContinuousPowerW) { Trace.TraceInformation("!!!! Warning: MaxPower {0} is less then continuous force calculated power {1} @ speed of {2}, please check !!!!", FormatStrings.FormatPower(MaxPowerW, IsMetric, false, false), FormatStrings.FormatPower(CalculatedContinuousPowerW, IsMetric, false, false), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } Trace.TraceInformation("===================================================================================================================\n\n"); } }