Skip to content

Commit acf84b8

Browse files
committed
Blueprint https://blueprints.launchpad.net/or/+spec/distributed-power : manual rebase from Peter Gulyas' work plus change of key assignments
1 parent 4830217 commit acf84b8

File tree

18 files changed

+715
-52
lines changed

18 files changed

+715
-52
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,18 +2031,82 @@ Some of the cab monitoring gauges provide visibility of what is happening on the
20312031
the "closest" powered car near the Control car and uses its information.
20322032

20332033

2034-
Engines -- Multiple Units in Same Consist or AI Engines
2035-
=======================================================
2036-
2037-
In an OR player train one locomotive is controlled by the player, while
2038-
the other units are controlled by default by the train's MU (multiple
2039-
unit) signals for braking and throttle position, etc. The
2040-
player-controlled locomotive generates the MU signals which are passed
2041-
along to every unit in the train. For AI trains, the AI software directly
2042-
generates the MU signals, i.e. there is no player-controlled locomotive.
2034+
Multiple Units of Locomotives in Same Consist
2035+
=============================================
2036+
2037+
In an OR player train one locomotive is controlled by the player, while
2038+
the other units are controlled by default by the train's MU (multiple
2039+
unit) signals for braking and throttle position, etc. The
2040+
player-controlled locomotive generates the MU signals which are passed
2041+
along to every unit in the train.
2042+
2043+
Distributed Power
2044+
-----------------
2045+
2046+
Remote engines can be controlled in two modes: *synchronous* or
2047+
*asynchronous*. Engines in the player consist can be arranged to be part of
2048+
one of the above control groups. The arrangement can be changed during run,
2049+
which in real life is performed by using the locomotive's onboard computer
2050+
(e.g. Locotrol).
2051+
2052+
This functionality is necessary to be used in American long-train freight
2053+
operations. An example use case is when a train finished climbing a
2054+
mountain pass. At this point the lead locomotives have to start dynamic
2055+
braking driving downhill, while the trailing unit still needs to keep pushing
2056+
the train's end uphill. The locomotive driver has the possibility to build
2057+
the *fence up*, i.e. move the last locomotive to the *async* control group.
2058+
2059+
While locomotives in *sync* control group always copy the traction and dynamic
2060+
brake settings of the lead (man-controlled) locomotive, for locomotives in
2061+
*async* group these can be adjusted independently. Other controls, like
2062+
reverser and air brake is always synchronized throughout the whole train,
2063+
and changing reverser setting or applying air brakes will force *async*
2064+
controlled locomotives to fall back to idle.
2065+
2066+
The fence between *sync* and *async* groups can be moved back and forth
2067+
along the train. This is useful when there are one or more middle-train
2068+
locomotive groups in the consist. However it is not possible to move the
2069+
fence to separate two directly interconnected locomotives: such locomotives
2070+
can be rearranged only together. The lead locomotive group, naturally, will
2071+
always belong to *sync* group.
2072+
2073+
When all locomotive groups had been moved back to *sync* group, then the
2074+
driver dismantled the *fence down*, all locomotives will work in sync with
2075+
the leading one. All-sync operation is also the default, when the game
2076+
starts.
2077+
2078+
Traction and dynamic brake settings for *sync* group can be controlled by the
2079+
usual keys: ``<A>`` and ``<D>``. The following additional controls are
2080+
available for controlling the *async* group settings:
2081+
2082+
- Move To Back -- ``<Ctrl+Shift+O>``: Move one locomotive group to back (*async*)
2083+
control group.
2084+
- Move To Front -- ``<Ctrl+O>``: Move one locomotive group to front (*sync*)
2085+
control group.
2086+
- Traction -- ``<Ctrl+L>``: Switch *async* group to traction mode.
2087+
- Idle -- ``<Ctrl+Shift+'> (key two positions at the right of L)``: Switch *async*
2088+
group to dynamic braking mode.
2089+
- More -- ``<Ctrl+U>``: Increase *async* group traction or dynamic brake,
2090+
depending on its mode setting.
2091+
- Less -- ``<Ctrl+Shift+U>``: Decrease *async* group traction or dynamic brake,
2092+
depending on its mode setting.
2093+
2094+
HUD shows the sync--async configuration in line *Multiple Units* on main page.
2095+
When it reads e.g. "2--2 | 1", then it means that front and middle-train
2096+
double-unit locomotives are controlled in *sync* with the leading unit,
2097+
while the trailing pushing unit is controlled *async* independently.
2098+
The set actual rate of traction or dynamic brake of *async* group is shown in
2099+
lines *Throttle* and *Dynamic Brake*, respectively, in brackets, e.g.:
2100+
Throttle: 0% (50%)
2101+
2102+
Engines of AI Trains
2103+
--------------------
2104+
2105+
For AI trains, the AI software directly generates the remote control
2106+
signals, i.e. there is no player-controlled locomotive.
20432107
In this way, all engines use the same physics code for power and friction.
20442108

