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;