diff --git a/Source/Documentation/Manual/driving.rst b/Source/Documentation/Manual/driving.rst index f94175da9..ff82ae80e 100644 --- a/Source/Documentation/Manual/driving.rst +++ b/Source/Documentation/Manual/driving.rst @@ -1411,7 +1411,8 @@ Changing the Train Driven by the Player General ------- -This function only works in activity mode, and allows the player to select +This function works in activity mode as well as in timetable mode, +and allows the player to select another (existing) train from a list and to start driving it. This function can be called more than once. A new information window has @@ -1453,9 +1454,11 @@ completely appeared on the screen - if it is far away from the player train this can require several seconds to load the *world* around the train) the switch of control occurs. -The AI train string now becomes red and is moved to the first position.The -train can be driven, or set to autopilot mode. The former player train -becomes an AI train. +The AI train string now becomes red and is moved to the first position. +In timetable mode the new player train is automatically set to autopilot mode, +while this does not apply to activity mode. However in both timetable and +activity mode the player can switch forth and back to autopilot mode. +The former player train becomes an AI train. Here is the final situation: @@ -1463,7 +1466,8 @@ Here is the final situation: :align: center :scale: 80% -If the second left-click was performed with the Shift key down, the former +In activity mode only, if the second left-click was performed with the Shift +key down, the former player train still becomes an AI train, but it is put in a suspended mode (only if its speed is 0). It won't move until it becomes a player train again. A suspended train is shown in orange color on the Train List window. @@ -1472,7 +1476,8 @@ The new player train can can be switched to manual mode, can also request to pass signals at danger with the ```` command, and can be moved outside of its original path. However before switching control to still another train, the new player train must be returned to the original path or put in suspend -mode; or else it will disappear, as occurs for AI trains running outside their +mode (last is possible only in activity mode); or else it will disappear, +as occurs for AI trains running outside their path. The sequence may be restarted to switch to a new train or to switch back to @@ -1482,15 +1487,9 @@ Train switching also works in activity mode together with multiplayer mode, in the sense that the dispatcher player can switch its played train, and the related information is sent to the client players. -The Train List window is also available in -:ref:`Timetable mode `. In this case the -names of all trains except the player train are shown in white (they can't -be driven), however with a single click on a train in the window the -external view cameras become linked to that train, as occurs with the Alt-9 -command described :ref:`further below `. -Switching to a static train ---------------------------- +Switching to a static train (only activity mode) +------------------------------------------------ In the Train List window the drivable static consists (that is the ones that have at least an engine provided with a cab) are also listed (in diff --git a/Source/Orts.Simulation/Simulation/Simulator.cs b/Source/Orts.Simulation/Simulation/Simulator.cs index 5fab6bcb5..222ec0efd 100644 --- a/Source/Orts.Simulation/Simulation/Simulator.cs +++ b/Source/Orts.Simulation/Simulation/Simulator.cs @@ -1921,6 +1921,13 @@ private void StartSwitchPlayerTrain() var playerTrain = PlayerLocomotive.Train as AITrain; if (playerTrain != null) { + if (TimetableMode && playerTrain.ControlMode == Train.TRAIN_CONTROL.MANUAL) + { + Confirmer.Message(ConfirmLevel.Warning, Catalog.GetString("Train can't be switched if in manual mode")); + TrainSwitcher.SuspendOldPlayer = false; + TrainSwitcher.ClickedSelectedAsPlayer = false; + return; + } if (playerTrain.ControlMode == Train.TRAIN_CONTROL.MANUAL) TrainSwitcher.SuspendOldPlayer = true; // force suspend state to avoid disappearing of train; if (TrainSwitcher.SuspendOldPlayer && (playerTrain.SpeedMpS < -0.025 || playerTrain.SpeedMpS > 0.025 || playerTrain.PresentPosition[0].TCOffset != playerTrain.PreviousPosition[0].TCOffset)) @@ -1930,14 +1937,14 @@ private void StartSwitchPlayerTrain() TrainSwitcher.ClickedSelectedAsPlayer = false; return; } - if (playerTrain.TrainType == Train.TRAINTYPE.AI_PLAYERDRIVEN) + if (playerTrain.TrainType == Train.TRAINTYPE.AI_PLAYERDRIVEN || !playerTrain.Autopilot) { // it must be autopiloted first playerTrain.SwitchToAutopilotControl(); } // and now switch! playerTrain.TrainType = Train.TRAINTYPE.AI; - AI.AITrains.Add(playerTrain); + playerTrain.Autopilot = false; if (TrainSwitcher.SuspendOldPlayer) { playerTrain.MovementState = AITrain.AI_MOVEMENT_STATE.SUSPENDED; @@ -2089,6 +2096,18 @@ private void StartSwitchPlayerTrain() PlayerLocomotive = SetPlayerLocomotive(pathlessPlayerTrain); if (oldPlayerTrain != null) oldPlayerTrain.LeadLocomotiveIndex = -1; } + if (TimetableMode) + { + // In timetable mode player train must have number 0 + (PlayerLocomotive.Train.Number, oldPlayerTrain.Number) = (oldPlayerTrain.Number, PlayerLocomotive.Train.Number); + var oldPlayerTrainIndex = Trains.IndexOf(oldPlayerTrain); + var playerTrainIndex = Trains.IndexOf(PlayerLocomotive.Train); + (Trains[oldPlayerTrainIndex], Trains[playerTrainIndex]) = (Trains[playerTrainIndex], Trains[oldPlayerTrainIndex]); + var index = AI.AITrains.IndexOf(PlayerLocomotive.Train as AITrain); + (AI.AITrains[0], AI.AITrains[index]) = (AI.AITrains[index], AI.AITrains[0]); + AI.aiListChanged = true; + PlayerLocomotive.Train.Autopilot = true; + } playerSwitchOngoing = true; if (MPManager.IsMultiPlayer()) { @@ -2107,19 +2126,25 @@ private void CompleteSwitchPlayerTrain() { if (PlayerLocomotive.Train.TrainType != Train.TRAINTYPE.STATIC) { - AI.AITrains.Remove(PlayerLocomotive.Train as AITrain); + if (!TimetableMode) + AI.AITrains.Remove(PlayerLocomotive.Train as AITrain); if ((PlayerLocomotive.Train as AITrain).MovementState == AITrain.AI_MOVEMENT_STATE.SUSPENDED) { PlayerLocomotive.Train.Reinitialize(); (PlayerLocomotive.Train as AITrain).MovementState = Math.Abs(PlayerLocomotive.Train.SpeedMpS) <= MaxStoppedMpS ? AITrain.AI_MOVEMENT_STATE.INIT : AITrain.AI_MOVEMENT_STATE.BRAKING; } - (PlayerLocomotive.Train as AITrain).SwitchToPlayerControl(); + if (!TimetableMode) + (PlayerLocomotive.Train as AITrain).SwitchToPlayerControl(); + else + PlayerLocomotive.Train.DisplayMessage = ""; } else { PlayerLocomotive.Train.CreatePathlessPlayerTrain(); } + var playerLocomotive = PlayerLocomotive as MSTSLocomotive; + playerLocomotive.UsingRearCab = (PlayerLocomotive.Flipped ^ PlayerLocomotive.Train.MUDirection == Direction.Reverse) && (playerLocomotive.HasRearCab || playerLocomotive.HasRear3DCab); OnPlayerLocomotiveChanged(); playerSwitchOngoing = false; TrainSwitcher.ClickedSelectedAsPlayer = false; diff --git a/Source/RunActivity/Viewer3D/Popups/TrainListWindow.cs b/Source/RunActivity/Viewer3D/Popups/TrainListWindow.cs index abef61950..c3a7f884b 100644 --- a/Source/RunActivity/Viewer3D/Popups/TrainListWindow.cs +++ b/Source/RunActivity/Viewer3D/Popups/TrainListWindow.cs @@ -91,7 +91,7 @@ protected override ControlLayout Layout(ControlLayout layout) line.Add(viewed = new TrainLabel(Owner.TextFontDefault.Height, line.RemainingHeight, Owner.Viewer, thisTrain, "*", LabelAlignment.Right)); viewed.Color = Color.Red; } - if (Owner.Viewer.Simulator.IsAutopilotMode && !Owner.Viewer.Simulator.TimetableMode) + if (Owner.Viewer.Simulator.IsAutopilotMode) { number.Color = thisTrain.IsPlayable ? Color.LightGreen : Color.White; name.Color = thisTrain.IsPlayable ? Color.LightGreen : Color.White; @@ -110,7 +110,7 @@ protected override ControlLayout Layout(ControlLayout layout) } // Now list static trains with loco and cab - if (Owner.Viewer.Simulator.IsAutopilotMode && !Owner.Viewer.Simulator.TimetableMode) + if (Owner.Viewer.Simulator.IsAutopilotMode) { foreach (var thisTrain in Owner.Viewer.Simulator.Trains) { @@ -181,7 +181,7 @@ void TrainListLabel_Click(Control arg1, Point arg2) } if (PickedTrainFromList != null && (PickedTrainFromList == Viewer.SelectedTrain || (PickedTrainFromList.TrainType == Train.TRAINTYPE.AI_INCORPORATED && (PickedTrainFromList as AITrain).IncorporatingTrain.IsPathless && (PickedTrainFromList as AITrain).IncorporatingTrain == Viewer.SelectedTrain)) && !PickedTrainFromList.IsActualPlayerTrain && - Viewer.Simulator.IsAutopilotMode && PickedTrainFromList.IsPlayable && !Viewer.Simulator.TimetableMode) + Viewer.Simulator.IsAutopilotMode && PickedTrainFromList.IsPlayable && !(Viewer.Simulator.TimetableMode && (Viewer.PlayerTrain as AITrain).MovementState == AITrain.AI_MOVEMENT_STATE.AI_STATIC)) { if (UserInput.IsDown(UserCommand.GameSuspendOldPlayer) && !Viewer.Simulator.TimetableMode) Viewer.Simulator.TrainSwitcher.SuspendOldPlayer = true; diff --git a/Source/RunActivity/Viewer3D/Processes/GameStateRunActivity.cs b/Source/RunActivity/Viewer3D/Processes/GameStateRunActivity.cs index 1f04a6d2d..019f2da4d 100644 --- a/Source/RunActivity/Viewer3D/Processes/GameStateRunActivity.cs +++ b/Source/RunActivity/Viewer3D/Processes/GameStateRunActivity.cs @@ -1145,6 +1145,7 @@ void InitSimulator(UserSettings settings, string[] args, string mode, string act // for resume and replay : set timetable file and selected train info Simulator.TimetableFileName = System.IO.Path.GetFileNameWithoutExtension(args[0]); Simulator.PathName = args[1]; + Simulator.IsAutopilotMode = true; } break; }