2045-
This software model will ensure that non-player controlled engines will
2109+
This software model will ensure that non-player controlled engines will
20462110
behave exactly the same way as player controlled ones.
20472111

20482112
.. _physics-braking:

Source/ORTS.Common/Input/UserCommand.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,5 +210,14 @@ public enum UserCommand
210210
[GetString("Control AI Fire On")] ControlAIFireOn,
211211
[GetString("Control AI Fire Off")] ControlAIFireOff,
212212
[GetString("Control AI Fire Reset")] ControlAIFireReset,
213+
214+
//Distributed power
215+
[GetString("Control DP Move To Front")] ControlDPMoveToFront,
216+
[GetString("Control DP Move To Back")] ControlDPMoveToBack,
217+
[GetString("Control DP Traction")] ControlDPTraction,
218+
[GetString("Control DP Idle")] ControlDPIdle,
219+
[GetString("Control DP Brake")] ControlDPBrake,
220+
[GetString("Control DP More")] ControlDPMore,
221+
[GetString("Control DP Less")] ControlDPLess,
213222
}
214223
}

Source/ORTS.Settings/InputSettings.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,14 @@ static void InitializeCommands(UserCommandInput[] Commands)
436436

437437
Commands[(int)UserCommand.ControlWaterScoop] = new UserCommandKeyInput(0x15);
438438
Commands[(int)UserCommand.ControlWiper] = new UserCommandKeyInput(0x2F);
439+
// Distributed power
440+
Commands[(int)UserCommand.ControlDPMoveToFront] = new UserCommandKeyInput(0x18, KeyModifiers.Control); //O
441+
Commands[(int)UserCommand.ControlDPMoveToBack] = new UserCommandKeyInput(0x18, KeyModifiers.Control | KeyModifiers.Shift); //O
442+
Commands[(int)UserCommand.ControlDPTraction] = new UserCommandKeyInput(0x26, KeyModifiers.Control); //L
443+
Commands[(int)UserCommand.ControlDPIdle] = new UserCommandKeyInput(0x26, KeyModifiers.Control | KeyModifiers.Shift); //L
444+
Commands[(int)UserCommand.ControlDPBrake] = new UserCommandKeyInput(0x28, KeyModifiers.Control); //
445+
Commands[(int)UserCommand.ControlDPMore] = new UserCommandKeyInput(0x16, KeyModifiers.Control); //U
446+
Commands[(int)UserCommand.ControlDPLess] = new UserCommandKeyInput(0x16, KeyModifiers.Control | KeyModifiers.Shift); //U
439447

440448
Commands[(int)UserCommand.DebugClockBackwards] = new UserCommandKeyInput(0x0C);
441449
Commands[(int)UserCommand.DebugClockForwards] = new UserCommandKeyInput(0x0D);

Source/Orts.Simulation/Common/Commands.cs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,134 @@ public override string ToString()
13111311
}
13121312
}
13131313

