diff --git a/Source/ORTS.Common/Input/UserCommand.cs b/Source/ORTS.Common/Input/UserCommand.cs
index b86dc2bd61..8e1a8bb5af 100644
--- a/Source/ORTS.Common/Input/UserCommand.cs
+++ b/Source/ORTS.Common/Input/UserCommand.cs
@@ -163,6 +163,8 @@ public enum UserCommand
[GetString("Control Pantograph 2")] ControlPantograph2,
[GetString("Control Pantograph 3")] ControlPantograph3,
[GetString("Control Pantograph 4")] ControlPantograph4,
+ [GetString("Control Window Left")] ControlWindowLeft,
+ [GetString("Control Window Right")] ControlWindowRight,
[GetString("Control Battery Close")] ControlBatterySwitchClose,
[GetString("Control Battery Open")] ControlBatterySwitchOpen,
[GetString("Control Master Key")] ControlMasterKey,
diff --git a/Source/ORTS.Settings/InputSettings.cs b/Source/ORTS.Settings/InputSettings.cs
index af82b2874c..b9fa35eda4 100644
--- a/Source/ORTS.Settings/InputSettings.cs
+++ b/Source/ORTS.Settings/InputSettings.cs
@@ -374,6 +374,8 @@ static void InitializeCommands(UserCommandInput[] Commands)
Commands[(int)UserCommand.ControlDieselPlayer] = new UserCommandKeyInput(0x15, KeyModifiers.Shift);
Commands[(int)UserCommand.ControlDoorLeft] = new UserCommandKeyInput(0x10);
Commands[(int)UserCommand.ControlDoorRight] = new UserCommandKeyInput(0x10, KeyModifiers.Shift);
+ Commands[(int)UserCommand.ControlWindowLeft] = new UserCommandKeyInput(0x10, KeyModifiers.Control);
+ Commands[(int)UserCommand.ControlWindowRight] = new UserCommandKeyInput(0x10, KeyModifiers.Control | KeyModifiers.Shift);
Commands[(int)UserCommand.ControlDynamicBrakeDecrease] = new UserCommandKeyInput(0x33);
Commands[(int)UserCommand.ControlDynamicBrakeIncrease] = new UserCommandKeyInput(0x34);
Commands[(int)UserCommand.ControlElectricTrainSupply] = new UserCommandKeyInput(0x30, KeyModifiers.Alt);
diff --git a/Source/Orts.Formats.Msts/CabViewFile.cs b/Source/Orts.Formats.Msts/CabViewFile.cs
index 67d0a1df90..3f6100d758 100644
--- a/Source/Orts.Formats.Msts/CabViewFile.cs
+++ b/Source/Orts.Formats.Msts/CabViewFile.cs
@@ -184,6 +184,8 @@ public enum CABViewControlTypes
ORTS_MIRRORS,
ORTS_PANTOGRAPH3,
ORTS_PANTOGRAPH4,
+ ORTS_LEFTWINDOW,
+ ORTS_RIGHTWINDOW,
ORTS_LARGE_EJECTOR,
ORTS_WATER_SCOOP,
ORTS_HOURDIAL,
@@ -206,6 +208,8 @@ public enum CABViewControlTypes
ORTS_ELECTRIC_TRAIN_SUPPLY_COMMAND_SWITCH,
ORTS_ELECTRIC_TRAIN_SUPPLY_ON,
ORTS_2DEXTERNALWIPERS,
+ ORTS_2DEXTERNALLEFTWINDOW,
+ ORTS_2DEXTERNALRIGHTWINDOW,
ORTS_GENERIC_ITEM1,
ORTS_GENERIC_ITEM2,
ORTS_SCREEN_SELECT,
@@ -273,6 +277,10 @@ public enum CABViewControlTypes
ORTS_ITEM2CONTINUOUS,
ORTS_ITEM1TWOSTATE,
ORTS_ITEM2TWOSTATE,
+ ORTS_EXTERNALLEFTWINDOWFRONT,
+ ORTS_EXTERNALRIGHTWINDOWFRONT,
+ ORTS_EXTERNALLEFTWINDOWREAR,
+ ORTS_EXTERNALRIGHTWINDOWREAR,
}
public enum CABViewControlStyles
diff --git a/Source/Orts.Simulation/Common/Commands.cs b/Source/Orts.Simulation/Common/Commands.cs
index 5e47dc944a..f9b61c0557 100644
--- a/Source/Orts.Simulation/Common/Commands.cs
+++ b/Source/Orts.Simulation/Common/Commands.cs
@@ -1243,6 +1243,47 @@ public override void Redo()
}
}
+ [Serializable()]
+ public sealed class ToggleWindowLeftCommand : Command
+ {
+ public static MSTSWagon Receiver { get; set; }
+
+ public ToggleWindowLeftCommand(CommandLog log)
+ : base(log)
+ {
+ Redo();
+ }
+
+ public override void Redo()
+ {
+ if (Receiver is MSTSLocomotive locomotive && locomotive.UsingRearCab)
+ locomotive.ToggleWindow(rear: true, left: false);
+ else
+ Receiver.ToggleWindow(rear: false, left: true);
+ }
+ }
+
+ [Serializable()]
+ public sealed class ToggleWindowRightCommand : Command
+ {
+ public static MSTSWagon Receiver { get; set; }
+
+ public ToggleWindowRightCommand(CommandLog log)
+ : base(log)
+ {
+ Redo();
+ }
+
+ public override void Redo()
+ {
+ if (Receiver is MSTSLocomotive locomotive && locomotive.UsingRearCab)
+ locomotive.ToggleWindow(rear: true, left: true);
+ else
+ Receiver.ToggleWindow(rear: false, left: false);
+ }
+ }
+
+
[Serializable()]
public sealed class ToggleBatterySwitchCommand : BooleanCommand
{
diff --git a/Source/Orts.Simulation/Common/Events.cs b/Source/Orts.Simulation/Common/Events.cs
index a1cce35972..f7d5c4d700 100644
--- a/Source/Orts.Simulation/Common/Events.cs
+++ b/Source/Orts.Simulation/Common/Events.cs
@@ -198,6 +198,10 @@ public enum Event
VigilanceAlarmReset,
WaterScoopDown,
WaterScoopUp,
+ WindowClosing,
+ WindowOpening,
+ WindowsClosed,
+ WindowsOpen,
WiperOff,
WiperOn,
_HeadlightDim,
@@ -526,6 +530,11 @@ public static Event From(Source source, int eventID)
case 251: return Event.OverchargeBrakingOff;
case 252: return Event.EmergencyVentValveOn;
+ case 260: return Event.WindowClosing;
+ case 261: return Event.WindowOpening;
+ case 262: return Event.WindowsClosed;
+ case 263: return Event.WindowsOpen;
+
// Cruise Control
case 298: return Event.LeverFromZero;
case 299: return Event.LeverToZero;
diff --git a/Source/Orts.Simulation/Simulation/Confirmer.cs b/Source/Orts.Simulation/Simulation/Confirmer.cs
index 406eaafdd0..b5b07eb59b 100644
--- a/Source/Orts.Simulation/Simulation/Confirmer.cs
+++ b/Source/Orts.Simulation/Simulation/Confirmer.cs
@@ -107,6 +107,8 @@ public enum CabControl {
, DoorsLeft
, DoorsRight
, Mirror
+ , WindowLeft
+ , WindowRight
// Track Devices
, SwitchAhead
, SwitchBehind
@@ -243,7 +245,7 @@ public Confirmer(Simulator simulator, double defaultDurationS)
, new string [] { GetString("Bell"), GetString("off"), null, GetString("ring") }
, new string [] { GetString("Headlight"), GetString("off"), GetString("dim"), GetString("bright") }
, new string [] { GetString("Cab Light"), GetString("off"), null, GetString("on") }
- , new string [] { GetString("Wipers"), GetString("off"), null, GetString("on") }
+ , new string [] { GetString("Wipers"), GetString("off"), null, GetString("on") }
, new string [] { GetString("Cab"), null, null, GetParticularString("Cab", "change"), null, null, GetString("changing is not available"), GetString("changing disabled. Close throttle, set reverser to neutral, stop train then re-try.") }
, new string [] { GetString("Odometer"), null, null, GetParticularString("Odometer", "reset"), GetParticularString("Odometer", "counting down"), GetParticularString("Odometer", "counting up") }
, new string [] { GetString("Battery"), GetString("off"), null, GetString("on") }
@@ -254,7 +256,9 @@ public Confirmer(Simulator simulator, double defaultDurationS)
// Train Devices
, new string [] { GetString("Doors Left"), GetString("close"), null, GetString("open") }
, new string [] { GetString("Doors Right"), GetString("close"), null, GetString("open") }
- , new string [] { GetString("Mirror"), GetString("retract"), null, GetString("extend") }
+ , new string [] { GetString("Mirror"), GetString("retract"), null, GetString("extend") }
+ , new string [] { GetString("Window Left"), GetString("closing"), null, GetString("opening") }
+ , new string [] { GetString("Window Right"), GetString("closing"), null, GetString("opening") }
// Track Devices
, new string [] { GetString("Switch Ahead"), null, null, GetParticularString("Switch", "change"), null, null, GetString("locked. Use Control+M to change signals to manual mode then re-try.") }
, new string [] { GetString("Switch Behind"), null, null, GetParticularString("Switch", "change"), null, null, GetString("locked. Use Control+M to change signals to manual mode then re-try.") }
diff --git a/Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs b/Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs
index 10845b9914..e0bddf0c59 100644
--- a/Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs
+++ b/Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs
@@ -5722,6 +5722,16 @@ public virtual float GetDataOf(CabViewControl cvc)
data = state >= DoorState.Opening ? 1 : 0;
}
break;
+ case CABViewControlTypes.ORTS_LEFTWINDOW:
+ case CABViewControlTypes.ORTS_2DEXTERNALLEFTWINDOW:
+ data = UsingRearCab ? (WindowStates[RightWindowRearIndex] == WindowState.Closing || WindowStates[RightWindowRearIndex] == WindowState.Opening ? 1 : 0) :
+ (WindowStates[LeftWindowFrontIndex] == WindowState.Closing || WindowStates[LeftWindowFrontIndex] == WindowState.Opening ? 1 : 0);
+ break;
+ case CABViewControlTypes.ORTS_RIGHTWINDOW:
+ case CABViewControlTypes.ORTS_2DEXTERNALRIGHTWINDOW:
+ data = UsingRearCab ? (WindowStates[LeftWindowRearIndex] == WindowState.Closing || WindowStates[LeftWindowRearIndex] == WindowState.Opening ? 1 : 0) :
+ (WindowStates[RightWindowFrontIndex] == WindowState.Closing || WindowStates[RightWindowFrontIndex] == WindowState.Opening ? 1 : 0);
+ break;
case CABViewControlTypes.ORTS_MIRRORS:
data = MirrorOpen ? 1 : 0;
break;
diff --git a/Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs b/Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs
index f897bb10cb..a6a132d1e5 100644
--- a/Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs
+++ b/Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs
@@ -72,6 +72,23 @@ public class MSTSWagon : TrainCar
public Doors Doors;
public Door RightDoor => Doors.RightDoor;
public Door LeftDoor => Doors.LeftDoor;
+
+ public enum WindowState
+ // Don't change the order of entries within this enum
+ {
+ Closed,
+ Closing,
+ Opening,
+ Open,
+ }
+
+ public static int LeftWindowFrontIndex = 0;
+ public static int RightWindowFrontIndex = 1;
+ public static int LeftWindowRearIndex = 2;
+ public static int RightWindowRearIndex = 3;
+ public WindowState[] WindowStates = new WindowState[4];
+ public float[] SoundHeardInternallyCorrection = new float[2];
+
public bool MirrorOpen;
public bool UnloadingPartsOpen;
public bool WaitForAnimationReady; // delay counter to start loading/unliading is on;
@@ -1812,6 +1829,10 @@ public override void Save(BinaryWriter outf)
outf.Write(DerailPossible);
outf.Write(DerailExpected);
outf.Write(DerailElapsedTimeS);
+ for (int index = 0; index < 4; index++)
+ {
+ outf.Write((int)WindowStates[index]);
+ }
LocomotiveAxles.Save(outf);
@@ -1867,6 +1888,10 @@ public override void Restore(BinaryReader inf)
DerailPossible = inf.ReadBoolean();
DerailExpected = inf.ReadBoolean();
DerailElapsedTimeS = inf.ReadSingle();
+ for (int index = 0; index < 4; index++)
+ {
+ WindowStates[index] = (WindowState)inf.ReadInt32();
+ }
MoveParamsToAxle();
LocomotiveAxles.Restore(inf);
@@ -3496,6 +3521,22 @@ public void ToggleMirrors()
if (Simulator.PlayerLocomotive == this) Simulator.Confirmer.Confirm(CabControl.Mirror, MirrorOpen ? CabSetting.On : CabSetting.Off);
}
+ public void ToggleWindow(bool rear, bool left)
+ {
+ var open = false;
+ var index = (left ? 0 : 1) + 2 * (rear ? 1 : 0);
+ if (WindowStates[index] == WindowState.Closed || WindowStates[index] == WindowState.Closing)
+ WindowStates[index] = WindowState.Opening;
+ else if (WindowStates[index] == WindowState.Open || WindowStates[index] == WindowState.Opening)
+ WindowStates[index] = WindowState.Closing;
+ if (WindowStates[index] == WindowState.Opening) open = true;
+
+
+ if (open) SignalEvent(Event.WindowOpening); // hook for sound trigger
+ else SignalEvent(Event.WindowClosing);
+ if (Simulator.PlayerLocomotive == this) Simulator.Confirmer.Confirm(left ^ rear ? CabControl.WindowLeft : CabControl.WindowRight, open ? CabSetting.On : CabSetting.Off);
+ }
+
public void FindControlActiveLocomotive()
{
// Find the active locomotive associated with a control car
diff --git a/Source/Orts.Simulation/Simulation/Simulator.cs b/Source/Orts.Simulation/Simulation/Simulator.cs
index 33fb03cc51..6cc919077b 100644
--- a/Source/Orts.Simulation/Simulation/Simulator.cs
+++ b/Source/Orts.Simulation/Simulation/Simulator.cs
@@ -699,6 +699,8 @@ public void SetCommandReceivers()
ToggleDoorsLeftCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
ToggleDoorsRightCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
ToggleMirrorsCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
+ ToggleWindowLeftCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
+ ToggleWindowRightCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
CabRadioCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
ToggleHelpersEngineCommand.Receiver = (MSTSLocomotive)PlayerLocomotive;
BatterySwitchCommand.Receiver = (PlayerLocomotive as MSTSLocomotive).LocomotivePowerSupply;
diff --git a/Source/RunActivity/Viewer3D/AnimatedPart.cs b/Source/RunActivity/Viewer3D/AnimatedPart.cs
index e1507b31c9..3e16c8c639 100644
--- a/Source/RunActivity/Viewer3D/AnimatedPart.cs
+++ b/Source/RunActivity/Viewer3D/AnimatedPart.cs
@@ -160,6 +160,16 @@ public void UpdateState(bool state, ElapsedTime elapsedTime)
SetFrameClamp(AnimationKey + (state ? 1 : -1) * elapsedTime.ClockSeconds);
}
+ ///
+ /// Updates an animated part that toggles between two states and returns relative value of
+ /// animation key (between 0 and 1).
+ ///
+ public float UpdateAndReturnState(bool state, ElapsedTime elapsedTime)
+ {
+ SetFrameClamp(AnimationKey + (state ? 1 : -1) * elapsedTime.ClockSeconds);
+ return AnimationKey / FrameCount;
+ }
+
///
/// Updates an animated part that loops (e.g. running gear), changing by the given amount.
///
diff --git a/Source/RunActivity/Viewer3D/RollingStock/MSTSLocomotiveViewer.cs b/Source/RunActivity/Viewer3D/RollingStock/MSTSLocomotiveViewer.cs
index 6e61c1b62b..8c0fc5f5fb 100644
--- a/Source/RunActivity/Viewer3D/RollingStock/MSTSLocomotiveViewer.cs
+++ b/Source/RunActivity/Viewer3D/RollingStock/MSTSLocomotiveViewer.cs
@@ -2191,6 +2191,8 @@ public virtual int GetDrawIndex()
case CABViewControlTypes.LEFTDOOR:
case CABViewControlTypes.RIGHTDOOR:
case CABViewControlTypes.MIRRORS:
+ case CABViewControlTypes.ORTS_LEFTWINDOW:
+ case CABViewControlTypes.ORTS_RIGHTWINDOW:
case CABViewControlTypes.HORN:
case CABViewControlTypes.VACUUM_EXHAUSTER:
case CABViewControlTypes.WHISTLE:
@@ -2572,6 +2574,20 @@ public void HandleUserInput()
}
ButtonState = buttonState;
break;
+ case CABViewControlTypes.ORTS_LEFTWINDOW:
+ case CABViewControlTypes.ORTS_RIGHTWINDOW:
+ {
+ bool left = (Control.ControlType.Type == CABViewControlTypes.ORTS_LEFTWINDOW);
+ var windowIndex = (left ? 0 : 1) + 2 * (Locomotive.UsingRearCab ? 1 : 0);
+ var state = Locomotive.WindowStates[windowIndex];
+ int open = state >= MSTSWagon.WindowState.Opening ? 1 : 0;
+ if (open != ChangedValue(open))
+ {
+ if (left) new ToggleWindowLeftCommand(Viewer.Log);
+ else new ToggleWindowRightCommand(Viewer.Log);
+ }
+ }
+ break;
// Train Control System controls
case CABViewControlTypes.ORTS_TCS:
@@ -2860,7 +2876,10 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
if (animate)
AnimationOn = true;
- int index;
+ int index = 0;
+ switch (ControlDiscrete.ControlType.Type)
+ {
+ case CABViewControlTypes.ORTS_2DEXTERNALWIPERS:
var halfCycleS = CycleTimeS / 2f;
if (AnimationOn)
{
@@ -2874,9 +2893,61 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
else
index = PercentToIndex((CycleTimeS - CumulativeTime) / halfCycleS);
}
+ break;
+
+ case CABViewControlTypes.ORTS_2DEXTERNALLEFTWINDOW:
+ case CABViewControlTypes.ORTS_2DEXTERNALRIGHTWINDOW:
+ var windowIndex = Locomotive.UsingRearCab ? MSTSWagon.RightWindowRearIndex : MSTSWagon.LeftWindowFrontIndex;
+ var soundCorrectionIndex = windowIndex;
+ if (ControlDiscrete.ControlType.Type == CABViewControlTypes.ORTS_2DEXTERNALRIGHTWINDOW)
+ {
+ windowIndex = Locomotive.UsingRearCab ? MSTSWagon.LeftWindowRearIndex : MSTSWagon.RightWindowFrontIndex;
+ }
+ Locomotive.SoundHeardInternallyCorrection[soundCorrectionIndex] = 0;
+ if (AnimationOn)
+ {
+ CumulativeTime += elapsedTime.ClockSeconds;
+ if (CumulativeTime >= CycleTimeS)
+ {
+ AnimationOn = false;
+ CumulativeTime = CycleTimeS;
+ }
+ if (Locomotive.WindowStates[windowIndex] == MSTSWagon.WindowState.Opening)
+ {
+ index = PercentToIndex(CumulativeTime / CycleTimeS);
+ Locomotive.SoundHeardInternallyCorrection[soundCorrectionIndex] = CumulativeTime / CycleTimeS;
+ if (!AnimationOn)
+ {
+ Locomotive.WindowStates[windowIndex] = MSTSWagon.WindowState.Open;
+ CumulativeTime = 0;
+ }
+ }
else
{
- index = 0;
+ index = PercentToIndex((CycleTimeS - CumulativeTime) / CycleTimeS);
+ Locomotive.SoundHeardInternallyCorrection[soundCorrectionIndex] = (CycleTimeS - CumulativeTime) / CycleTimeS;
+ if (!AnimationOn)
+ {
+ Locomotive.WindowStates[windowIndex] = MSTSWagon.WindowState.Closed;
+ CumulativeTime = 0;
+ }
+ }
+ }
+ else
+ {
+ CumulativeTime = 0;
+ if (Locomotive.WindowStates[windowIndex] == MSTSWagon.WindowState.Open)
+ {
+ index = PercentToIndex(1);
+ Locomotive.SoundHeardInternallyCorrection[soundCorrectionIndex] = 1;
+ }
+ else
+ {
+ index = PercentToIndex(0);
+ Locomotive.SoundHeardInternallyCorrection[soundCorrectionIndex] = 0;
+ }
+ }
+ break;
}
PrepareFrameForIndex(frame, elapsedTime, index);
@@ -3254,6 +3325,10 @@ public ThreeDimentionCabViewer(Viewer viewer, MSTSLocomotive car, MSTSLocomotive
case CABViewControlTypes.ORTS_ITEM2CONTINUOUS:
case CABViewControlTypes.ORTS_ITEM1TWOSTATE:
case CABViewControlTypes.ORTS_ITEM2TWOSTATE:
+ case CABViewControlTypes.ORTS_EXTERNALLEFTWINDOWFRONT:
+ case CABViewControlTypes.ORTS_EXTERNALRIGHTWINDOWFRONT:
+ case CABViewControlTypes.ORTS_EXTERNALLEFTWINDOWREAR:
+ case CABViewControlTypes.ORTS_EXTERNALRIGHTWINDOWREAR:
//cvf file has no external wipers, left door, right door and mirrors key word
break;
default:
@@ -3334,6 +3409,8 @@ public override void HandleUserInput(ElapsedTime elapsedTime)
///
public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
{
+
+ Locomotive.SoundHeardInternallyCorrection[0] = Locomotive.SoundHeardInternallyCorrection[1] = 0;
foreach (var p in AnimateParts)
{
if (p.Value.Type.Type >= CABViewControlTypes.EXTERNALWIPERS) //for wipers, doors and mirrors
@@ -3354,6 +3431,18 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
case CABViewControlTypes.MIRRORS:
p.Value.UpdateState(Locomotive.MirrorOpen, elapsedTime);
break;
+ case CABViewControlTypes.ORTS_EXTERNALLEFTWINDOWFRONT:
+ PrepareFrameForWindow(MSTSWagon.LeftWindowFrontIndex, p.Value, elapsedTime);
+ break;
+ case CABViewControlTypes.ORTS_EXTERNALRIGHTWINDOWFRONT:
+ PrepareFrameForWindow(MSTSWagon.RightWindowFrontIndex, p.Value, elapsedTime);
+ break;
+ case CABViewControlTypes.ORTS_EXTERNALLEFTWINDOWREAR:
+ PrepareFrameForWindow(MSTSWagon.LeftWindowRearIndex, p.Value, elapsedTime);
+ break;
+ case CABViewControlTypes.ORTS_EXTERNALRIGHTWINDOWREAR:
+ PrepareFrameForWindow(MSTSWagon.RightWindowRearIndex, p.Value, elapsedTime);
+ break;
case CABViewControlTypes.ORTS_ITEM1CONTINUOUS:
p.Value.UpdateLoop(Locomotive.GenericItem1, elapsedTime);
break;
@@ -3462,6 +3551,19 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
TrainCarShape.ConditionallyPrepareFrame(frame, elapsedTime, MatrixVisible);
}
+ internal void PrepareFrameForWindow(int windowIndex, AnimatedPartMultiState anim, ElapsedTime elapsedTime)
+ {
+ if (Locomotive.WindowStates[windowIndex] == MSTSWagon.WindowState.Closed) anim.SetState(false);
+ else if (Locomotive.WindowStates[windowIndex] == MSTSWagon.WindowState.Open) anim.SetState(true);
+ var animationFraction = anim.UpdateAndReturnState(Locomotive.WindowStates[windowIndex] >= MSTSWagon.WindowState.Opening, elapsedTime);
+ if (animationFraction == 0 && Locomotive.WindowStates[windowIndex] < MSTSWagon.WindowState.Opening)
+ Locomotive.WindowStates[windowIndex] = MSTSWagon.WindowState.Closed;
+ else if (animationFraction == 1 && Locomotive.WindowStates[windowIndex] >= MSTSWagon.WindowState.Opening)
+ Locomotive.WindowStates[windowIndex] = MSTSWagon.WindowState.Open;
+ if (Locomotive.UsingRearCab ^ windowIndex < 2)
+ Locomotive.SoundHeardInternallyCorrection[windowIndex > 1 ? windowIndex - 2 : windowIndex] = animationFraction;
+ }
+
internal override void Mark()
{
TrainCarShape?.Mark();
diff --git a/Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs b/Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs
index 6341d4bef4..76d61071f7 100644
--- a/Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs
+++ b/Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs
@@ -70,6 +70,10 @@ public class MSTSWagonViewer : TrainCarViewer
AnimatedPart LeftDoor;
AnimatedPart RightDoor;
AnimatedPart Mirrors;
+ AnimatedPart LeftWindowFront;
+ AnimatedPart RightWindowFront;
+ AnimatedPart LeftWindowRear;
+ AnimatedPart RightWindowRear;
protected AnimatedPart Wipers;
protected AnimatedPart Bell;
protected AnimatedPart Item1Continuous;
@@ -321,6 +325,10 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
LeftDoor = new AnimatedPart(TrainCarShape);
RightDoor = new AnimatedPart(TrainCarShape);
Mirrors = new AnimatedPart(TrainCarShape);
+ LeftWindowFront = new AnimatedPart(TrainCarShape);
+ RightWindowFront = new AnimatedPart(TrainCarShape);
+ LeftWindowRear = new AnimatedPart(TrainCarShape);
+ RightWindowRear = new AnimatedPart(TrainCarShape);
Wipers = new AnimatedPart(TrainCarShape);
UnloadingParts = new AnimatedPart(TrainCarShape);
Bell = new AnimatedPart(TrainCarShape);
@@ -413,6 +421,10 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
LeftDoor.SetState(MSTSWagon.LeftDoor.State >= DoorState.Opening);
RightDoor.SetState(MSTSWagon.RightDoor.State >= DoorState.Opening);
Mirrors.SetState(MSTSWagon.MirrorOpen);
+ LeftWindowFront.SetState(MSTSWagon.WindowStates[MSTSWagon.LeftWindowFrontIndex] >= MSTSWagon.WindowState.Opening);
+ RightWindowFront.SetState(MSTSWagon.WindowStates[MSTSWagon.RightWindowFrontIndex] >= MSTSWagon.WindowState.Opening);
+ LeftWindowRear.SetState(MSTSWagon.WindowStates[MSTSWagon.LeftWindowRearIndex] >= MSTSWagon.WindowState.Opening);
+ RightWindowRear.SetState(MSTSWagon.WindowStates[MSTSWagon.RightWindowRearIndex] >= MSTSWagon.WindowState.Opening);
Item1TwoState.SetState(MSTSWagon.GenericItem1);
Item2TwoState.SetState(MSTSWagon.GenericItem2);
UnloadingParts.SetState(MSTSWagon.UnloadingPartsOpen);
@@ -531,6 +543,22 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
{
Mirrors.AddMatrix(matrix);
}
+ else if (matrixName.StartsWith("LEFTWINDOWFRONT")) // Windows
+ {
+ LeftWindowFront.AddMatrix(matrix);
+ }
+ else if (matrixName.StartsWith("RIGHTWINDOWFRONT")) // Windows
+ {
+ RightWindowFront.AddMatrix(matrix);
+ }
+ else if (matrixName.StartsWith("LEFTWINDOWREAR")) // Windows
+ {
+ LeftWindowRear.AddMatrix(matrix);
+ }
+ else if (matrixName.StartsWith("RIGHTWINDOWREAR")) // Windows
+ {
+ RightWindowRear.AddMatrix(matrix);
+ }
else if (matrixName.StartsWith("UNLOADINGPARTS")) // unloading parts
{
UnloadingParts.AddMatrix(matrix);
@@ -592,6 +620,8 @@ public override void InitializeUserInputCommands()
UserInputCommands.Add(UserCommand.ControlDoorLeft, new Action[] { Noop, () => new ToggleDoorsLeftCommand(Viewer.Log) });
UserInputCommands.Add(UserCommand.ControlDoorRight, new Action[] { Noop, () => new ToggleDoorsRightCommand(Viewer.Log) });
UserInputCommands.Add(UserCommand.ControlMirror, new Action[] { Noop, () => new ToggleMirrorsCommand(Viewer.Log) });
+ UserInputCommands.Add(UserCommand.ControlWindowLeft, new Action[] { Noop, () => new ToggleWindowLeftCommand(Viewer.Log) });
+ UserInputCommands.Add(UserCommand.ControlWindowRight, new Action[] { Noop, () => new ToggleWindowRightCommand(Viewer.Log) });
}
public override void HandleUserInput(ElapsedTime elapsedTime)
@@ -615,6 +645,10 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
LeftDoor.UpdateState(MSTSWagon.LeftDoor.State >= DoorState.Opening, elapsedTime);
RightDoor.UpdateState(MSTSWagon.RightDoor.State >= DoorState.Opening, elapsedTime);
Mirrors.UpdateState(MSTSWagon.MirrorOpen, elapsedTime);
+ LeftWindowFront.UpdateState(MSTSWagon.WindowStates[MSTSWagon.LeftWindowFrontIndex] >= MSTSWagon.WindowState.Opening, elapsedTime);
+ RightWindowFront.UpdateState(MSTSWagon.WindowStates[MSTSWagon.RightWindowFrontIndex] >= MSTSWagon.WindowState.Opening, elapsedTime);
+ LeftWindowRear.UpdateState(MSTSWagon.WindowStates[MSTSWagon.LeftWindowRearIndex] >= MSTSWagon.WindowState.Opening, elapsedTime);
+ RightWindowRear.UpdateState(MSTSWagon.WindowStates[MSTSWagon.RightWindowRearIndex] >= MSTSWagon.WindowState.Opening, elapsedTime);
UnloadingParts.UpdateState(MSTSWagon.UnloadingPartsOpen, elapsedTime);
Item1TwoState.UpdateState(MSTSWagon.GenericItem1, elapsedTime);
Item2TwoState.UpdateState(MSTSWagon.GenericItem2, elapsedTime);
diff --git a/Source/RunActivity/Viewer3D/Sound.cs b/Source/RunActivity/Viewer3D/Sound.cs
index 169b46a96e..991c876ad0 100644
--- a/Source/RunActivity/Viewer3D/Sound.cs
+++ b/Source/RunActivity/Viewer3D/Sound.cs
@@ -1420,17 +1420,19 @@ private void SetFreqAndVolume()
volume *= Interpolate(x, MSTSStream.VolumeCurves[i]);
}
+ var wag = (MSTSWagon)SoundSource.Viewer.Camera.AttachedCar;
+ var soundHeardInternallyCorrection = Math.Min(wag.SoundHeardInternallyCorrection[0] + wag.SoundHeardInternallyCorrection[1], 1);
if (SoundSource.IsExternal && SoundSource.Viewer.Camera.Style != Camera.Styles.External && !SoundSource.IsUnattenuated)
{
- if (SoundSource.Viewer.Camera.AttachedCar == null || ((MSTSWagon)SoundSource.Viewer.Camera.AttachedCar).ExternalSoundPassThruPercent == -1)
- volume *= Program.Viewer.Settings.ExternalSoundPassThruPercent * 0.01f;
- else volume *= ((MSTSWagon)SoundSource.Viewer.Camera.AttachedCar).ExternalSoundPassThruPercent * 0.01f;
+ if (wag == null || wag.ExternalSoundPassThruPercent == -1)
+ volume *= Program.Viewer.Settings.ExternalSoundPassThruPercent * 0.01f + (1 - Program.Viewer.Settings.ExternalSoundPassThruPercent * 0.01f) * soundHeardInternallyCorrection;
+ else volume *= wag.ExternalSoundPassThruPercent * 0.01f + (1 - wag.ExternalSoundPassThruPercent * 0.01f) * soundHeardInternallyCorrection;
}
if (SoundSource.IsInternalTrackSound && SoundSource.Viewer.Camera.Style != Camera.Styles.External)
{
- if (((MSTSWagon)SoundSource.Viewer.Camera.AttachedCar)?.TrackSoundPassThruPercent != -1)
- volume *= ((MSTSWagon)SoundSource.Viewer.Camera.AttachedCar).TrackSoundPassThruPercent * 0.01f;
+ if (wag?.TrackSoundPassThruPercent != -1)
+ volume *= wag.TrackSoundPassThruPercent * 0.01f + (1 - wag.TrackSoundPassThruPercent * 0.01f) * soundHeardInternallyCorrection;
}
ALSoundSource.Volume = volume;