Skip to content

Commit 83d5f99

Browse files
committed
Merge branch 'master' into TrainCarOperationsBugfixes
2 parents 6dd0532 + 8773ee5 commit 83d5f99

File tree

33 files changed

+555
-140
lines changed

33 files changed

+555
-140
lines changed

Source/Contrib/ContentManager/ContentInfo.cs

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,18 @@
2727
using System.Runtime.Serialization.Formatters.Binary;
2828
using System.Text;
2929
using Path = ORTS.ContentManager.Models.Path;
30+
using ORTS.Common;
3031

3132
namespace ORTS.ContentManager
3233
{
3334
public static class ContentInfo
3435
{
36+
// will be set from ConntentManagerGUI constructor
37+
public static bool IsMetric = false;
38+
public static bool IsUK = false;
39+
public static bool IsImperialBHP = false; // using default; seems only used for steam locos
40+
public static bool IsImperialBTUpS = false; // using default; seems only be used for steam locos
41+
3542
public static string GetText(Content content)
3643
{
3744
var details = new StringBuilder();
@@ -179,16 +186,39 @@ public static string GetText(Content content)
179186
{
180187
var data = new Consist(content);
181188
details.AppendFormat("Name:\t{1}{0}", Environment.NewLine, data.Name);
182-
details.AppendFormat("Car ID:\tDirection:\tName:\t{0}", Environment.NewLine);
189+
details.AppendFormat("NumEngines:\t{1}{0}", Environment.NewLine, data.NumEngines);
190+
details.AppendFormat("NumCars:\t{1}{0}", Environment.NewLine, data.NumCars);
191+
details.AppendFormat("MaxSpeed:\t{1}{0}", Environment.NewLine, FormatStrings.FormatSpeedLimit(data.MaxSpeedMps, IsMetric));
192+
details.AppendFormat("Weight:\t{1}{0}", Environment.NewLine, FormatStrings.FormatLargeMass(data.MassKG, IsMetric, IsUK));
193+
details.AppendFormat("Length:\t{1}{0}", Environment.NewLine, FormatStrings.FormatShortDistanceDisplay(data.LengthM, IsMetric));
194+
details.AppendFormat("Power:\t{1}{0}", Environment.NewLine, FormatStrings.FormatPower(data.MaxPowerW, IsMetric, IsImperialBHP, IsImperialBTUpS));
195+
details.AppendFormat("MaxTE:\t{1}{0}", Environment.NewLine, FormatStrings.FormatForce(data.MaxTractiveForceN, IsMetric));
196+
details.AppendFormat("MinCouplerStrength:\t{1}{0}", Environment.NewLine, FormatStrings.FormatForce(data.MinCouplerStrengthN, IsMetric));
197+
if (!IsMetric && !IsUK) { details.AppendFormat("HPT:\t{1}{0}", Environment.NewLine, FormatHPT(data.MaxPowerW, data.MassKG)); }
198+
if (!IsMetric && !IsUK) { details.AppendFormat("TPOB:\t{1}{0}", Environment.NewLine, FormatTPOB(data.MassKG, data.NumOperativeBrakes)); }
199+
details.AppendLine();
200+
details.AppendFormat("Car ID:\tDirection:\tWeight:\tName:\t{0}", Environment.NewLine);
183201
foreach (var car in data.Cars)
184-
details.AppendFormat("{1}\t{2}\t\u0001{3}\u0002Car\u0001{0}", Environment.NewLine, car.ID, car.Direction, car.Name);
202+
details.AppendFormat("{1}\t{2}\t{3}\t\u0001{4}\u0002Car\u0001{0}", Environment.NewLine, car.ID, car.Direction, car.IsEngine ? "Engine" : FormatMassBar(car.MassKG), car.Name);
185203
details.AppendFormat("{0}", Environment.NewLine);
186204
}
187205
else if (content.Type == ContentType.Car)
188206
{
189207
var data = new Car(content);
190208
details.AppendFormat("Type:\t{1}{0}", Environment.NewLine, data.Type);
209+
details.AppendFormat("SubType:\t{1}{0}", Environment.NewLine, data.SubType);
191210
details.AppendFormat("Name:\t{1}{0}", Environment.NewLine, data.Name);
211+
details.AppendFormat("Weight:\t{1} ({2}){0}", Environment.NewLine, FormatStrings.FormatMass(data.MassKG, IsMetric), FormatStrings.FormatLargeMass(data.MassKG, IsMetric, IsUK));
212+
details.AppendFormat("Length:\t{1}{0}", Environment.NewLine, FormatStrings.FormatShortDistanceDisplay(data.LengthM, IsMetric));
213+
if (data.Type == CarType.Engine)
214+
{
215+
details.AppendFormat("MaxPowerW:\t{1}{0}", Environment.NewLine, FormatStrings.FormatPower(data.MaxPowerW, IsMetric, IsImperialBHP, IsImperialBTUpS));
216+
details.AppendFormat("MaxForce:\t{1}{0}", Environment.NewLine, FormatStrings.FormatForce(data.MaxForceN, IsMetric));
217+
details.AppendFormat("MaxSpeed:\t{1}{0}", Environment.NewLine, FormatStrings.FormatSpeedLimit(data.MaxSpeedMps, IsMetric));
218+
}
219+
details.AppendFormat("MaxBrakeF:\t{1}{0}", Environment.NewLine, FormatStrings.FormatForce(data.MaxBarkeForceN, IsMetric));
220+
details.AppendFormat("MinCouplerStrength:\t{1}{0}", Environment.NewLine, FormatStrings.FormatForce(data.MinCouplerStrengthN, IsMetric));
221+
details.AppendLine();
192222
details.AppendFormat("Description:\t{0}{0}{1}{0}{0}", Environment.NewLine, data.Description);
193223
}
194224
else if (content is ContentMSTSCab)
@@ -215,5 +245,46 @@ static string FormatDateTime(DateTime dateTime)
215245
{
216246
return String.Format("{0} {1}", dateTime.Day - 1, dateTime.ToLongTimeString());
217247
}
248+
249+
/// <summary>
250+
/// Create a simple bar graph (string of asterisk) for the car mass.
251+
/// </summary>
252+
/// <param name="massKg"></param>
253+
/// <returns>String of asterisk representing the mass.</returns>
254+
static string FormatMassBar(float massKg)
255+
{
256+
string massBar;
257+
var range = (int)Math.Ceiling(massKg / 20000);
258+
if (massKg < 1.0) { massBar = "?"; }
259+
else if (range > 8) { massBar = new string('*', 8) + '>'; }
260+
else { massBar = new string('*', range); }
261+
return massBar;
262+
}
263+
264+
/// <summary>
265+
/// Calculate and format horsepower per ton for consist, rounded to one decimal.
266+
/// </summary>
267+
/// <param name="consistPowerW"></param>
268+
/// <param name="consistMassKG"></param>
269+
/// <returns>horsepower-per-ton formated to one decimal.</returns>
270+
//TODO: implement UK and metric version
271+
static string FormatHPT(float consistPowerW, float consistMassKG)
272+
{
273+
var hpt = consistMassKG > 0 ? W.ToHp(consistPowerW) / Kg.ToTUS(consistMassKG) : 0;
274+
return string.Format("{0:0.0}", hpt);
275+
}
276+
277+
/// <summary>
278+
/// Calculate and format tons per operative brake for consist, rounded to an integer.
279+
/// </summary>
280+
/// <param name="consistMassKG"></param>
281+
/// <param name="consistNumOpBrakes"></param>
282+
/// <returns>tons-per-operative-brake formated to an integer.</returns>
283+
//TODO: implement UK and metric version
284+
static string FormatTPOB(float consistMassKG, float consistNumOpBrakes)
285+
{
286+
var tpob = consistNumOpBrakes > 0 ? Kg.ToTUS(consistMassKG) / consistNumOpBrakes : 0;
287+
return string.Format("{0:0}", tpob);
288+
}
218289
}
219290
}

Source/Contrib/ContentManager/ContentManagerGUI.Designer.cs

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Source/Contrib/ContentManager/ContentManagerGUI.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ public ContentManagerGUI()
7575
Settings = new UserSettings(new string[0]);
7676
ContentManager = new ContentManager(Settings.Folders);
7777

78+
// add unit settings to ContentInfo static class; only considering explict setting or system setting
79+
if (Settings.Units == "Metric") { ContentInfo.IsMetric = true; }
80+
else if (Settings.Units == "UK") { ContentInfo.IsUK = true; }
81+
else // setting is Automatic or Route
82+
{
83+
ContentInfo.IsMetric = System.Globalization.RegionInfo.CurrentRegion.IsMetric;
84+
// special cases
85+
if (System.Globalization.RegionInfo.CurrentRegion.Name == "UK") { ContentInfo.IsUK = true; }
86+
else if (System.Globalization.RegionInfo.CurrentRegion.Name == "CA") { ContentInfo.IsMetric = false; } // Canada is metric, but RRs use imperial US
87+
}
88+
7889
// Start off the tree with the Content Manager itself at the root and expand to show packages.
7990
treeViewContent.Nodes.Add(CreateContentNode(ContentManager));
8091
treeViewContent.Nodes[0].Expand();

Source/Contrib/ContentManager/Models/Car.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,41 @@ public enum CarType
3333
public class Car
3434
{
3535
public readonly CarType Type;
36+
public readonly string SubType;
3637
public readonly string Name;
3738
public readonly string Description;
39+
public readonly float MassKG;
40+
public readonly float LengthM;
41+
public readonly float MaxBarkeForceN;
42+
public readonly float MaxPowerW;
43+
public readonly float MaxForceN;
44+
public readonly float MaxSpeedMps;
45+
public readonly float MinCouplerStrengthN;
3846

3947
public Car(Content content)
4048
{
4149
Debug.Assert(content.Type == ContentType.Car);
50+
51+
// .eng files also have a wagon block
52+
var wagFile = new WagonFile(content.PathName);
53+
Type = CarType.Wagon;
54+
SubType = wagFile.WagonType;
55+
Name = wagFile.Name;
56+
MassKG = wagFile.MassKG;
57+
LengthM = wagFile.WagonSize.LengthM;
58+
MaxBarkeForceN = wagFile.MaxBrakeForceN;
59+
MinCouplerStrengthN = wagFile.MinCouplerStrengthN;
60+
4261
if (System.IO.Path.GetExtension(content.PathName).Equals(".eng", StringComparison.OrdinalIgnoreCase))
4362
{
44-
var file = new EngineFile(content.PathName);
63+
var engFile = new EngineFile(content.PathName);
4564
Type = CarType.Engine;
46-
Name = file.Name;
47-
Description = file.Description;
48-
}
49-
else if (System.IO.Path.GetExtension(content.PathName).Equals(".wag", StringComparison.OrdinalIgnoreCase))
50-
{
51-
var file = new WagonFile(content.PathName);
52-
Type = CarType.Wagon;
53-
Name = file.Name;
54-
Description = "";
65+
SubType = engFile.EngineType;
66+
Name = engFile.Name;
67+
MaxPowerW = engFile.MaxPowerW;
68+
MaxForceN = engFile.MaxForceN;
69+
MaxSpeedMps = engFile.MaxSpeedMps;
70+
Description = engFile.Description;
5571
}
5672
}
5773
}

Source/Contrib/ContentManager/Models/Consist.cs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,26 @@
1919
using System;
2020
using System.Collections.Generic;
2121
using System.Diagnostics;
22+
using System.IO;
2223
using System.Linq;
24+
using System.Runtime.CompilerServices;
2325
using System.Text;
2426

2527
namespace ORTS.ContentManager.Models
2628
{
2729
public class Consist
2830
{
2931
public readonly string Name;
32+
public readonly string NumEngines; // using "+" between DPU sets
33+
public readonly string NumCars;
34+
public readonly float MaxSpeedMps;
35+
public readonly float LengthM = 0F;
36+
public readonly float MassKG = 0F;
37+
public readonly float MaxPowerW = 0F;
38+
public readonly float MaxTractiveForceN = 0F;
39+
public readonly float MaxBrakeForce = 0F;
40+
public readonly int NumOperativeBrakes = 0;
41+
public readonly float MinCouplerStrengthN = 9.999e8f; // impossible high force
3042

3143
public readonly IEnumerable<Car> Cars;
3244

@@ -37,9 +49,60 @@ public Consist(Content content)
3749
{
3850
var file = new ConsistFile(content.PathName);
3951
Name = file.Name;
52+
MaxSpeedMps = file.Train.TrainCfg.MaxVelocity.A;
4053

41-
Cars = from car in file.Train.TrainCfg.WagonList
42-
select new Car(car);
54+
var EngCount = 0;
55+
var WagCount = 0;
56+
var Separator = ""; // when set, indicates that subsequent engines are in a separate block
57+
58+
var basePath = System.IO.Path.Combine(System.IO.Path.Combine(content.Parent.PathName, "Trains"), "Trainset");
59+
60+
var CarList = new List<Car>();
61+
foreach (Wagon wag in file.Train.TrainCfg.WagonList)
62+
{
63+
float wagonMassKG = 0;
64+
try
65+
{
66+
var fileType = wag.IsEngine ? ".eng" : ".wag";
67+
var filePath = System.IO.Path.Combine(System.IO.Path.Combine(basePath, wag.Folder), wag.Name + fileType);
68+
var wagonFile = new WagonFile(filePath);
69+
var engFile = wag.IsEngine ? new EngineFile(filePath) : null;
70+
71+
LengthM += wagonFile.WagonSize.LengthM;
72+
MassKG += wagonFile.MassKG;
73+
wagonMassKG = wagonFile.MassKG;
74+
MaxBrakeForce += wagonFile.MaxBrakeForceN;
75+
MinCouplerStrengthN = Math.Min(MinCouplerStrengthN, wagonFile.MinCouplerStrengthN);
76+
if (wagonFile.MaxBrakeForceN > 0) { NumOperativeBrakes++; }
77+
78+
if (wag.IsEngine && engFile.MaxForceN > 25000) // exclude legacy driving trailers / cab-cars
79+
{
80+
EngCount++;
81+
82+
MaxPowerW += engFile.MaxPowerW;
83+
MaxTractiveForceN += engFile.MaxForceN;
84+
}
85+
else if (!wag.IsEOT && wagonFile.WagonSize.LengthM > 1.1) // exclude legacy EOT
86+
{
87+
WagCount++;
88+
}
89+
} catch (IOException e) // continue without details when eng/wag file does not exist
90+
{
91+
if (wag.IsEngine) { EngCount++; } else { WagCount++; }
92+
}
93+
94+
if (!wag.IsEngine && EngCount > 0)
95+
{
96+
NumEngines = NumEngines + Separator + EngCount.ToString();
97+
EngCount = 0; Separator = "+";
98+
}
99+
100+
CarList.Add(new Car(wag, wagonMassKG));
101+
}
102+
if (EngCount > 0) { NumEngines = NumEngines + Separator + EngCount.ToString(); }
103+
if (NumEngines == null) { NumEngines = "0"; }
104+
NumCars = WagCount.ToString();
105+
Cars = CarList;
43106
}
44107
}
45108

@@ -53,12 +116,16 @@ public class Car
53116
public readonly string ID;
54117
public readonly string Name;
55118
public readonly Direction Direction;
119+
public readonly bool IsEngine;
120+
public readonly float MassKG;
56121

57-
internal Car(Wagon car)
122+
internal Car(Wagon car, float massKg)
58123
{
59124
ID = car.UiD.ToString();
60125
Name = car.Folder + "/" + car.Name;
61126
Direction = car.Flip ? Consist.Direction.Backwards : Consist.Direction.Forwards;
127+
IsEngine = car.IsEngine;
128+
MassKG = massKg;
62129
}
63130
}
64131
}

Source/Documentation/Manual/driving.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ Following activity features are randomized:
18701870
will be shown in red in the train operations window and will squeal
18711871
if an .sms file named BrakesStuck.sms is present in the
18721872
``<Train Simulator\Sound>`` directory. `Here
1873-
<http://www.interazioni-educative.it/Varie/BrakesStuckSound.zip>`_
1873+
<https://static.openrails.org/files/BrakesStuckSound.zip>`_
18741874
an example of such file.
18751875
Of course when this event occurs it is advisable to uncouple the
18761876
wagon as soon as possible from the train. No more than a car will

0 commit comments

Comments
 (0)