1314+
// Distributed Power controls
1315+
[Serializable()]
1316+
public sealed class DPMoveToFrontCommand : Command
1317+
{
1318+
public static MSTSWagon Receiver { get; set; }
1319+
1320+
public DPMoveToFrontCommand(CommandLog log)
1321+
: base(log)
1322+
{
1323+
Redo();
1324+
}
1325+
1326+
public override void Redo()
1327+
{
1328+
Receiver.Train.DPMoveToFront();
1329+
// Report();
1330+
}
1331+
}
1332+
1333+
[Serializable()]
1334+
public sealed class DPMoveToBackCommand : Command
1335+
{
1336+
public static MSTSWagon Receiver { get; set; }
1337+
1338+
public DPMoveToBackCommand(CommandLog log)
1339+
: base(log)
1340+
{
1341+
Redo();
1342+
}
1343+
1344+
public override void Redo()
1345+
{
1346+
Receiver.Train.DPMoveToBack();
1347+
// Report();
1348+
}
1349+
}
1350+
1351+
[Serializable()]
1352+
public sealed class DPIdleCommand : Command
1353+
{
1354+
public static MSTSWagon Receiver { get; set; }
1355+
1356+
public DPIdleCommand(CommandLog log)
1357+
: base(log)
1358+
{
1359+
Redo();
1360+
}
1361+
1362+
public override void Redo()
1363+
{
1364+
Receiver.Train.DPIdle();
1365+
// Report();
1366+
}
1367+
}
1368+
1369+
[Serializable()]
1370+
public sealed class DPTractionCommand : Command
1371+
{
1372+
public static MSTSWagon Receiver { get; set; }
1373+
1374+
public DPTractionCommand(CommandLog log)
1375+
: base(log)
1376+
{
1377+
Redo();
1378+
}
1379+
1380+
public override void Redo()
1381+
{
1382+
Receiver.Train.DPTraction();
1383+
// Report();
1384+
}
1385+
}
1386+
1387+
[Serializable()]
1388+
public sealed class DPDynamicBrakeCommand : Command
1389+
{
1390+
public static MSTSWagon Receiver { get; set; }
1391+
1392+
public DPDynamicBrakeCommand(CommandLog log)
1393+
: base(log)
1394+
{
1395+
Redo();
1396+
}
1397+
1398+
public override void Redo()
1399+
{
1400+
Receiver.Train.DPDynamicBrake();
1401+
// Report();
1402+
}
1403+
}
1404+
1405+
[Serializable()]
1406+
public sealed class DPMoreCommand : Command
1407+
{
1408+
public static MSTSWagon Receiver { get; set; }
1409+
1410+
public DPMoreCommand(CommandLog log)
1411+
: base(log)
1412+
{
1413+
Redo();
1414+
}
1415+
1416+
public override void Redo()
1417+
{
1418+
Receiver.Train.DPMore();
1419+
// Report();
1420+
}
1421+
}
1422+
1423+
[Serializable()]
1424+
public sealed class DPLessCommand : Command
1425+
{
1426+
public static MSTSWagon Receiver { get; set; }
1427+
1428+
public DPLessCommand(CommandLog log)
1429+
: base(log)
1430+
{
1431+
Redo();
1432+
}
1433+
1434+
public override void Redo()
1435+
{
1436+
Receiver.Train.DPLess();
1437+
// Report();
1438+
}
1439+
}
1440+
1441+
13141442
// Steam controls
13151443
[Serializable()]
13161444
public sealed class ContinuousSteamHeatCommand : ContinuousCommand

Source/Orts.Simulation/Simulation/AIs/AI.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ public AITrain CreateAITrainDetail(Service_Definition sd, Traffic_Service_Defini
961961
#endif
962962
train.CreateRoute(false); // create route without use of FrontTDBtraveller
963963
train.CheckFreight(); // check if train is freight or passenger
964+
train.SetDPUnitIDs(); // distributed power
964965
if (!isInitialPlayerTrain || train.InitialSpeed != 0) train.AITrainDirectionForward = true;
965966
train.BrakeLine3PressurePSI = 0;
966967

0 commit comments

Comments
 (0)