@@ -76,6 +76,9 @@ namespace Orts.Simulation.Physics
76
76
public class Train
77
77
{
78
78
public List<TrainCar> Cars = new List<TrainCar>(); // listed front to back
79
+ public List<TrainCar> DPLeadUnits = new List<TrainCar>(); // list of all DP lead locomotives
80
+ // list of connected locomotives, each element is a list of the connected locomotives themselves
81
+ public List<List<TrainCar>> LocoGroups = new List<List<TrainCar>>();
79
82
public int Number;
80
83
public string Name;
81
84
public string TcsParametersFileName;
@@ -138,6 +141,7 @@ public TrainCar LastCar
138
141
public float BrakeLine4 = -1; // extra line just in case, ep brake control line. -2: hold, -1: inactive, 0: release, 0 < value <=1: apply
139
142
public RetainerSetting RetainerSetting = RetainerSetting.Exhaust;
140
143
public int RetainerPercent = 100;
144
+ public float TotalBrakePipeFlowM3pS; // Total flow rate of air from all MR to BP
141
145
public float TotalTrainBrakePipeVolumeM3; // Total volume of train brake pipe
142
146
public float TotalTrainBrakeCylinderVolumeM3; // Total volume of train brake cylinders
143
147
public float TotalTrainBrakeSystemVolumeM3; // Total volume of train brake system
@@ -509,6 +513,9 @@ public TrainCar LeadLocomotive
509
513
//if (lead.EngineBrakeController != null)
510
514
// lead.EngineBrakeController.UpdateEngineBrakePressure(ref BrakeLine3PressurePSI, 1000);
511
515
}
516
+
517
+ // If lead locomotive changes, distributed power needs to be updated
518
+ SetDPUnitIDs(true);
512
519
}
513
520
}
514
521
@@ -691,6 +698,7 @@ public Train(Simulator simulator, BinaryReader inf)
691
698
BrakeLine2PressurePSI = inf.ReadSingle();
692
699
BrakeLine3PressurePSI = inf.ReadSingle();
693
700
BrakeLine4 = inf.ReadSingle();
701
+ TotalBrakePipeFlowM3pS = inf.ReadSingle();
694
702
aiBrakePercent = inf.ReadSingle();
695
703
LeadLocomotiveIndex = inf.ReadInt32();
696
704
RetainerSetting = (RetainerSetting)inf.ReadInt32();
@@ -1039,6 +1047,7 @@ public virtual void Save(BinaryWriter outf)
1039
1047
outf.Write(BrakeLine2PressurePSI);
1040
1048
outf.Write(BrakeLine3PressurePSI);
1041
1049
outf.Write(BrakeLine4);
1050
+ outf.Write(TotalBrakePipeFlowM3pS);
1042
1051
outf.Write(aiBrakePercent);
1043
1052
outf.Write(LeadLocomotiveIndex);
1044
1053
outf.Write((int)RetainerSetting);
@@ -1314,6 +1323,7 @@ public TrainCar GetNextCab()
1314
1323
LeadLocomotiveIndex = Math.Abs(nextCabIndex) - 1;
1315
1324
Trace.Assert(LeadLocomotive != null, "Tried to switch to non-existent loco");
1316
1325
TrainCar newLead = LeadLocomotive; // Changing LeadLocomotiveIndex also changed LeadLocomotive
1326
+ SetDPUnitIDs(true); // DP IDs must be reprocessed when lead locomotive changes
1317
1327
((MSTSLocomotive)newLead).UsingRearCab = nextCabIndex < 0;
1318
1328
1319
1329
if (oldLead != null && newLead != null && oldLead != newLead)
@@ -1372,6 +1382,7 @@ public void LeadNextLocomotive()
1372
1382
else if (coud > 1)
1373
1383
LeadLocomotiveIndex = firstLead;
1374
1384
TrainCar newLead = LeadLocomotive;
1385
+ SetDPUnitIDs(true); // DP IDs must be reprocessed when lead locomotive changes
1375
1386
if (prevLead != null && newLead != null && prevLead != newLead)
1376
1387
newLead.CopyControllerSettings(prevLead);
1377
1388
}
@@ -1527,19 +1538,79 @@ public void ReverseCars()
1527
1538
/// </summary>
1528
1539
public void SetDPUnitIDs(bool keepRemoteGroups = false)
1529
1540
{
1541
+ // List to keep track of new 'lead' DP units
1542
+ // 'Lead' DP units follow the air brake commands of the master loco, 'trail' DP units do not
1543
+ List<TrainCar> tempDPLeads = new List<TrainCar>();
1544
+ TrainCar tempDPLead = null;
1545
+ // Value judging how compatible this locomotive is to the lead locomotive for DP purposes
1546
+ float dpRating = 0;
1547
+
1548
+ // List of each DP group's locomotives
1549
+ List<List<TrainCar>> tempLocoGroups = new List<List<TrainCar>>();
1550
+
1551
+ var prevId = -1;
1530
1552
var id = 0;
1553
+
1531
1554
foreach (var car in Cars)
1532
1555
{
1533
- //Console.WriteLine("___{0} {1}", car.CarID, id);
1534
- if (car is MSTSLocomotive)
1556
+ if (car is MSTSLocomotive loco)
1535
1557
{
1536
- (car as MSTSLocomotive).DPUnitID = id;
1558
+ float thisDPRating = DetermineDPCompatibility(LeadLocomotive, car);
1559
+
1560
+ loco.DPUnitID = id;
1561
+
1562
+ if (id != prevId) // New locomotive group
1563
+ {
1564
+ // Add the most suitable unit from the previous group as a DP lead unit
1565
+ if (tempDPLead != null && !tempDPLeads.Contains(tempDPLead))
1566
+ tempDPLeads.Add(tempDPLead);
1567
+
1568
+ dpRating = thisDPRating;
1569
+ tempDPLead = car;
1570
+
1571
+ prevId = id;
1572
+ }
1573
+ else // Same locomotive group
1574
+ // Check to see if this locomotive is more compatible than previous ones
1575
+ if (thisDPRating > dpRating)
1576
+ {
1577
+ dpRating = thisDPRating;
1578
+ tempDPLead = car;
1579
+ }
1580
+
1537
1581
if (car.RemoteControlGroup == 1 && !keepRemoteGroups)
1538
1582
car.RemoteControlGroup = 0;
1539
1583
}
1540
1584
else
1541
1585
id++;
1542
1586
}
1587
+
1588
+ // Add final DP lead unit
1589
+ if (tempDPLead != null && !tempDPLeads.Contains(tempDPLead))
1590
+ tempDPLeads.Add(tempDPLead);
1591
+
1592
+ foreach (TrainCar locoCar in tempDPLeads)
1593
+ {
1594
+ // The train's lead unit should always be a DP lead unit, even if not at the front
1595
+ // If a different locomotive in the lead loco's group has been declared DP lead, replace that loco with the lead loco
1596
+ if (LeadLocomotive is MSTSLocomotive lead && locoCar is MSTSLocomotive loco)
1597
+ if (loco.DPUnitID == lead.DPUnitID && locoCar != LeadLocomotive)
1598
+ {
1599
+ tempDPLeads.Insert(tempDPLeads.IndexOf(locoCar), LeadLocomotive);
1600
+ tempDPLeads.Remove(locoCar);
1601
+ break; // foreach doesn't like it when the collection is modified during the loop, break to mitigate error
1602
+ }
1603
+ }
1604
+
1605
+ DPLeadUnits = tempDPLeads;
1606
+
1607
+ foreach (TrainCar loco in DPLeadUnits)
1608
+ {
1609
+ // Find all locomotives connected to each DP unit
1610
+ tempLocoGroups.Add(DetermineLocomotiveGroup(loco));
1611
+ }
1612
+
1613
+ LocoGroups = tempLocoGroups;
1543
1614
}
1544
1615
1545
1616
/// <summary>
@@ -4231,6 +4302,127 @@ public TrainCar FindLeadLocomotive()
4231
4302
return null;
4232
4303
}
4233
4304
4305
+ //================================================================================================//
4306
+ /// <summary>
4307
+ /// Find connected locomotives
4308
+ /// <\summary>
4309
+
4310
+ // Finds all locomotives connected to the TrainCar reference provided as input,
4311
+ // returning the connected locomotives* as a list of TrainCars.
4312
+ // Returns null if there are no locomotives in the given group.
4313
+ // *If the input is a steam locomotive, the output will instead be the steam locomotive and any tenders connected.
4314
+ // Useful for determining locomotive brake propagation on groups of locomotives other than the lead group.
4315
+
4316
+ public List<TrainCar> DetermineLocomotiveGroup(TrainCar loco)
4317
+ {
4318
+ if (loco is MSTSLocomotive)
4319
+ {
4320
+ List<TrainCar> tempGroup = new List<TrainCar>();
4321
+ int first;
4322
+ int last;
4323
+
4324
+ first = last = Cars.IndexOf(loco);
4325
+
4326
+ // If locomotive is a steam locomotive, check for tenders only
4327
+ if (first >= 0 && loco is MSTSSteamLocomotive)
4328
+ {
4329
+ if (last < Cars.Count - 1 && !loco.Flipped && Cars[last + 1].WagonType == TrainCar.WagonTypes.Tender)
4330
+ last++;
4331
+ else if (first > 0 && loco.Flipped && Cars[first - 1].WagonType == TrainCar.WagonTypes.Tender)
4332
+ first--;
4333
+ }
4334
+ else // Other locomotive types
4335
+ {
4336
+ for (int i = last; i < Cars.Count && (Cars[i] is MSTSLocomotive && !(Cars[i] is MSTSSteamLocomotive)); i++)
4337
+ last = i;
4338
+ for (int i = first; i >= 0 && (Cars[i] is MSTSLocomotive && !(Cars[i] is MSTSSteamLocomotive)); i--)
4339
+ first = i;
4340
+ }
4341
+
4342
+ if (first < 0 || last < 0)
4343
+ return null;
4344
+ else
4345
+ {
4346
+ for (int i = first; i <= last; i++)
4347
+ tempGroup.Add(Cars[i]);
4348
+ return tempGroup;
4349
+ }
4350
+ }
4351
+ else
4352
+ return null;
4353
+ }
4354
+
4355
+ //================================================================================================//
4356
+ /// <summary>
4357
+ /// Find connected DP lead locomotive
4358
+ /// <\summary>
4359
+
4360
+ // Finds the DP lead locomotive to the TrainCar reference provided as input,
4361
+ // returning the TrainCar reference to the DP lead unit.
4362
+ // Returns null if there are no DP lead units controlling the given train car.
4363
+
4364
+ public TrainCar DetermineDPLeadLocomotive(TrainCar locoCar)
4365
+ {
4366
+ if (Cars.Contains(locoCar) && locoCar is MSTSLocomotive loco)
4367
+ foreach (TrainCar dpLead in DPLeadUnits)
4368
+ if (dpLead is MSTSLocomotive dpLeadLoco && dpLeadLoco.DPUnitID == loco.DPUnitID)
4369
+ return dpLead;
4370
+
4371
+ return null;
4372
+ }
4373
+
4374
+ //================================================================================================//
4375
+ /// <summary>
4376
+ /// Find compatibility of DP connection between two locomotives
4377
+ /// <\summary>
4378
+
4379
+ // Returns a score judging the compatibility of a lead locomotive (first input as a TrainCar)
4380
+ // and remote locomotive (second input as a TrainCar). The more capabilities the two locomotives
4381
+ // share, the higher the number returned. There is an additional slight bias for remote
4382
+ // locomotives having higher capabilities than the lead locomotive.
4383
+ // Returns -1 if one of the input TrainCars isn't a locomotive
4384
+
4385
+ public float DetermineDPCompatibility(TrainCar leadCar, TrainCar remoteCar)
4386
+ {
4387
+ float score = 0;
4388
+
4389
+ if (leadCar is MSTSLocomotive lead && remoteCar is MSTSLocomotive remote)
4390
+ {
4391
+ if (remote.DPSyncTrainApplication)
4392
+ {
4393
+ if (lead.DPSyncTrainApplication)
4394
+ score++;
4395
+ else
4396
+ score += 0.1f;
4397
+ }
4398
+ if (remote.DPSyncTrainRelease)
4399
+ {
4400
+ if (lead.DPSyncTrainRelease)
4401
+ score++;
4402
+ else
4403
+ score += 0.1f;
4404
+ }
4405
+ if (remote.DPSyncEmergency)
4406
+ {
4407
+ if (lead.DPSyncEmergency)
4408
+ score++;
4409
+ else
4410
+ score += 0.1f;
4411
+ }
4412
+ if (remote.DPSyncIndependent)
4413
+ {
4414
+ if (lead.DPSyncIndependent)
4415
+ score++;
4416
+ else
4417
+ score += 0.1f;
4418
+ }
4419
+
4420
+ return score;
4421
+ }
4422
+ else
4423
+ return -1;
4424
+ }
4425
+
4234
4426
//================================================================================================//
4235
4427
/// <summary>
4236
4428
/// Propagate brake pressure
0 commit comments