diff --git a/OpenBVE.sln b/OpenBVE.sln
index 0ba02dcc9a..340dd0a23b 100644
--- a/OpenBVE.sln
+++ b/OpenBVE.sln
@@ -28,6 +28,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenBve", "source\OpenBVE\O
{7D0D7673-C77A-4140-A5C6-075D825AC11D} = {7D0D7673-C77A-4140-A5C6-075D825AC11D}
{8DAA1CF4-A29A-42CE-8649-34E0FBC0D97C} = {8DAA1CF4-A29A-42CE-8649-34E0FBC0D97C}
{A2FC4D71-1ED9-40D4-B746-FE6AB3C7D55E} = {A2FC4D71-1ED9-40D4-B746-FE6AB3C7D55E}
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45} = {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}
{ACAFCA35-01B7-479C-AD5F-9BCE0F8A597B} = {ACAFCA35-01B7-479C-AD5F-9BCE0F8A597B}
{B520B1D7-3889-4C88-9E0F-CB96802D5CD1} = {B520B1D7-3889-4C88-9E0F-CB96802D5CD1}
{C4BE7A1F-9CCD-4E78-8341-741ABDA8E026} = {C4BE7A1F-9CCD-4E78-8341-741ABDA8E026}
@@ -176,6 +177,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Train.OpenBve", "source\Plu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32PluginProxy", "source\Plugins\Win32PluginProxy\Win32PluginProxy.csproj", "{B9014791-7170-4DCD-B3F1-2B7518A85C83}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Train.MsTs", "source\Plugins\Train.MsTs\Train.MsTs.csproj", "{A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Route.Bve5", "source\Plugins\Route.Bve5\Route.Bve5.csproj", "{C4BE7A1F-9CCD-4E78-8341-741ABDA8E026}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Formats.OpenBve", "source\Plugins\Formats.OpenBve\Formats.OpenBve.csproj", "{7ED7B285-FAE6-4B34-ACC5-87399F27C8BC}"
@@ -859,6 +862,24 @@ Global
{B9014791-7170-4DCD-B3F1-2B7518A85C83}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B9014791-7170-4DCD-B3F1-2B7518A85C83}.Release|x86.ActiveCfg = Release|Any CPU
{B9014791-7170-4DCD-B3F1-2B7518A85C83}.Release|x86.Build.0 = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Debug|x86.Build.0 = Debug|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.GLMenu|Any CPU.ActiveCfg = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.GLMenu|Any CPU.Build.0 = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.GLMenu|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.GLMenu|Mixed Platforms.Build.0 = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.GLMenu|x86.ActiveCfg = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.GLMenu|x86.Build.0 = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Release|x86.ActiveCfg = Release|Any CPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}.Release|x86.Build.0 = Release|Any CPU
{C4BE7A1F-9CCD-4E78-8341-741ABDA8E026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4BE7A1F-9CCD-4E78-8341-741ABDA8E026}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4BE7A1F-9CCD-4E78-8341-741ABDA8E026}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -930,6 +951,7 @@ Global
{7D0D7673-C77A-4140-A5C6-075D825AC11D} = {D75531B7-000E-432E-A168-51846256A9D1}
{D3710390-CD0E-4E14-8E4F-80302D797D5E} = {F49789F2-97F3-45B3-BC85-F4E09C0D120D}
{B9014791-7170-4DCD-B3F1-2B7518A85C83} = {F49789F2-97F3-45B3-BC85-F4E09C0D120D}
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45} = {F49789F2-97F3-45B3-BC85-F4E09C0D120D}
{C4BE7A1F-9CCD-4E78-8341-741ABDA8E026} = {D75531B7-000E-432E-A168-51846256A9D1}
{7ED7B285-FAE6-4B34-ACC5-87399F27C8BC} = {16553295-E70F-4596-AA78-848EEA576C4A}
EndGlobalSection
diff --git a/Readme.md b/Readme.md
index d0a59c703c..6584db02f7 100644
--- a/Readme.md
+++ b/Readme.md
@@ -6,11 +6,15 @@
This repository contains the source code for the Train Simulator OpenBVE, a 3D cab based simulator.
-The simulator supports the following route formats:
+Supported route formats:
* Native CSV / RW.
* BVE5 TXT format.
* Mechanik DAT format.
+Supported train formats:
+* BVE2 / BVE4, with native OpenBVE extensions.
+* Microsoft Train Simulator (MSTS)
+
OpenBVE is built in OpenGL, using the OpenTK framework for windowing.
### Fixed Errata
diff --git a/assets/Compatibility/numbers.png b/assets/Compatibility/numbers.png
new file mode 100644
index 0000000000..1b61e68232
Binary files /dev/null and b/assets/Compatibility/numbers.png differ
diff --git a/assets/Languages/ca-ES.xlf b/assets/Languages/ca-ES.xlf
index 6d0714b94e..d194a26158 100644
--- a/assets/Languages/ca-ES.xlf
+++ b/assets/Languages/ca-ES.xlf
@@ -1620,6 +1620,10 @@
Other items installation directory:
Carpeta d'instal·lació d'altres paquets:
+
+ MSTS installation directory:
+ Carpeta d'instal·lació de MSTS:
+
Package compression format:
Format de compressió dels paquets:
diff --git a/assets/Languages/cs-CZ.xlf b/assets/Languages/cs-CZ.xlf
index 0af0804201..5e3b2d4f53 100644
--- a/assets/Languages/cs-CZ.xlf
+++ b/assets/Languages/cs-CZ.xlf
@@ -1635,6 +1635,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/de-CH.xlf b/assets/Languages/de-CH.xlf
index b1d6e59e66..569b331c7c 100644
--- a/assets/Languages/de-CH.xlf
+++ b/assets/Languages/de-CH.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/de-DE.xlf b/assets/Languages/de-DE.xlf
index 88b3b1535c..1426c2dfb1 100644
--- a/assets/Languages/de-DE.xlf
+++ b/assets/Languages/de-DE.xlf
@@ -1635,6 +1635,10 @@
Other items installation directory:
Installationsordner für sonstiges:
+
+ MSTS installation directory:
+ MSTS installationsordner:
+
Package compression format:
Paketkomprimierungsformat:
diff --git a/assets/Languages/en-GB.xlf b/assets/Languages/en-GB.xlf
index b0da83cb1e..a8e7eed9c6 100644
--- a/assets/Languages/en-GB.xlf
+++ b/assets/Languages/en-GB.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/en-US.xlf b/assets/Languages/en-US.xlf
index d57dd5f404..b21ded3cda 100755
--- a/assets/Languages/en-US.xlf
+++ b/assets/Languages/en-US.xlf
@@ -1243,6 +1243,9 @@
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
diff --git a/assets/Languages/es-ES.xlf b/assets/Languages/es-ES.xlf
index 3eef65cc87..07a4a32f6b 100644
--- a/assets/Languages/es-ES.xlf
+++ b/assets/Languages/es-ES.xlf
@@ -1636,6 +1636,10 @@
Other items installation directory:
Carpeta de instalación de otros paquetes:
+
+ MSTS installation directory:
+ Carpeta de instalación de MSTS:
+
Package compression format:
Formato de compresión de los paquetes:
diff --git a/assets/Languages/fi-FI.xlf b/assets/Languages/fi-FI.xlf
index fc825ef21b..1695d37af9 100644
--- a/assets/Languages/fi-FI.xlf
+++ b/assets/Languages/fi-FI.xlf
@@ -1635,6 +1635,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/fr-FR.xlf b/assets/Languages/fr-FR.xlf
index 49341868d7..e078483d69 100644
--- a/assets/Languages/fr-FR.xlf
+++ b/assets/Languages/fr-FR.xlf
@@ -1635,6 +1635,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/hu-HU.xlf b/assets/Languages/hu-HU.xlf
index a6a3da38a9..ba880ecd2e 100644
--- a/assets/Languages/hu-HU.xlf
+++ b/assets/Languages/hu-HU.xlf
@@ -1638,6 +1638,10 @@
Other items installation directory:
Egyebek telepítési könyvtára:
+
+ MSTS installation directory:
+ MSTS telepítési könyvtára:
+
Package compression format:
Csomag tömörítésének formátuma:
diff --git a/assets/Languages/id-ID.xlf b/assets/Languages/id-ID.xlf
index 4556dc1ee4..e45183b8bb 100644
--- a/assets/Languages/id-ID.xlf
+++ b/assets/Languages/id-ID.xlf
@@ -1609,6 +1609,10 @@
Other items installation directory:
Folder konten lainnya:
+
+ MSTS installation directory:
+ Folder MSTS:
+
Package compression format:
Format file kompresi:
diff --git a/assets/Languages/it-IT.xlf b/assets/Languages/it-IT.xlf
index 246cd2d9b6..47830c6570 100644
--- a/assets/Languages/it-IT.xlf
+++ b/assets/Languages/it-IT.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/ja-JP.xlf b/assets/Languages/ja-JP.xlf
index 79774feb22..361ff5c7cc 100644
--- a/assets/Languages/ja-JP.xlf
+++ b/assets/Languages/ja-JP.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
その他のアイテムのインストール場所:
+
+ MSTS installation directory:
+
Package compression format:
パッケージの圧縮形式:
diff --git a/assets/Languages/ko-KR.xlf b/assets/Languages/ko-KR.xlf
index 5e3da0f70a..4860e9d191 100644
--- a/assets/Languages/ko-KR.xlf
+++ b/assets/Languages/ko-KR.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/ms_MY.xlf b/assets/Languages/ms_MY.xlf
index 63ea3d4c18..ed1e57cf7d 100644
--- a/assets/Languages/ms_MY.xlf
+++ b/assets/Languages/ms_MY.xlf
@@ -1604,6 +1604,10 @@
Other items installation directory:
Direktori pemasangan iitem lain-lain:
+
+ MSTS installation directory:
+ Direktori pemasangan MSTS:
+
Package compression format:
Format mampatan pakej:
diff --git a/assets/Languages/nb_NO.xlf b/assets/Languages/nb_NO.xlf
index 3187d30fb5..80bf88be40 100644
--- a/assets/Languages/nb_NO.xlf
+++ b/assets/Languages/nb_NO.xlf
@@ -1616,6 +1616,10 @@
Other items installation directory:
Mappe for installasjon av andre ting:
+
+ MSTS installation directory:
+ Mappe for installasjon MSTS:
+
Package compression format:
Pakke kompresjonsformat:
diff --git a/assets/Languages/nl-NL.xlf b/assets/Languages/nl-NL.xlf
index de0b3dc26a..ddd03e622f 100644
--- a/assets/Languages/nl-NL.xlf
+++ b/assets/Languages/nl-NL.xlf
@@ -1635,6 +1635,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/pl-PL.xlf b/assets/Languages/pl-PL.xlf
index 95e3b9858b..37237a0dff 100644
--- a/assets/Languages/pl-PL.xlf
+++ b/assets/Languages/pl-PL.xlf
@@ -1607,6 +1607,10 @@
Other items installation directory:
Folder instalacji innych:
+
+ MSTS installation directory:
+ Folder instalacji MSTS:
+
Package compression format:
Format kompresji pakietów:
diff --git a/assets/Languages/pt-BR.xlf b/assets/Languages/pt-BR.xlf
index 3794a91ab4..81228d66b5 100644
--- a/assets/Languages/pt-BR.xlf
+++ b/assets/Languages/pt-BR.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/pt-PT.xlf b/assets/Languages/pt-PT.xlf
index f8bca89a18..2430d50123 100644
--- a/assets/Languages/pt-PT.xlf
+++ b/assets/Languages/pt-PT.xlf
@@ -1652,6 +1652,10 @@
Other items installation directory:
Directório de instalação de outros itens:
+
+ MSTS installation directory:
+ Directório de instalação da MSTS:
+
Package compression format:
Formato de compressão do pacote:
diff --git a/assets/Languages/ro-RO.xlf b/assets/Languages/ro-RO.xlf
index 26d530c8b6..018615c026 100644
--- a/assets/Languages/ro-RO.xlf
+++ b/assets/Languages/ro-RO.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/ru-RU.xlf b/assets/Languages/ru-RU.xlf
index 9aac65118b..938bcafd7c 100644
--- a/assets/Languages/ru-RU.xlf
+++ b/assets/Languages/ru-RU.xlf
@@ -1635,6 +1635,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/sk-SK.xlf b/assets/Languages/sk-SK.xlf
index bdb3c99061..98f36c2820 100644
--- a/assets/Languages/sk-SK.xlf
+++ b/assets/Languages/sk-SK.xlf
@@ -1554,6 +1554,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/uk-UA.xlf b/assets/Languages/uk-UA.xlf
index ecd76db99d..99984897a7 100644
--- a/assets/Languages/uk-UA.xlf
+++ b/assets/Languages/uk-UA.xlf
@@ -1637,6 +1637,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Languages/zh-CN.xlf b/assets/Languages/zh-CN.xlf
index f811002066..ab94d8fec6 100644
--- a/assets/Languages/zh-CN.xlf
+++ b/assets/Languages/zh-CN.xlf
@@ -1634,6 +1634,9 @@
Other items installation directory:
其他安装目录:
+
+ MSTS installation directory:
+
Package compression format:
扩展包压缩格式:
diff --git a/assets/Languages/zh-HK.xlf b/assets/Languages/zh-HK.xlf
index d6343459f3..fb70d5d5ee 100644
--- a/assets/Languages/zh-HK.xlf
+++ b/assets/Languages/zh-HK.xlf
@@ -1639,6 +1639,9 @@
Other items installation directory:
其他項目安裝資料夾:
+
+ MSTS installation directory:
+
Package compression format:
擴展包壓縮格式:
diff --git a/assets/Languages/zh-TW.xlf b/assets/Languages/zh-TW.xlf
index f0c2e34cca..a75ff3dd87 100644
--- a/assets/Languages/zh-TW.xlf
+++ b/assets/Languages/zh-TW.xlf
@@ -1636,6 +1636,9 @@
Other items installation directory:
Other items installation directory:
+
+ MSTS installation directory:
+
Package compression format:
Package compression format:
diff --git a/assets/Menu/icon_msts.png b/assets/Menu/icon_msts.png
new file mode 100644
index 0000000000..5770a13c6c
Binary files /dev/null and b/assets/Menu/icon_msts.png differ
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index c4eb469bad..22e2e84064 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -692,19 +692,19 @@ public void InitializeVisibility()
{
for (int i = 0; i < StaticObjectStates.Count; i++)
{
- VAOExtensions.CreateVAO(StaticObjectStates[i].Prototype?.Mesh, false, DefaultShader.VertexLayout, this);
- if (StaticObjectStates[i].Matricies != null)
- {
- GL.CreateBuffers(1, out StaticObjectStates[i].MatrixBufferIndex);
- }
+ VAOExtensions.CreateVAO(StaticObjectStates[i].Prototype.Mesh, false, DefaultShader.VertexLayout, this);
+ /*
+ * n.b.
+ * Only create the actual matrix buffer at first frame render time
+ * I can't find why at the minute, but Object Viewer otherwise doesn't show them, and attempting
+ * to retrieve previously set matricies from the shader shows all zeros
+ *
+ * Probably a timing issue, but it works doing it that way :/
+ */
}
for (int i = 0; i < DynamicObjectStates.Count; i++)
{
- VAOExtensions.CreateVAO(DynamicObjectStates[i].Prototype?.Mesh, false, DefaultShader.VertexLayout, this);
- if (DynamicObjectStates[i].Matricies != null)
- {
- GL.CreateBuffers(1, out DynamicObjectStates[i].MatrixBufferIndex);
- }
+ VAOExtensions.CreateVAO(DynamicObjectStates[i].Prototype.Mesh, false, DefaultShader.VertexLayout, this);
}
}
ObjectsSortedByStart = StaticObjectStates.Select((x, i) => new { Index = i, Distance = x.StartingDistance }).OrderBy(x => x.Distance).Select(x => x.Index).ToArray();
diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs
index 809267a014..d48b6330ec 100644
--- a/source/ObjectViewer/ProgramS.cs
+++ b/source/ObjectViewer/ProgramS.cs
@@ -315,18 +315,22 @@ internal static void RefreshObjects()
{
try
{
- if(Files[i].EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase))
+ if(Files[i].EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".con", StringComparison.InvariantCultureIgnoreCase))
{
- string currentTrainFolder = Path.GetDirectoryName(Files[i]);
+ string currentTrain = Files[i];
+ if (currentTrain.EndsWith("extensions.cfg", StringComparison.InvariantCultureIgnoreCase))
+ {
+ currentTrain = System.IO.Path.GetDirectoryName(currentTrain);
+ }
bool canLoad = false;
for (int j = 0; j < Program.CurrentHost.Plugins.Length; j++)
{
- if (Program.CurrentHost.Plugins[j].Train != null && Program.CurrentHost.Plugins[j].Train.CanLoadTrain(currentTrainFolder))
+ if (Program.CurrentHost.Plugins[j].Train != null && Program.CurrentHost.Plugins[j].Train.CanLoadTrain(currentTrain))
{
Control[] dummyControls = new Control[0];
TrainManager.Trains = new List { new TrainBase(TrainState.Available, TrainType.LocalPlayerTrain) };
AbstractTrain playerTrain = TrainManager.Trains[0];
- Program.CurrentHost.Plugins[j].Train.LoadTrain(Encoding.UTF8, currentTrainFolder, ref playerTrain, ref dummyControls);
+ Program.CurrentHost.Plugins[j].Train.LoadTrain(Encoding.UTF8, currentTrain, ref playerTrain, ref dummyControls);
TrainManager.PlayerTrain = TrainManager.Trains[0];
canLoad = true;
break;
@@ -423,7 +427,7 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e)
{
CheckFileExists = true,
Multiselect = true,
- Filter = @"All supported object files|*.csv;*.b3d;*.x;*.animated;extensions.cfg;*.l3dobj;*.l3dgrp;*.obj;*.s;train.xml|openBVE Objects|*.csv;*.b3d;*.x;*.animated;extensions.cfg;train.xml|LokSim 3D Objects|*.l3dobj;*.l3dgrp|Wavefront Objects|*.obj|Microsoft Train Simulator Objects|*.s|All files|*"
+ Filter = @"All supported object files|*.csv;*.b3d;*.x;*.animated;extensions.cfg;*.l3dobj;*.l3dgrp;*.obj;*.s;train.xml;*.con|openBVE Objects|*.csv;*.b3d;*.x;*.animated;extensions.cfg;train.xml|LokSim 3D Objects|*.l3dobj;*.l3dgrp|Wavefront Objects|*.obj|Microsoft Train Simulator Files|*.s;*.con|All files|*"
};
if (Dialog.ShowDialog() == DialogResult.OK)
{
@@ -431,11 +435,11 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e)
string[] f = Dialog.FileNames;
for (int i = 0; i < f.Length; i++)
{
- string currentTrainFolder = string.Empty;
- if(f[i].EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || f[i].EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || f[i].EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase))
+ string currentTrain = string.Empty;
+ if(f[i].EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || f[i].EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || f[i].EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase) || f[i].EndsWith(".con", StringComparison.InvariantCultureIgnoreCase))
{
// only check to see if it's a train if this is a specified filetype, else we'll start loading the full train from an object in it's folder
- currentTrainFolder = Path.GetDirectoryName(f[i]);
+ currentTrain = f[i].EndsWith(".con", StringComparison.InvariantCultureIgnoreCase) ? f[i] : Path.GetDirectoryName(f[i]);
}
for (int j = 0; j < Program.CurrentHost.Plugins.Length; j++)
{
@@ -453,7 +457,7 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e)
{
Files.Add(f[i]);
}
- if (!string.IsNullOrEmpty(currentTrainFolder) && Program.CurrentHost.Plugins[j].Train != null && Program.CurrentHost.Plugins[j].Train.CanLoadTrain(currentTrainFolder))
+ if (!string.IsNullOrEmpty(currentTrain) && Program.CurrentHost.Plugins[j].Train != null && Program.CurrentHost.Plugins[j].Train.CanLoadTrain(currentTrain))
{
Files.Add(f[i]);
}
diff --git a/source/OpenBVE/System/Loading.cs b/source/OpenBVE/System/Loading.cs
index e098eded14..78187f2a96 100644
--- a/source/OpenBVE/System/Loading.cs
+++ b/source/OpenBVE/System/Loading.cs
@@ -472,7 +472,7 @@ private static void LoadEverythingThreaded() {
// load plugin
for (int i = 0; i < Program.TrainManager.Trains.Count; i++) {
if ( Program.TrainManager.Trains[i].State != TrainState.Bogus) {
- if ( Program.TrainManager.Trains[i].IsPlayerTrain) {
+ if (Program.TrainManager.Trains[i].IsPlayerTrain && !string.IsNullOrEmpty(Program.TrainManager.Trains[i].TrainFolder)) {
if (Program.TrainManager.Trains[i].Plugin == null && !Program.TrainManager.Trains[i].LoadCustomPlugin(Program.TrainManager.Trains[i].TrainFolder, CurrentTrainEncoding)) {
Program.TrainManager.Trains[i].LoadDefaultPlugin(Program.TrainManager.Trains[i].TrainFolder);
}
diff --git a/source/OpenBVE/System/Options.cs b/source/OpenBVE/System/Options.cs
index ff62461e1f..d166b7f47b 100644
--- a/source/OpenBVE/System/Options.cs
+++ b/source/OpenBVE/System/Options.cs
@@ -345,6 +345,7 @@ public override void Save(string fileName)
Builder.AppendLine("[folders]");
Builder.AppendLine("route = " + RouteFolder);
Builder.AppendLine("train = " + TrainFolder);
+ Builder.AppendLine("MSTSTrainset = " + Program.FileSystem.MSTSDirectory);
Builder.AppendLine();
Builder.AppendLine("[recentlyUsedRoutes]");
for (int i = 0; i < RecentlyUsedRoutes.Length; i++)
diff --git a/source/OpenBVE/UserInterface/formMain.Designer.cs b/source/OpenBVE/UserInterface/formMain.Designer.cs
index 2b1ba07f03..1c762ab5c0 100644
--- a/source/OpenBVE/UserInterface/formMain.Designer.cs
+++ b/source/OpenBVE/UserInterface/formMain.Designer.cs
@@ -101,6 +101,53 @@ private void InitializeComponent() {
this.panelOptions = new System.Windows.Forms.Panel();
this.buttonOptionsPrevious = new System.Windows.Forms.Button();
this.buttonOptionsNext = new System.Windows.Forms.Button();
+ this.panelOptionsPage2 = new System.Windows.Forms.Panel();
+ this.groupBoxInputDevice = new System.Windows.Forms.GroupBox();
+ this.labelInputDevice = new System.Windows.Forms.Label();
+ this.listviewInputDevice = new System.Windows.Forms.ListView();
+ this.columnheaderInputDeviceName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.columnheaderInputDeviceStatus = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.columnheaderInputDeviceVersion = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.columnheaderInputDeviceProvider = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.columnheaderInputDeviceFileName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.checkBoxInputDeviceEnable = new System.Windows.Forms.CheckBox();
+ this.buttonInputDeviceConfig = new System.Windows.Forms.Button();
+ this.groupBoxObjectParser = new System.Windows.Forms.GroupBox();
+ this.labelObjparser = new System.Windows.Forms.Label();
+ this.comboBoxObjparser = new System.Windows.Forms.ComboBox();
+ this.labelXparser = new System.Windows.Forms.Label();
+ this.comboBoxXparser = new System.Windows.Forms.ComboBox();
+ this.groupBoxKioskMode = new System.Windows.Forms.GroupBox();
+ this.labelKioskTimeout = new System.Windows.Forms.Label();
+ this.numericUpDownKioskTimeout = new System.Windows.Forms.NumericUpDown();
+ this.checkBoxEnableKiosk = new System.Windows.Forms.CheckBox();
+ this.groupBoxAdvancedOptions = new System.Windows.Forms.GroupBox();
+ this.checkBoxPanel2Extended = new System.Windows.Forms.CheckBox();
+ this.pictureboxCursor = new System.Windows.Forms.PictureBox();
+ this.labelCursor = new System.Windows.Forms.Label();
+ this.comboboxCursor = new System.Windows.Forms.ComboBox();
+ this.checkBoxHacks = new System.Windows.Forms.CheckBox();
+ this.checkBoxTransparencyFix = new System.Windows.Forms.CheckBox();
+ this.checkBoxUnloadTextures = new System.Windows.Forms.CheckBox();
+ this.labelTimeAcceleration = new System.Windows.Forms.Label();
+ this.updownTimeAccelerationFactor = new System.Windows.Forms.NumericUpDown();
+ this.checkBoxIsUseNewRenderer = new System.Windows.Forms.CheckBox();
+ this.checkBoxLoadInAdvance = new System.Windows.Forms.CheckBox();
+ this.groupBoxPackageOptions = new System.Windows.Forms.GroupBox();
+ this.buttonMSTSTrainsetDirectory = new System.Windows.Forms.Button();
+ this.label1 = new System.Windows.Forms.Label();
+ this.textBoxMSTSTrainsetDirectory = new System.Windows.Forms.TextBox();
+ this.comboBoxCompressionFormat = new System.Windows.Forms.ComboBox();
+ this.labelPackageCompression = new System.Windows.Forms.Label();
+ this.buttonOtherDirectory = new System.Windows.Forms.Button();
+ this.labelOtherInstallDirectory = new System.Windows.Forms.Label();
+ this.textBoxOtherDirectory = new System.Windows.Forms.TextBox();
+ this.buttonTrainInstallationDirectory = new System.Windows.Forms.Button();
+ this.labelTrainInstallDirectory = new System.Windows.Forms.Label();
+ this.textBoxTrainDirectory = new System.Windows.Forms.TextBox();
+ this.buttonSetRouteDirectory = new System.Windows.Forms.Button();
+ this.labelRouteInstallDirectory = new System.Windows.Forms.Label();
+ this.textBoxRouteDirectory = new System.Windows.Forms.TextBox();
this.panelOptionsLeft = new System.Windows.Forms.Panel();
this.groupboxDisplayMode = new System.Windows.Forms.GroupBox();
this.comboBoxFont = new System.Windows.Forms.ComboBox();
@@ -170,50 +217,6 @@ private void InitializeComponent() {
this.groupboxSound = new System.Windows.Forms.GroupBox();
this.updownSoundNumber = new System.Windows.Forms.NumericUpDown();
this.labelSoundNumber = new System.Windows.Forms.Label();
- this.panelOptionsPage2 = new System.Windows.Forms.Panel();
- this.groupBoxInputDevice = new System.Windows.Forms.GroupBox();
- this.labelInputDevice = new System.Windows.Forms.Label();
- this.listviewInputDevice = new System.Windows.Forms.ListView();
- this.columnheaderInputDeviceName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
- this.columnheaderInputDeviceStatus = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
- this.columnheaderInputDeviceVersion = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
- this.columnheaderInputDeviceProvider = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
- this.columnheaderInputDeviceFileName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
- this.checkBoxInputDeviceEnable = new System.Windows.Forms.CheckBox();
- this.buttonInputDeviceConfig = new System.Windows.Forms.Button();
- this.groupBoxObjectParser = new System.Windows.Forms.GroupBox();
- this.labelObjparser = new System.Windows.Forms.Label();
- this.comboBoxObjparser = new System.Windows.Forms.ComboBox();
- this.labelXparser = new System.Windows.Forms.Label();
- this.comboBoxXparser = new System.Windows.Forms.ComboBox();
- this.groupBoxKioskMode = new System.Windows.Forms.GroupBox();
- this.labelKioskTimeout = new System.Windows.Forms.Label();
- this.numericUpDownKioskTimeout = new System.Windows.Forms.NumericUpDown();
- this.checkBoxEnableKiosk = new System.Windows.Forms.CheckBox();
- this.groupBoxAdvancedOptions = new System.Windows.Forms.GroupBox();
- this.checkBoxPanel2Extended = new System.Windows.Forms.CheckBox();
- this.pictureboxCursor = new System.Windows.Forms.PictureBox();
- this.labelCursor = new System.Windows.Forms.Label();
- this.comboboxCursor = new System.Windows.Forms.ComboBox();
- this.checkBoxHacks = new System.Windows.Forms.CheckBox();
- this.checkBoxTransparencyFix = new System.Windows.Forms.CheckBox();
- this.checkBoxUnloadTextures = new System.Windows.Forms.CheckBox();
- this.labelTimeAcceleration = new System.Windows.Forms.Label();
- this.updownTimeAccelerationFactor = new System.Windows.Forms.NumericUpDown();
- this.checkBoxIsUseNewRenderer = new System.Windows.Forms.CheckBox();
- this.checkBoxLoadInAdvance = new System.Windows.Forms.CheckBox();
- this.groupBoxPackageOptions = new System.Windows.Forms.GroupBox();
- this.comboBoxCompressionFormat = new System.Windows.Forms.ComboBox();
- this.labelPackageCompression = new System.Windows.Forms.Label();
- this.buttonOtherDirectory = new System.Windows.Forms.Button();
- this.labelOtherInstallDirectory = new System.Windows.Forms.Label();
- this.textBoxOtherDirectory = new System.Windows.Forms.TextBox();
- this.buttonTrainInstallationDirectory = new System.Windows.Forms.Button();
- this.labelTrainInstallDirectory = new System.Windows.Forms.Label();
- this.textBoxTrainDirectory = new System.Windows.Forms.TextBox();
- this.buttonSetRouteDirectory = new System.Windows.Forms.Button();
- this.labelRouteInstallDirectory = new System.Windows.Forms.Label();
- this.textBoxRouteDirectory = new System.Windows.Forms.TextBox();
this.pictureboxLanguage = new System.Windows.Forms.PictureBox();
this.comboboxLanguages = new System.Windows.Forms.ComboBox();
this.labelOptionsTitleSeparator = new System.Windows.Forms.Label();
@@ -490,6 +493,15 @@ private void InitializeComponent() {
this.tabpageRouteSettings.SuspendLayout();
this.panelRouteEncoding.SuspendLayout();
this.panelOptions.SuspendLayout();
+ this.panelOptionsPage2.SuspendLayout();
+ this.groupBoxInputDevice.SuspendLayout();
+ this.groupBoxObjectParser.SuspendLayout();
+ this.groupBoxKioskMode.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDownKioskTimeout)).BeginInit();
+ this.groupBoxAdvancedOptions.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureboxCursor)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.updownTimeAccelerationFactor)).BeginInit();
+ this.groupBoxPackageOptions.SuspendLayout();
this.panelOptionsLeft.SuspendLayout();
this.groupboxDisplayMode.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarHUDSize)).BeginInit();
@@ -514,15 +526,6 @@ private void InitializeComponent() {
this.groupboxSimulation.SuspendLayout();
this.groupboxSound.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.updownSoundNumber)).BeginInit();
- this.panelOptionsPage2.SuspendLayout();
- this.groupBoxInputDevice.SuspendLayout();
- this.groupBoxObjectParser.SuspendLayout();
- this.groupBoxKioskMode.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.numericUpDownKioskTimeout)).BeginInit();
- this.groupBoxAdvancedOptions.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.pictureboxCursor)).BeginInit();
- ((System.ComponentModel.ISupportInitialize)(this.updownTimeAccelerationFactor)).BeginInit();
- this.groupBoxPackageOptions.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureboxLanguage)).BeginInit();
this.panelPanels.SuspendLayout();
this.panelReview.SuspendLayout();
@@ -593,7 +596,7 @@ private void InitializeComponent() {
this.labelVerticalSeparator.BackColor = System.Drawing.Color.White;
this.labelVerticalSeparator.Location = new System.Drawing.Point(158, 0);
this.labelVerticalSeparator.Name = "labelVerticalSeparator";
- this.labelVerticalSeparator.Size = new System.Drawing.Size(2, 651);
+ this.labelVerticalSeparator.Size = new System.Drawing.Size(2, 681);
this.labelVerticalSeparator.TabIndex = 9;
//
// buttonClose
@@ -601,7 +604,7 @@ private void InitializeComponent() {
this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonClose.AutoEllipsis = true;
this.buttonClose.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonClose.Location = new System.Drawing.Point(8, 599);
+ this.buttonClose.Location = new System.Drawing.Point(8, 629);
this.buttonClose.Name = "buttonClose";
this.buttonClose.Size = new System.Drawing.Size(144, 26);
this.buttonClose.TabIndex = 5;
@@ -631,7 +634,7 @@ private void InitializeComponent() {
this.panelStart.Controls.Add(this.labelStartTitleBackground);
this.panelStart.Location = new System.Drawing.Point(160, 0);
this.panelStart.Name = "panelStart";
- this.panelStart.Size = new System.Drawing.Size(699, 631);
+ this.panelStart.Size = new System.Drawing.Size(699, 661);
this.panelStart.TabIndex = 7;
//
// comboboxMode
@@ -639,7 +642,7 @@ private void InitializeComponent() {
this.comboboxMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.comboboxMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboboxMode.FormattingEnabled = true;
- this.comboboxMode.Location = new System.Drawing.Point(144, 599);
+ this.comboboxMode.Location = new System.Drawing.Point(144, 629);
this.comboboxMode.Name = "comboboxMode";
this.comboboxMode.Size = new System.Drawing.Size(144, 21);
this.comboboxMode.TabIndex = 11;
@@ -649,7 +652,7 @@ private void InitializeComponent() {
this.labelMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelMode.AutoEllipsis = true;
this.labelMode.ForeColor = System.Drawing.Color.Black;
- this.labelMode.Location = new System.Drawing.Point(16, 601);
+ this.labelMode.Location = new System.Drawing.Point(16, 631);
this.labelMode.Name = "labelMode";
this.labelMode.Size = new System.Drawing.Size(128, 18);
this.labelMode.TabIndex = 10;
@@ -661,7 +664,7 @@ private void InitializeComponent() {
this.groupboxTrainSelection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.groupboxTrainSelection.Controls.Add(this.tabcontrolTrainSelection);
this.groupboxTrainSelection.ForeColor = System.Drawing.Color.Black;
- this.groupboxTrainSelection.Location = new System.Drawing.Point(8, 359);
+ this.groupboxTrainSelection.Location = new System.Drawing.Point(8, 389);
this.groupboxTrainSelection.Name = "groupboxTrainSelection";
this.groupboxTrainSelection.Size = new System.Drawing.Size(365, 200);
this.groupboxTrainSelection.TabIndex = 7;
@@ -816,7 +819,7 @@ private void InitializeComponent() {
this.groupboxTrainDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.groupboxTrainDetails.Controls.Add(this.tabcontrolTrainDetails);
this.groupboxTrainDetails.ForeColor = System.Drawing.Color.Black;
- this.groupboxTrainDetails.Location = new System.Drawing.Point(375, 359);
+ this.groupboxTrainDetails.Location = new System.Drawing.Point(375, 389);
this.groupboxTrainDetails.Name = "groupboxTrainDetails";
this.groupboxTrainDetails.Size = new System.Drawing.Size(319, 200);
this.groupboxTrainDetails.TabIndex = 8;
@@ -1016,7 +1019,7 @@ private void InitializeComponent() {
this.buttonStart.AutoEllipsis = true;
this.buttonStart.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonStart.Enabled = false;
- this.buttonStart.Location = new System.Drawing.Point(571, 599);
+ this.buttonStart.Location = new System.Drawing.Point(571, 629);
this.buttonStart.Name = "buttonStart";
this.buttonStart.Size = new System.Drawing.Size(120, 26);
this.buttonStart.TabIndex = 12;
@@ -1032,7 +1035,7 @@ private void InitializeComponent() {
this.labelStart.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(107)))), ((int)(((byte)(130)))), ((int)(((byte)(153)))));
this.labelStart.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelStart.ForeColor = System.Drawing.Color.White;
- this.labelStart.Location = new System.Drawing.Point(7, 567);
+ this.labelStart.Location = new System.Drawing.Point(7, 597);
this.labelStart.Name = "labelStart";
this.labelStart.Size = new System.Drawing.Size(684, 26);
this.labelStart.TabIndex = 9;
@@ -1047,7 +1050,7 @@ private void InitializeComponent() {
this.labelTrain.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(107)))), ((int)(((byte)(130)))), ((int)(((byte)(153)))));
this.labelTrain.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelTrain.ForeColor = System.Drawing.Color.White;
- this.labelTrain.Location = new System.Drawing.Point(8, 327);
+ this.labelTrain.Location = new System.Drawing.Point(8, 357);
this.labelTrain.Name = "labelTrain";
this.labelTrain.Size = new System.Drawing.Size(683, 24);
this.labelTrain.TabIndex = 6;
@@ -1062,7 +1065,7 @@ private void InitializeComponent() {
this.groupboxRouteSelection.ForeColor = System.Drawing.Color.Black;
this.groupboxRouteSelection.Location = new System.Drawing.Point(8, 72);
this.groupboxRouteSelection.Name = "groupboxRouteSelection";
- this.groupboxRouteSelection.Size = new System.Drawing.Size(365, 247);
+ this.groupboxRouteSelection.Size = new System.Drawing.Size(365, 277);
this.groupboxRouteSelection.TabIndex = 4;
this.groupboxRouteSelection.TabStop = false;
this.groupboxRouteSelection.Text = "Selection";
@@ -1078,7 +1081,7 @@ private void InitializeComponent() {
this.tabcontrolRouteSelection.Location = new System.Drawing.Point(8, 16);
this.tabcontrolRouteSelection.Name = "tabcontrolRouteSelection";
this.tabcontrolRouteSelection.SelectedIndex = 0;
- this.tabcontrolRouteSelection.Size = new System.Drawing.Size(349, 223);
+ this.tabcontrolRouteSelection.Size = new System.Drawing.Size(349, 253);
this.tabcontrolRouteSelection.TabIndex = 0;
this.tabcontrolRouteSelection.SelectedIndexChanged += new System.EventHandler(this.tabcontrolRouteSelection_SelectedIndexChanged);
//
@@ -1089,7 +1092,7 @@ private void InitializeComponent() {
this.tabpageRouteBrowse.Location = new System.Drawing.Point(4, 22);
this.tabpageRouteBrowse.Name = "tabpageRouteBrowse";
this.tabpageRouteBrowse.Padding = new System.Windows.Forms.Padding(3);
- this.tabpageRouteBrowse.Size = new System.Drawing.Size(341, 197);
+ this.tabpageRouteBrowse.Size = new System.Drawing.Size(341, 227);
this.tabpageRouteBrowse.TabIndex = 0;
this.tabpageRouteBrowse.Text = "File browser";
this.tabpageRouteBrowse.UseVisualStyleBackColor = true;
@@ -1106,7 +1109,7 @@ private void InitializeComponent() {
this.listviewRouteFiles.MultiSelect = false;
this.listviewRouteFiles.Name = "listviewRouteFiles";
this.listviewRouteFiles.ShowGroups = false;
- this.listviewRouteFiles.Size = new System.Drawing.Size(325, 159);
+ this.listviewRouteFiles.Size = new System.Drawing.Size(325, 189);
this.listviewRouteFiles.TabIndex = 1;
this.listviewRouteFiles.UseCompatibleStateImageBehavior = false;
this.listviewRouteFiles.View = System.Windows.Forms.View.Details;
@@ -1130,7 +1133,7 @@ private void InitializeComponent() {
this.tabpageRouteRecently.Location = new System.Drawing.Point(4, 22);
this.tabpageRouteRecently.Name = "tabpageRouteRecently";
this.tabpageRouteRecently.Padding = new System.Windows.Forms.Padding(3);
- this.tabpageRouteRecently.Size = new System.Drawing.Size(341, 197);
+ this.tabpageRouteRecently.Size = new System.Drawing.Size(341, 227);
this.tabpageRouteRecently.TabIndex = 1;
this.tabpageRouteRecently.Text = "Recently used";
this.tabpageRouteRecently.UseVisualStyleBackColor = true;
@@ -1158,7 +1161,7 @@ private void InitializeComponent() {
this.tabPageRoutePackages.Controls.Add(this.listViewRoutePackages);
this.tabPageRoutePackages.Location = new System.Drawing.Point(4, 22);
this.tabPageRoutePackages.Name = "tabPageRoutePackages";
- this.tabPageRoutePackages.Size = new System.Drawing.Size(341, 197);
+ this.tabPageRoutePackages.Size = new System.Drawing.Size(341, 227);
this.tabPageRoutePackages.TabIndex = 2;
this.tabPageRoutePackages.Text = "Installed Packages";
this.tabPageRoutePackages.UseVisualStyleBackColor = true;
@@ -1190,7 +1193,7 @@ private void InitializeComponent() {
this.groupboxRouteDetails.ForeColor = System.Drawing.Color.Black;
this.groupboxRouteDetails.Location = new System.Drawing.Point(375, 72);
this.groupboxRouteDetails.Name = "groupboxRouteDetails";
- this.groupboxRouteDetails.Size = new System.Drawing.Size(319, 247);
+ this.groupboxRouteDetails.Size = new System.Drawing.Size(319, 277);
this.groupboxRouteDetails.TabIndex = 5;
this.groupboxRouteDetails.TabStop = false;
this.groupboxRouteDetails.Text = "Details";
@@ -1208,7 +1211,7 @@ private void InitializeComponent() {
this.tabcontrolRouteDetails.Location = new System.Drawing.Point(8, 16);
this.tabcontrolRouteDetails.Name = "tabcontrolRouteDetails";
this.tabcontrolRouteDetails.SelectedIndex = 0;
- this.tabcontrolRouteDetails.Size = new System.Drawing.Size(303, 223);
+ this.tabcontrolRouteDetails.Size = new System.Drawing.Size(303, 253);
this.tabcontrolRouteDetails.TabIndex = 19;
this.tabcontrolRouteDetails.SelectedIndexChanged += new System.EventHandler(this.tabcontrolRouteDetails_SelectedIndexChanged);
//
@@ -1219,7 +1222,7 @@ private void InitializeComponent() {
this.tabpageRouteDescription.Location = new System.Drawing.Point(4, 22);
this.tabpageRouteDescription.Name = "tabpageRouteDescription";
this.tabpageRouteDescription.Padding = new System.Windows.Forms.Padding(3);
- this.tabpageRouteDescription.Size = new System.Drawing.Size(295, 197);
+ this.tabpageRouteDescription.Size = new System.Drawing.Size(295, 227);
this.tabpageRouteDescription.TabIndex = 0;
this.tabpageRouteDescription.Text = "Description";
this.tabpageRouteDescription.UseVisualStyleBackColor = true;
@@ -1231,11 +1234,11 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.textboxRouteDescription.BackColor = System.Drawing.SystemColors.Window;
this.textboxRouteDescription.Location = new System.Drawing.Point(168, 8);
- this.textboxRouteDescription.Multiline = true;
this.textboxRouteDescription.Name = "textboxRouteDescription";
this.textboxRouteDescription.ReadOnly = true;
- this.textboxRouteDescription.Size = new System.Drawing.Size(119, 183);
+ this.textboxRouteDescription.Size = new System.Drawing.Size(119, 213);
this.textboxRouteDescription.TabIndex = 0;
+ this.textboxRouteDescription.Text = "";
//
// pictureboxRouteImage
//
@@ -1244,7 +1247,7 @@ private void InitializeComponent() {
this.pictureboxRouteImage.Cursor = System.Windows.Forms.Cursors.Hand;
this.pictureboxRouteImage.Location = new System.Drawing.Point(8, 8);
this.pictureboxRouteImage.Name = "pictureboxRouteImage";
- this.pictureboxRouteImage.Size = new System.Drawing.Size(152, 183);
+ this.pictureboxRouteImage.Size = new System.Drawing.Size(152, 213);
this.pictureboxRouteImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureboxRouteImage.TabIndex = 0;
this.pictureboxRouteImage.TabStop = false;
@@ -1256,7 +1259,7 @@ private void InitializeComponent() {
this.tabpageRouteMap.Location = new System.Drawing.Point(4, 22);
this.tabpageRouteMap.Name = "tabpageRouteMap";
this.tabpageRouteMap.Padding = new System.Windows.Forms.Padding(3);
- this.tabpageRouteMap.Size = new System.Drawing.Size(295, 197);
+ this.tabpageRouteMap.Size = new System.Drawing.Size(295, 227);
this.tabpageRouteMap.TabIndex = 1;
this.tabpageRouteMap.Text = "Map";
this.tabpageRouteMap.UseVisualStyleBackColor = true;
@@ -1279,12 +1282,12 @@ private void InitializeComponent() {
this.pictureBoxContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripExport});
this.pictureBoxContextMenu.Name = "pictureBoxRouteMapContextMenu";
- this.pictureBoxContextMenu.Size = new System.Drawing.Size(109, 26);
+ this.pictureBoxContextMenu.Size = new System.Drawing.Size(108, 26);
//
// toolStripExport
//
this.toolStripExport.Name = "toolStripExport";
- this.toolStripExport.Size = new System.Drawing.Size(108, 22);
+ this.toolStripExport.Size = new System.Drawing.Size(107, 22);
this.toolStripExport.Text = "Export";
this.toolStripExport.Click += new System.EventHandler(this.toolStripExport_Click);
//
@@ -1294,7 +1297,7 @@ private void InitializeComponent() {
this.tabpageRouteGradient.Location = new System.Drawing.Point(4, 22);
this.tabpageRouteGradient.Name = "tabpageRouteGradient";
this.tabpageRouteGradient.Padding = new System.Windows.Forms.Padding(3);
- this.tabpageRouteGradient.Size = new System.Drawing.Size(295, 197);
+ this.tabpageRouteGradient.Size = new System.Drawing.Size(295, 227);
this.tabpageRouteGradient.TabIndex = 2;
this.tabpageRouteGradient.Text = "Gradient profile";
this.tabpageRouteGradient.UseVisualStyleBackColor = true;
@@ -1322,7 +1325,7 @@ private void InitializeComponent() {
this.tabpageRouteSettings.Location = new System.Drawing.Point(4, 22);
this.tabpageRouteSettings.Name = "tabpageRouteSettings";
this.tabpageRouteSettings.Padding = new System.Windows.Forms.Padding(3);
- this.tabpageRouteSettings.Size = new System.Drawing.Size(295, 197);
+ this.tabpageRouteSettings.Size = new System.Drawing.Size(295, 227);
this.tabpageRouteSettings.TabIndex = 3;
this.tabpageRouteSettings.Text = "Settings";
this.tabpageRouteSettings.UseVisualStyleBackColor = true;
@@ -1519,7 +1522,7 @@ private void InitializeComponent() {
this.labelFillerTwo.BackColor = System.Drawing.Color.Silver;
this.labelFillerTwo.Location = new System.Drawing.Point(0, 330);
this.labelFillerTwo.Name = "labelFillerTwo";
- this.labelFillerTwo.Size = new System.Drawing.Size(160, 151);
+ this.labelFillerTwo.Size = new System.Drawing.Size(160, 181);
this.labelFillerTwo.TabIndex = 2;
//
// panelOptions
@@ -1530,9 +1533,9 @@ private void InitializeComponent() {
this.panelOptions.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(243)))), ((int)(((byte)(255)))), ((int)(((byte)(243)))));
this.panelOptions.Controls.Add(this.buttonOptionsPrevious);
this.panelOptions.Controls.Add(this.buttonOptionsNext);
+ this.panelOptions.Controls.Add(this.panelOptionsPage2);
this.panelOptions.Controls.Add(this.panelOptionsLeft);
this.panelOptions.Controls.Add(this.panelOptionsRight);
- this.panelOptions.Controls.Add(this.panelOptionsPage2);
this.panelOptions.Controls.Add(this.pictureboxLanguage);
this.panelOptions.Controls.Add(this.comboboxLanguages);
this.panelOptions.Controls.Add(this.labelOptionsTitleSeparator);
@@ -1540,7 +1543,7 @@ private void InitializeComponent() {
this.panelOptions.Controls.Add(this.labelOptionsTitleBackground);
this.panelOptions.Location = new System.Drawing.Point(160, 0);
this.panelOptions.Name = "panelOptions";
- this.panelOptions.Size = new System.Drawing.Size(699, 631);
+ this.panelOptions.Size = new System.Drawing.Size(699, 661);
this.panelOptions.TabIndex = 0;
//
// buttonOptionsPrevious
@@ -1567,1412 +1570,1449 @@ private void InitializeComponent() {
this.buttonOptionsNext.UseVisualStyleBackColor = true;
this.buttonOptionsNext.Click += new System.EventHandler(this.buttonOptionsPrevious_Click);
//
- // panelOptionsLeft
+ // panelOptionsPage2
//
- this.panelOptionsLeft.Controls.Add(this.groupboxDisplayMode);
- this.panelOptionsLeft.Controls.Add(this.groupboxWindow);
- this.panelOptionsLeft.Controls.Add(this.groupboxFullscreen);
- this.panelOptionsLeft.Controls.Add(this.groupboxInterpolation);
- this.panelOptionsLeft.Location = new System.Drawing.Point(8, 72);
- this.panelOptionsLeft.Name = "panelOptionsLeft";
- this.panelOptionsLeft.Size = new System.Drawing.Size(316, 576);
- this.panelOptionsLeft.TabIndex = 16;
+ this.panelOptionsPage2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panelOptionsPage2.Controls.Add(this.groupBoxInputDevice);
+ this.panelOptionsPage2.Controls.Add(this.groupBoxObjectParser);
+ this.panelOptionsPage2.Controls.Add(this.groupBoxKioskMode);
+ this.panelOptionsPage2.Controls.Add(this.groupBoxAdvancedOptions);
+ this.panelOptionsPage2.Controls.Add(this.groupBoxPackageOptions);
+ this.panelOptionsPage2.Location = new System.Drawing.Point(0, 72);
+ this.panelOptionsPage2.Name = "panelOptionsPage2";
+ this.panelOptionsPage2.Size = new System.Drawing.Size(683, 583);
+ this.panelOptionsPage2.TabIndex = 20;
//
- // groupboxDisplayMode
+ // groupBoxInputDevice
//
- this.groupboxDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.groupBoxInputDevice.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxDisplayMode.Controls.Add(this.comboBoxFont);
- this.groupboxDisplayMode.Controls.Add(this.labelFontName);
- this.groupboxDisplayMode.Controls.Add(this.labelHUDLarge);
- this.groupboxDisplayMode.Controls.Add(this.labelHUDNormal);
- this.groupboxDisplayMode.Controls.Add(this.labelHUDSmall);
- this.groupboxDisplayMode.Controls.Add(this.trackBarHUDSize);
- this.groupboxDisplayMode.Controls.Add(this.labelHUDScale);
- this.groupboxDisplayMode.Controls.Add(this.comboboxVSync);
- this.groupboxDisplayMode.Controls.Add(this.labelVSync);
- this.groupboxDisplayMode.Controls.Add(this.radiobuttonFullscreen);
- this.groupboxDisplayMode.Controls.Add(this.radiobuttonWindow);
- this.groupboxDisplayMode.ForeColor = System.Drawing.Color.Black;
- this.groupboxDisplayMode.Location = new System.Drawing.Point(0, 0);
- this.groupboxDisplayMode.Name = "groupboxDisplayMode";
- this.groupboxDisplayMode.Size = new System.Drawing.Size(316, 189);
- this.groupboxDisplayMode.TabIndex = 4;
- this.groupboxDisplayMode.TabStop = false;
- this.groupboxDisplayMode.Text = "Display mode";
+ this.groupBoxInputDevice.Controls.Add(this.labelInputDevice);
+ this.groupBoxInputDevice.Controls.Add(this.listviewInputDevice);
+ this.groupBoxInputDevice.Controls.Add(this.checkBoxInputDeviceEnable);
+ this.groupBoxInputDevice.Controls.Add(this.buttonInputDeviceConfig);
+ this.groupBoxInputDevice.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxInputDevice.Location = new System.Drawing.Point(6, 396);
+ this.groupBoxInputDevice.Name = "groupBoxInputDevice";
+ this.groupBoxInputDevice.Size = new System.Drawing.Size(674, 181);
+ this.groupBoxInputDevice.TabIndex = 24;
+ this.groupBoxInputDevice.TabStop = false;
+ this.groupBoxInputDevice.Text = "Input Device Plugin";
//
- // comboBoxFont
+ // labelInputDevice
//
- this.comboBoxFont.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.comboBoxFont.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboBoxFont.FormattingEnabled = true;
- this.comboBoxFont.Location = new System.Drawing.Point(45, 155);
- this.comboBoxFont.Name = "comboBoxFont";
- this.comboBoxFont.Size = new System.Drawing.Size(264, 21);
- this.comboBoxFont.TabIndex = 14;
- this.comboBoxFont.SelectionChangeCommitted += new System.EventHandler(this.comboBoxFont_SelectedIndexChanged);
+ this.labelInputDevice.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelInputDevice.Location = new System.Drawing.Point(8, 17);
+ this.labelInputDevice.Name = "labelInputDevice";
+ this.labelInputDevice.Size = new System.Drawing.Size(658, 17);
+ this.labelInputDevice.TabIndex = 0;
+ this.labelInputDevice.Text = "WARNING: If you are turn on the Input Device Plugin(s), it may be happen the conf" +
+ "lict of input setting(s).";
//
- // labelFontName
+ // listviewInputDevice
//
- this.labelFontName.Location = new System.Drawing.Point(8, 148);
- this.labelFontName.Name = "labelFontName";
- this.labelFontName.Size = new System.Drawing.Size(50, 36);
- this.labelFontName.TabIndex = 13;
- this.labelFontName.Text = "Font:";
- this.labelFontName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.listviewInputDevice.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.listviewInputDevice.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.columnheaderInputDeviceName,
+ this.columnheaderInputDeviceStatus,
+ this.columnheaderInputDeviceVersion,
+ this.columnheaderInputDeviceProvider,
+ this.columnheaderInputDeviceFileName});
+ this.listviewInputDevice.FullRowSelect = true;
+ this.listviewInputDevice.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
+ this.listviewInputDevice.HideSelection = false;
+ this.listviewInputDevice.LabelWrap = false;
+ this.listviewInputDevice.Location = new System.Drawing.Point(8, 38);
+ this.listviewInputDevice.MultiSelect = false;
+ this.listviewInputDevice.Name = "listviewInputDevice";
+ this.listviewInputDevice.ShowGroups = false;
+ this.listviewInputDevice.Size = new System.Drawing.Size(658, 103);
+ this.listviewInputDevice.TabIndex = 1;
+ this.listviewInputDevice.UseCompatibleStateImageBehavior = false;
+ this.listviewInputDevice.View = System.Windows.Forms.View.Details;
+ this.listviewInputDevice.SelectedIndexChanged += new System.EventHandler(this.listviewInputDevice_SelectedIndexChanged);
+ this.listviewInputDevice.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.listviewInputDevice_MouseDoubleClick);
//
- // labelHUDLarge
+ // columnheaderInputDeviceName
//
- this.labelHUDLarge.Location = new System.Drawing.Point(258, 125);
- this.labelHUDLarge.Name = "labelHUDLarge";
- this.labelHUDLarge.Size = new System.Drawing.Size(72, 48);
- this.labelHUDLarge.TabIndex = 12;
- this.labelHUDLarge.Text = "Large";
- this.labelHUDLarge.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ this.columnheaderInputDeviceName.Text = "Name";
//
- // labelHUDNormal
+ // columnheaderInputDeviceStatus
//
- this.labelHUDNormal.Location = new System.Drawing.Point(162, 125);
- this.labelHUDNormal.Name = "labelHUDNormal";
- this.labelHUDNormal.Size = new System.Drawing.Size(70, 48);
- this.labelHUDNormal.TabIndex = 11;
- this.labelHUDNormal.Text = "Normal";
- this.labelHUDNormal.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ this.columnheaderInputDeviceStatus.Text = "Status";
//
- // labelHUDSmall
+ // columnheaderInputDeviceVersion
//
- this.labelHUDSmall.Location = new System.Drawing.Point(66, 125);
- this.labelHUDSmall.Name = "labelHUDSmall";
- this.labelHUDSmall.Size = new System.Drawing.Size(70, 48);
- this.labelHUDSmall.TabIndex = 10;
- this.labelHUDSmall.Text = "Small";
- this.labelHUDSmall.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ this.columnheaderInputDeviceVersion.Text = "Version";
//
- // trackBarHUDSize
+ // columnheaderInputDeviceProvider
//
- this.trackBarHUDSize.LargeChange = 1;
- this.trackBarHUDSize.Location = new System.Drawing.Point(88, 100);
- this.trackBarHUDSize.Maximum = 2;
- this.trackBarHUDSize.Name = "trackBarHUDSize";
- this.trackBarHUDSize.Size = new System.Drawing.Size(220, 45);
- this.trackBarHUDSize.TabIndex = 9;
- this.trackBarHUDSize.Value = 1;
+ this.columnheaderInputDeviceProvider.Text = "Provider";
//
- // labelHUDScale
+ // columnheaderInputDeviceFileName
//
- this.labelHUDScale.AutoSize = true;
- this.labelHUDScale.Location = new System.Drawing.Point(8, 106);
- this.labelHUDScale.Name = "labelHUDScale";
- this.labelHUDScale.Size = new System.Drawing.Size(54, 13);
- this.labelHUDScale.TabIndex = 8;
- this.labelHUDScale.Text = "HUD Size";
+ this.columnheaderInputDeviceFileName.Text = "File Name";
+ this.columnheaderInputDeviceFileName.Width = 200;
//
- // comboboxVSync
- //
- this.comboboxVSync.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.comboboxVSync.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboboxVSync.FormattingEnabled = true;
- this.comboboxVSync.Location = new System.Drawing.Point(156, 72);
- this.comboboxVSync.Name = "comboboxVSync";
- this.comboboxVSync.Size = new System.Drawing.Size(152, 21);
- this.comboboxVSync.TabIndex = 7;
- //
- // labelVSync
- //
- this.labelVSync.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelVSync.AutoEllipsis = true;
- this.labelVSync.Location = new System.Drawing.Point(8, 72);
- this.labelVSync.Name = "labelVSync";
- this.labelVSync.Size = new System.Drawing.Size(148, 18);
- this.labelVSync.TabIndex = 2;
- this.labelVSync.Text = "Vertical syncronization:";
- this.labelVSync.TextAlign = System.Drawing.ContentAlignment.TopRight;
- //
- // radiobuttonFullscreen
- //
- this.radiobuttonFullscreen.AutoSize = true;
- this.radiobuttonFullscreen.Location = new System.Drawing.Point(8, 48);
- this.radiobuttonFullscreen.Name = "radiobuttonFullscreen";
- this.radiobuttonFullscreen.Size = new System.Drawing.Size(102, 17);
- this.radiobuttonFullscreen.TabIndex = 1;
- this.radiobuttonFullscreen.TabStop = true;
- this.radiobuttonFullscreen.Text = "Fullscreen mode";
- this.radiobuttonFullscreen.UseVisualStyleBackColor = true;
- //
- // radiobuttonWindow
+ // checkBoxInputDeviceEnable
//
- this.radiobuttonWindow.AutoSize = true;
- this.radiobuttonWindow.Checked = true;
- this.radiobuttonWindow.Location = new System.Drawing.Point(8, 24);
- this.radiobuttonWindow.Name = "radiobuttonWindow";
- this.radiobuttonWindow.Size = new System.Drawing.Size(93, 17);
- this.radiobuttonWindow.TabIndex = 0;
- this.radiobuttonWindow.TabStop = true;
- this.radiobuttonWindow.Text = "Window mode";
- this.radiobuttonWindow.UseVisualStyleBackColor = true;
+ this.checkBoxInputDeviceEnable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.checkBoxInputDeviceEnable.Enabled = false;
+ this.checkBoxInputDeviceEnable.Location = new System.Drawing.Point(8, 144);
+ this.checkBoxInputDeviceEnable.Name = "checkBoxInputDeviceEnable";
+ this.checkBoxInputDeviceEnable.Size = new System.Drawing.Size(230, 34);
+ this.checkBoxInputDeviceEnable.TabIndex = 2;
+ this.checkBoxInputDeviceEnable.Text = "Enable this Input Device Plugin";
+ this.checkBoxInputDeviceEnable.UseVisualStyleBackColor = true;
+ this.checkBoxInputDeviceEnable.CheckedChanged += new System.EventHandler(this.checkBoxInputDeviceEnable_CheckedChanged);
//
- // groupboxWindow
+ // buttonInputDeviceConfig
//
- this.groupboxWindow.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxWindow.Controls.Add(this.updownWindowHeight);
- this.groupboxWindow.Controls.Add(this.labelWindowHeight);
- this.groupboxWindow.Controls.Add(this.updownWindowWidth);
- this.groupboxWindow.Controls.Add(this.labelWindowWidth);
- this.groupboxWindow.ForeColor = System.Drawing.Color.Black;
- this.groupboxWindow.Location = new System.Drawing.Point(0, 192);
- this.groupboxWindow.Name = "groupboxWindow";
- this.groupboxWindow.Size = new System.Drawing.Size(316, 80);
- this.groupboxWindow.TabIndex = 5;
- this.groupboxWindow.TabStop = false;
- this.groupboxWindow.Text = "Window mode";
+ this.buttonInputDeviceConfig.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+ this.buttonInputDeviceConfig.BackColor = System.Drawing.SystemColors.ButtonFace;
+ this.buttonInputDeviceConfig.Enabled = false;
+ this.buttonInputDeviceConfig.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.buttonInputDeviceConfig.Location = new System.Drawing.Point(270, 148);
+ this.buttonInputDeviceConfig.MaximumSize = new System.Drawing.Size(106, 25);
+ this.buttonInputDeviceConfig.Name = "buttonInputDeviceConfig";
+ this.buttonInputDeviceConfig.Size = new System.Drawing.Size(106, 25);
+ this.buttonInputDeviceConfig.TabIndex = 3;
+ this.buttonInputDeviceConfig.Text = "Config";
+ this.buttonInputDeviceConfig.UseVisualStyleBackColor = true;
+ this.buttonInputDeviceConfig.Click += new System.EventHandler(this.buttonInputDeviceConfig_Click);
//
- // updownWindowHeight
+ // groupBoxObjectParser
//
- this.updownWindowHeight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownWindowHeight.Location = new System.Drawing.Point(156, 48);
- this.updownWindowHeight.Maximum = new decimal(new int[] {
- 1048575,
- 0,
- 0,
- 0});
- this.updownWindowHeight.Minimum = new decimal(new int[] {
- 16,
- 0,
- 0,
- 0});
- this.updownWindowHeight.Name = "updownWindowHeight";
- this.updownWindowHeight.Size = new System.Drawing.Size(152, 20);
- this.updownWindowHeight.TabIndex = 3;
- this.updownWindowHeight.Value = new decimal(new int[] {
- 600,
- 0,
- 0,
- 0});
+ this.groupBoxObjectParser.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBoxObjectParser.Controls.Add(this.labelObjparser);
+ this.groupBoxObjectParser.Controls.Add(this.comboBoxObjparser);
+ this.groupBoxObjectParser.Controls.Add(this.labelXparser);
+ this.groupBoxObjectParser.Controls.Add(this.comboBoxXparser);
+ this.groupBoxObjectParser.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxObjectParser.Location = new System.Drawing.Point(377, 288);
+ this.groupBoxObjectParser.Name = "groupBoxObjectParser";
+ this.groupBoxObjectParser.Size = new System.Drawing.Size(305, 110);
+ this.groupBoxObjectParser.TabIndex = 23;
+ this.groupBoxObjectParser.TabStop = false;
+ this.groupBoxObjectParser.Text = "Object Parser";
//
- // labelWindowHeight
+ // labelObjparser
//
- this.labelWindowHeight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelWindowHeight.AutoEllipsis = true;
- this.labelWindowHeight.Location = new System.Drawing.Point(8, 50);
- this.labelWindowHeight.Name = "labelWindowHeight";
- this.labelWindowHeight.Size = new System.Drawing.Size(148, 18);
- this.labelWindowHeight.TabIndex = 2;
- this.labelWindowHeight.Text = "Height:";
- this.labelWindowHeight.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.labelObjparser.Location = new System.Drawing.Point(7, 44);
+ this.labelObjparser.Name = "labelObjparser";
+ this.labelObjparser.Size = new System.Drawing.Size(113, 26);
+ this.labelObjparser.TabIndex = 0;
+ this.labelObjparser.Text = "Obj Object Parser:";
+ this.labelObjparser.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
- // updownWindowWidth
+ // comboBoxObjparser
//
- this.updownWindowWidth.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownWindowWidth.Location = new System.Drawing.Point(156, 24);
- this.updownWindowWidth.Maximum = new decimal(new int[] {
- 1048575,
- 0,
- 0,
- 0});
- this.updownWindowWidth.Minimum = new decimal(new int[] {
- 16,
- 0,
- 0,
- 0});
- this.updownWindowWidth.Name = "updownWindowWidth";
- this.updownWindowWidth.Size = new System.Drawing.Size(152, 20);
- this.updownWindowWidth.TabIndex = 1;
- this.updownWindowWidth.Value = new decimal(new int[] {
- 960,
- 0,
- 0,
- 0});
+ this.comboBoxObjparser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBoxObjparser.FormattingEnabled = true;
+ this.comboBoxObjparser.Items.AddRange(new object[] {
+ "Original",
+ "Assimp"});
+ this.comboBoxObjparser.Location = new System.Drawing.Point(127, 44);
+ this.comboBoxObjparser.Name = "comboBoxObjparser";
+ this.comboBoxObjparser.Size = new System.Drawing.Size(170, 21);
+ this.comboBoxObjparser.TabIndex = 1;
//
- // labelWindowWidth
+ // labelXparser
//
- this.labelWindowWidth.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelWindowWidth.AutoEllipsis = true;
- this.labelWindowWidth.Location = new System.Drawing.Point(8, 26);
- this.labelWindowWidth.Name = "labelWindowWidth";
- this.labelWindowWidth.Size = new System.Drawing.Size(148, 18);
- this.labelWindowWidth.TabIndex = 0;
- this.labelWindowWidth.Text = "Width:";
- this.labelWindowWidth.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.labelXparser.Location = new System.Drawing.Point(7, 17);
+ this.labelXparser.Name = "labelXparser";
+ this.labelXparser.Size = new System.Drawing.Size(113, 26);
+ this.labelXparser.TabIndex = 0;
+ this.labelXparser.Text = "X Object Parser:";
+ this.labelXparser.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
- // groupboxFullscreen
+ // comboBoxXparser
//
- this.groupboxFullscreen.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxFullscreen.Controls.Add(this.comboboxFullscreenBits);
- this.groupboxFullscreen.Controls.Add(this.labelFullscreenBits);
- this.groupboxFullscreen.Controls.Add(this.updownFullscreenHeight);
- this.groupboxFullscreen.Controls.Add(this.labelFullscreenHeight);
- this.groupboxFullscreen.Controls.Add(this.updownFullscreenWidth);
- this.groupboxFullscreen.Controls.Add(this.labelFullscreenWidth);
- this.groupboxFullscreen.ForeColor = System.Drawing.Color.Black;
- this.groupboxFullscreen.Location = new System.Drawing.Point(0, 275);
- this.groupboxFullscreen.Name = "groupboxFullscreen";
- this.groupboxFullscreen.Size = new System.Drawing.Size(316, 104);
- this.groupboxFullscreen.TabIndex = 6;
- this.groupboxFullscreen.TabStop = false;
- this.groupboxFullscreen.Text = "Fullscreen mode";
+ this.comboBoxXparser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBoxXparser.FormattingEnabled = true;
+ this.comboBoxXparser.Items.AddRange(new object[] {
+ "Original",
+ "NewXParser",
+ "Assimp"});
+ this.comboBoxXparser.Location = new System.Drawing.Point(127, 21);
+ this.comboBoxXparser.Name = "comboBoxXparser";
+ this.comboBoxXparser.Size = new System.Drawing.Size(170, 21);
+ this.comboBoxXparser.TabIndex = 1;
//
- // comboboxFullscreenBits
+ // groupBoxKioskMode
//
- this.comboboxFullscreenBits.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.comboboxFullscreenBits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboboxFullscreenBits.FormattingEnabled = true;
- this.comboboxFullscreenBits.Location = new System.Drawing.Point(156, 72);
- this.comboboxFullscreenBits.Name = "comboboxFullscreenBits";
- this.comboboxFullscreenBits.Size = new System.Drawing.Size(152, 21);
- this.comboboxFullscreenBits.TabIndex = 5;
+ this.groupBoxKioskMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBoxKioskMode.Controls.Add(this.labelKioskTimeout);
+ this.groupBoxKioskMode.Controls.Add(this.numericUpDownKioskTimeout);
+ this.groupBoxKioskMode.Controls.Add(this.checkBoxEnableKiosk);
+ this.groupBoxKioskMode.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxKioskMode.Location = new System.Drawing.Point(377, 190);
+ this.groupBoxKioskMode.Name = "groupBoxKioskMode";
+ this.groupBoxKioskMode.Size = new System.Drawing.Size(305, 92);
+ this.groupBoxKioskMode.TabIndex = 22;
+ this.groupBoxKioskMode.TabStop = false;
+ this.groupBoxKioskMode.Text = "Kiosk Mode";
//
- // labelFullscreenBits
+ // labelKioskTimeout
//
- this.labelFullscreenBits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelFullscreenBits.AutoEllipsis = true;
- this.labelFullscreenBits.Location = new System.Drawing.Point(8, 74);
- this.labelFullscreenBits.Name = "labelFullscreenBits";
- this.labelFullscreenBits.Size = new System.Drawing.Size(148, 18);
- this.labelFullscreenBits.TabIndex = 4;
- this.labelFullscreenBits.Text = "Bits per pixel:";
- this.labelFullscreenBits.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.labelKioskTimeout.Location = new System.Drawing.Point(8, 37);
+ this.labelKioskTimeout.Name = "labelKioskTimeout";
+ this.labelKioskTimeout.Size = new System.Drawing.Size(155, 30);
+ this.labelKioskTimeout.TabIndex = 2;
+ this.labelKioskTimeout.Text = "Control timeout (s)";
+ this.labelKioskTimeout.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
- // updownFullscreenHeight
+ // numericUpDownKioskTimeout
//
- this.updownFullscreenHeight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownFullscreenHeight.Location = new System.Drawing.Point(156, 48);
- this.updownFullscreenHeight.Maximum = new decimal(new int[] {
- 1048575,
- 0,
- 0,
- 0});
- this.updownFullscreenHeight.Minimum = new decimal(new int[] {
- 16,
- 0,
- 0,
- 0});
- this.updownFullscreenHeight.Name = "updownFullscreenHeight";
- this.updownFullscreenHeight.Size = new System.Drawing.Size(152, 20);
- this.updownFullscreenHeight.TabIndex = 3;
- this.updownFullscreenHeight.Value = new decimal(new int[] {
- 768,
+ this.numericUpDownKioskTimeout.DecimalPlaces = 2;
+ this.numericUpDownKioskTimeout.Location = new System.Drawing.Point(166, 41);
+ this.numericUpDownKioskTimeout.Maximum = new decimal(new int[] {
+ 10000,
0,
0,
0});
+ this.numericUpDownKioskTimeout.Name = "numericUpDownKioskTimeout";
+ this.numericUpDownKioskTimeout.Size = new System.Drawing.Size(131, 20);
+ this.numericUpDownKioskTimeout.TabIndex = 1;
//
- // labelFullscreenHeight
+ // checkBoxEnableKiosk
//
- this.labelFullscreenHeight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelFullscreenHeight.AutoEllipsis = true;
- this.labelFullscreenHeight.Location = new System.Drawing.Point(8, 50);
- this.labelFullscreenHeight.Name = "labelFullscreenHeight";
- this.labelFullscreenHeight.Size = new System.Drawing.Size(148, 18);
- this.labelFullscreenHeight.TabIndex = 2;
- this.labelFullscreenHeight.Text = "Height:";
- this.labelFullscreenHeight.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.checkBoxEnableKiosk.AutoSize = true;
+ this.checkBoxEnableKiosk.Location = new System.Drawing.Point(9, 20);
+ this.checkBoxEnableKiosk.Name = "checkBoxEnableKiosk";
+ this.checkBoxEnableKiosk.Size = new System.Drawing.Size(118, 17);
+ this.checkBoxEnableKiosk.TabIndex = 0;
+ this.checkBoxEnableKiosk.Text = "Enable Kiosk Mode";
+ this.checkBoxEnableKiosk.UseVisualStyleBackColor = true;
//
- // updownFullscreenWidth
+ // groupBoxAdvancedOptions
//
- this.updownFullscreenWidth.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownFullscreenWidth.Location = new System.Drawing.Point(156, 24);
- this.updownFullscreenWidth.Maximum = new decimal(new int[] {
- 1048575,
- 0,
- 0,
- 0});
- this.updownFullscreenWidth.Minimum = new decimal(new int[] {
- 16,
- 0,
- 0,
- 0});
- this.updownFullscreenWidth.Name = "updownFullscreenWidth";
- this.updownFullscreenWidth.Size = new System.Drawing.Size(152, 20);
- this.updownFullscreenWidth.TabIndex = 1;
- this.updownFullscreenWidth.Value = new decimal(new int[] {
- 1024,
- 0,
- 0,
- 0});
+ this.groupBoxAdvancedOptions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxPanel2Extended);
+ this.groupBoxAdvancedOptions.Controls.Add(this.pictureboxCursor);
+ this.groupBoxAdvancedOptions.Controls.Add(this.labelCursor);
+ this.groupBoxAdvancedOptions.Controls.Add(this.comboboxCursor);
+ this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxHacks);
+ this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxTransparencyFix);
+ this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxUnloadTextures);
+ this.groupBoxAdvancedOptions.Controls.Add(this.labelTimeAcceleration);
+ this.groupBoxAdvancedOptions.Controls.Add(this.updownTimeAccelerationFactor);
+ this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxIsUseNewRenderer);
+ this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxLoadInAdvance);
+ this.groupBoxAdvancedOptions.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxAdvancedOptions.Location = new System.Drawing.Point(8, 190);
+ this.groupBoxAdvancedOptions.Name = "groupBoxAdvancedOptions";
+ this.groupBoxAdvancedOptions.Size = new System.Drawing.Size(358, 208);
+ this.groupBoxAdvancedOptions.TabIndex = 21;
+ this.groupBoxAdvancedOptions.TabStop = false;
+ this.groupBoxAdvancedOptions.Text = "Advanced Options";
//
- // labelFullscreenWidth
+ // checkBoxPanel2Extended
//
- this.labelFullscreenWidth.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelFullscreenWidth.AutoEllipsis = true;
- this.labelFullscreenWidth.Location = new System.Drawing.Point(8, 26);
- this.labelFullscreenWidth.Name = "labelFullscreenWidth";
- this.labelFullscreenWidth.Size = new System.Drawing.Size(148, 18);
- this.labelFullscreenWidth.TabIndex = 0;
- this.labelFullscreenWidth.Text = "Width:";
- this.labelFullscreenWidth.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.checkBoxPanel2Extended.AutoSize = true;
+ this.checkBoxPanel2Extended.Location = new System.Drawing.Point(8, 183);
+ this.checkBoxPanel2Extended.Name = "checkBoxPanel2Extended";
+ this.checkBoxPanel2Extended.Size = new System.Drawing.Size(159, 17);
+ this.checkBoxPanel2Extended.TabIndex = 20;
+ this.checkBoxPanel2Extended.Text = "Enable Panel2 extend mode";
+ this.checkBoxPanel2Extended.UseVisualStyleBackColor = true;
//
- // groupboxInterpolation
+ // pictureboxCursor
//
- this.groupboxInterpolation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxInterpolation.Controls.Add(this.updownAntiAliasing);
- this.groupboxInterpolation.Controls.Add(this.labelAntiAliasing);
- this.groupboxInterpolation.Controls.Add(this.labelTransparencyQuality);
- this.groupboxInterpolation.Controls.Add(this.labelTransparencyPerformance);
- this.groupboxInterpolation.Controls.Add(this.labelTransparency);
- this.groupboxInterpolation.Controls.Add(this.updownAnisotropic);
- this.groupboxInterpolation.Controls.Add(this.labelAnisotropic);
- this.groupboxInterpolation.Controls.Add(this.comboboxInterpolation);
- this.groupboxInterpolation.Controls.Add(this.labelInterpolation);
- this.groupboxInterpolation.Controls.Add(this.trackbarTransparency);
- this.groupboxInterpolation.ForeColor = System.Drawing.Color.Black;
- this.groupboxInterpolation.Location = new System.Drawing.Point(0, 381);
- this.groupboxInterpolation.Name = "groupboxInterpolation";
- this.groupboxInterpolation.Size = new System.Drawing.Size(316, 160);
- this.groupboxInterpolation.TabIndex = 7;
- this.groupboxInterpolation.TabStop = false;
- this.groupboxInterpolation.Text = "Interpolation";
+ this.pictureboxCursor.Location = new System.Drawing.Point(8, 145);
+ this.pictureboxCursor.Name = "pictureboxCursor";
+ this.pictureboxCursor.Size = new System.Drawing.Size(32, 32);
+ this.pictureboxCursor.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.pictureboxCursor.TabIndex = 18;
+ this.pictureboxCursor.TabStop = false;
//
- // updownAntiAliasing
+ // labelCursor
//
- this.updownAntiAliasing.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownAntiAliasing.Location = new System.Drawing.Point(156, 64);
- this.updownAntiAliasing.Maximum = new decimal(new int[] {
- 16,
- 0,
- 0,
- 0});
- this.updownAntiAliasing.Name = "updownAntiAliasing";
- this.updownAntiAliasing.Size = new System.Drawing.Size(152, 20);
- this.updownAntiAliasing.TabIndex = 5;
+ this.labelCursor.AutoSize = true;
+ this.labelCursor.Location = new System.Drawing.Point(48, 140);
+ this.labelCursor.Name = "labelCursor";
+ this.labelCursor.Size = new System.Drawing.Size(37, 13);
+ this.labelCursor.TabIndex = 17;
+ this.labelCursor.Text = "Cursor";
//
- // labelAntiAliasing
+ // comboboxCursor
//
- this.labelAntiAliasing.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelAntiAliasing.AutoEllipsis = true;
- this.labelAntiAliasing.Location = new System.Drawing.Point(8, 66);
- this.labelAntiAliasing.Name = "labelAntiAliasing";
- this.labelAntiAliasing.Size = new System.Drawing.Size(148, 18);
- this.labelAntiAliasing.TabIndex = 4;
- this.labelAntiAliasing.Text = "Level of anti-aliasing:";
- this.labelAntiAliasing.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.comboboxCursor.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboboxCursor.FormattingEnabled = true;
+ this.comboboxCursor.Location = new System.Drawing.Point(48, 158);
+ this.comboboxCursor.Name = "comboboxCursor";
+ this.comboboxCursor.Size = new System.Drawing.Size(108, 21);
+ this.comboboxCursor.TabIndex = 19;
+ this.comboboxCursor.SelectedIndexChanged += new System.EventHandler(this.comboboxCursor_SelectedIndexChanged);
//
- // labelTransparencyQuality
+ // checkBoxHacks
//
- this.labelTransparencyQuality.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.labelTransparencyQuality.AutoEllipsis = true;
- this.labelTransparencyQuality.Location = new System.Drawing.Point(230, 136);
- this.labelTransparencyQuality.Name = "labelTransparencyQuality";
- this.labelTransparencyQuality.Size = new System.Drawing.Size(76, 16);
- this.labelTransparencyQuality.TabIndex = 9;
- this.labelTransparencyQuality.Text = "Smooth";
- this.labelTransparencyQuality.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.checkBoxHacks.AutoSize = true;
+ this.checkBoxHacks.Location = new System.Drawing.Point(8, 100);
+ this.checkBoxHacks.Name = "checkBoxHacks";
+ this.checkBoxHacks.Size = new System.Drawing.Size(203, 17);
+ this.checkBoxHacks.TabIndex = 15;
+ this.checkBoxHacks.Text = "Enable hacks for buggy older content";
+ this.checkBoxHacks.UseVisualStyleBackColor = true;
//
- // labelTransparencyPerformance
+ // checkBoxTransparencyFix
//
- this.labelTransparencyPerformance.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.labelTransparencyPerformance.AutoEllipsis = true;
- this.labelTransparencyPerformance.Location = new System.Drawing.Point(130, 136);
- this.labelTransparencyPerformance.Name = "labelTransparencyPerformance";
- this.labelTransparencyPerformance.Size = new System.Drawing.Size(76, 16);
- this.labelTransparencyPerformance.TabIndex = 8;
- this.labelTransparencyPerformance.Text = "Sharp";
- this.labelTransparencyPerformance.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ this.checkBoxTransparencyFix.AutoSize = true;
+ this.checkBoxTransparencyFix.Location = new System.Drawing.Point(8, 81);
+ this.checkBoxTransparencyFix.Name = "checkBoxTransparencyFix";
+ this.checkBoxTransparencyFix.Size = new System.Drawing.Size(259, 17);
+ this.checkBoxTransparencyFix.TabIndex = 14;
+ this.checkBoxTransparencyFix.Text = "Attempt to fix transparency issues in older content";
+ this.checkBoxTransparencyFix.UseVisualStyleBackColor = true;
//
- // labelTransparency
+ // checkBoxUnloadTextures
//
- this.labelTransparency.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelTransparency.AutoEllipsis = true;
- this.labelTransparency.Location = new System.Drawing.Point(8, 100);
- this.labelTransparency.Name = "labelTransparency";
- this.labelTransparency.Size = new System.Drawing.Size(148, 18);
- this.labelTransparency.TabIndex = 6;
- this.labelTransparency.Text = "Transparency:";
- this.labelTransparency.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.checkBoxUnloadTextures.AutoSize = true;
+ this.checkBoxUnloadTextures.Location = new System.Drawing.Point(8, 62);
+ this.checkBoxUnloadTextures.Name = "checkBoxUnloadTextures";
+ this.checkBoxUnloadTextures.Size = new System.Drawing.Size(138, 17);
+ this.checkBoxUnloadTextures.TabIndex = 13;
+ this.checkBoxUnloadTextures.Text = "Unload unused textures";
+ this.checkBoxUnloadTextures.UseVisualStyleBackColor = true;
+ this.checkBoxUnloadTextures.CheckedChanged += new System.EventHandler(this.checkBoxUnloadTextures_CheckedChanged);
//
- // updownAnisotropic
+ // labelTimeAcceleration
//
- this.updownAnisotropic.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownAnisotropic.Enabled = false;
- this.updownAnisotropic.Location = new System.Drawing.Point(156, 40);
- this.updownAnisotropic.Maximum = new decimal(new int[] {
- 16,
+ this.labelTimeAcceleration.AutoSize = true;
+ this.labelTimeAcceleration.Location = new System.Drawing.Point(8, 123);
+ this.labelTimeAcceleration.Name = "labelTimeAcceleration";
+ this.labelTimeAcceleration.Size = new System.Drawing.Size(126, 13);
+ this.labelTimeAcceleration.TabIndex = 10;
+ this.labelTimeAcceleration.Text = "Accelerated Time Factor:";
+ //
+ // updownTimeAccelerationFactor
+ //
+ this.updownTimeAccelerationFactor.Location = new System.Drawing.Point(200, 122);
+ this.updownTimeAccelerationFactor.Maximum = new decimal(new int[] {
+ 5,
0,
0,
0});
- this.updownAnisotropic.Name = "updownAnisotropic";
- this.updownAnisotropic.Size = new System.Drawing.Size(152, 20);
- this.updownAnisotropic.TabIndex = 3;
+ this.updownTimeAccelerationFactor.Name = "updownTimeAccelerationFactor";
+ this.updownTimeAccelerationFactor.Size = new System.Drawing.Size(52, 20);
+ this.updownTimeAccelerationFactor.TabIndex = 16;
+ this.updownTimeAccelerationFactor.ValueChanged += new System.EventHandler(this.updownTimeAccelerationFactor_ValueChanged);
//
- // labelAnisotropic
+ // checkBoxIsUseNewRenderer
//
- this.labelAnisotropic.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelAnisotropic.AutoEllipsis = true;
- this.labelAnisotropic.Enabled = false;
- this.labelAnisotropic.Location = new System.Drawing.Point(8, 42);
- this.labelAnisotropic.Name = "labelAnisotropic";
- this.labelAnisotropic.Size = new System.Drawing.Size(148, 18);
- this.labelAnisotropic.TabIndex = 2;
- this.labelAnisotropic.Text = "Level of anisotropic filtering:";
- this.labelAnisotropic.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.checkBoxIsUseNewRenderer.AutoSize = true;
+ this.checkBoxIsUseNewRenderer.Location = new System.Drawing.Point(8, 43);
+ this.checkBoxIsUseNewRenderer.Name = "checkBoxIsUseNewRenderer";
+ this.checkBoxIsUseNewRenderer.Size = new System.Drawing.Size(159, 17);
+ this.checkBoxIsUseNewRenderer.TabIndex = 2;
+ this.checkBoxIsUseNewRenderer.Text = "Disable OpenGL display lists";
+ this.checkBoxIsUseNewRenderer.UseVisualStyleBackColor = true;
//
- // comboboxInterpolation
+ // checkBoxLoadInAdvance
//
- this.comboboxInterpolation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.comboboxInterpolation.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboboxInterpolation.FormattingEnabled = true;
- this.comboboxInterpolation.Location = new System.Drawing.Point(156, 16);
- this.comboboxInterpolation.Name = "comboboxInterpolation";
- this.comboboxInterpolation.Size = new System.Drawing.Size(152, 21);
- this.comboboxInterpolation.TabIndex = 1;
- this.comboboxInterpolation.SelectedIndexChanged += new System.EventHandler(this.comboboxInterpolation_SelectedIndexChanged);
+ this.checkBoxLoadInAdvance.AutoSize = true;
+ this.checkBoxLoadInAdvance.Location = new System.Drawing.Point(8, 24);
+ this.checkBoxLoadInAdvance.Name = "checkBoxLoadInAdvance";
+ this.checkBoxLoadInAdvance.Size = new System.Drawing.Size(106, 17);
+ this.checkBoxLoadInAdvance.TabIndex = 1;
+ this.checkBoxLoadInAdvance.Text = "Load in advance";
+ this.checkBoxLoadInAdvance.UseVisualStyleBackColor = true;
+ this.checkBoxLoadInAdvance.CheckedChanged += new System.EventHandler(this.checkBoxLoadInAdvance_CheckedChanged);
//
- // labelInterpolation
+ // groupBoxPackageOptions
//
- this.labelInterpolation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.groupBoxPackageOptions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.labelInterpolation.AutoEllipsis = true;
- this.labelInterpolation.Location = new System.Drawing.Point(8, 18);
- this.labelInterpolation.Name = "labelInterpolation";
- this.labelInterpolation.Size = new System.Drawing.Size(148, 18);
- this.labelInterpolation.TabIndex = 0;
- this.labelInterpolation.Text = "Mode:";
- this.labelInterpolation.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.groupBoxPackageOptions.Controls.Add(this.buttonMSTSTrainsetDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.label1);
+ this.groupBoxPackageOptions.Controls.Add(this.textBoxMSTSTrainsetDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.comboBoxCompressionFormat);
+ this.groupBoxPackageOptions.Controls.Add(this.labelPackageCompression);
+ this.groupBoxPackageOptions.Controls.Add(this.buttonOtherDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.labelOtherInstallDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.textBoxOtherDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.buttonTrainInstallationDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.labelTrainInstallDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.textBoxTrainDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.buttonSetRouteDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.labelRouteInstallDirectory);
+ this.groupBoxPackageOptions.Controls.Add(this.textBoxRouteDirectory);
+ this.groupBoxPackageOptions.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxPackageOptions.Location = new System.Drawing.Point(6, 0);
+ this.groupBoxPackageOptions.Name = "groupBoxPackageOptions";
+ this.groupBoxPackageOptions.Size = new System.Drawing.Size(674, 183);
+ this.groupBoxPackageOptions.TabIndex = 19;
+ this.groupBoxPackageOptions.TabStop = false;
+ this.groupBoxPackageOptions.Text = "Package Management";
//
- // trackbarTransparency
+ // buttonMSTSTrainsetDirectory
//
- this.trackbarTransparency.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.trackbarTransparency.Location = new System.Drawing.Point(156, 88);
- this.trackbarTransparency.Maximum = 2;
- this.trackbarTransparency.Name = "trackbarTransparency";
- this.trackbarTransparency.Size = new System.Drawing.Size(152, 45);
- this.trackbarTransparency.TabIndex = 7;
- this.trackbarTransparency.TickStyle = System.Windows.Forms.TickStyle.Both;
+ this.buttonMSTSTrainsetDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.buttonMSTSTrainsetDirectory.BackColor = System.Drawing.SystemColors.Control;
+ this.buttonMSTSTrainsetDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.buttonMSTSTrainsetDirectory.Location = new System.Drawing.Point(593, 114);
+ this.buttonMSTSTrainsetDirectory.Name = "buttonMSTSTrainsetDirectory";
+ this.buttonMSTSTrainsetDirectory.Size = new System.Drawing.Size(75, 26);
+ this.buttonMSTSTrainsetDirectory.TabIndex = 13;
+ this.buttonMSTSTrainsetDirectory.Text = "Choose...";
+ this.buttonMSTSTrainsetDirectory.UseVisualStyleBackColor = true;
+ this.buttonMSTSTrainsetDirectory.Click += new System.EventHandler(this.buttonMSTSTrainsetDirectory_Click);
//
- // panelOptionsRight
+ // label1
//
- this.panelOptionsRight.Controls.Add(this.groupBoxOther);
- this.panelOptionsRight.Controls.Add(this.groupBoxRailDriver);
- this.panelOptionsRight.Controls.Add(this.groupboxDistance);
- this.panelOptionsRight.Controls.Add(this.groupboxControls);
- this.panelOptionsRight.Controls.Add(this.groupboxVerbosity);
- this.panelOptionsRight.Controls.Add(this.groupboxSimulation);
- this.panelOptionsRight.Controls.Add(this.groupboxSound);
- this.panelOptionsRight.Location = new System.Drawing.Point(332, 72);
- this.panelOptionsRight.Name = "panelOptionsRight";
- this.panelOptionsRight.Size = new System.Drawing.Size(316, 579);
- this.panelOptionsRight.TabIndex = 17;
+ this.label1.Location = new System.Drawing.Point(5, 113);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(175, 30);
+ this.label1.TabIndex = 12;
+ this.label1.Text = "MSTS Directory:";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
- // groupBoxOther
+ // textBoxMSTSTrainsetDirectory
//
- this.groupBoxOther.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.textBoxMSTSTrainsetDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxOther.Controls.Add(this.comboBoxTimeTableDisplayMode);
- this.groupBoxOther.Controls.Add(this.labelTimeTableDisplayMode);
- this.groupBoxOther.ForeColor = System.Drawing.Color.Black;
- this.groupBoxOther.Location = new System.Drawing.Point(0, 468);
- this.groupBoxOther.Name = "groupBoxOther";
- this.groupBoxOther.Size = new System.Drawing.Size(316, 48);
- this.groupBoxOther.TabIndex = 19;
- this.groupBoxOther.TabStop = false;
- this.groupBoxOther.Text = "Other";
+ this.textBoxMSTSTrainsetDirectory.BackColor = System.Drawing.SystemColors.Control;
+ this.textBoxMSTSTrainsetDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.textBoxMSTSTrainsetDirectory.Location = new System.Drawing.Point(199, 117);
+ this.textBoxMSTSTrainsetDirectory.Name = "textBoxMSTSTrainsetDirectory";
+ this.textBoxMSTSTrainsetDirectory.ReadOnly = true;
+ this.textBoxMSTSTrainsetDirectory.Size = new System.Drawing.Size(387, 20);
+ this.textBoxMSTSTrainsetDirectory.TabIndex = 11;
//
- // comboBoxTimeTableDisplayMode
+ // comboBoxCompressionFormat
//
- this.comboBoxTimeTableDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.comboBoxTimeTableDisplayMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboBoxTimeTableDisplayMode.FormattingEnabled = true;
- this.comboBoxTimeTableDisplayMode.Location = new System.Drawing.Point(156, 16);
- this.comboBoxTimeTableDisplayMode.Name = "comboBoxTimeTableDisplayMode";
- this.comboBoxTimeTableDisplayMode.Size = new System.Drawing.Size(152, 21);
- this.comboBoxTimeTableDisplayMode.TabIndex = 1;
- this.comboBoxTimeTableDisplayMode.SelectedIndexChanged += new System.EventHandler(this.comboBoxTimeTableDisplayMode_SelectedIndexChanged);
+ this.comboBoxCompressionFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBoxCompressionFormat.Items.AddRange(new object[] {
+ "LZMA ZIP ( .zip )",
+ "GZip ( .tgz )",
+ "BZip2 ( .bz2 )"});
+ this.comboBoxCompressionFormat.Location = new System.Drawing.Point(202, 146);
+ this.comboBoxCompressionFormat.Name = "comboBoxCompressionFormat";
+ this.comboBoxCompressionFormat.Size = new System.Drawing.Size(188, 21);
+ this.comboBoxCompressionFormat.TabIndex = 10;
+ this.comboBoxCompressionFormat.SelectedIndexChanged += new System.EventHandler(this.comboBoxCompressionFormat_SelectedIndexChanged);
//
- // labelTimeTableDisplayMode
+ // labelPackageCompression
//
- this.labelTimeTableDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.labelPackageCompression.AutoSize = true;
+ this.labelPackageCompression.Location = new System.Drawing.Point(8, 150);
+ this.labelPackageCompression.Name = "labelPackageCompression";
+ this.labelPackageCompression.Size = new System.Drawing.Size(147, 13);
+ this.labelPackageCompression.TabIndex = 9;
+ this.labelPackageCompression.Text = "Package compression format:";
+ //
+ // buttonOtherDirectory
+ //
+ this.buttonOtherDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.buttonOtherDirectory.BackColor = System.Drawing.SystemColors.Control;
+ this.buttonOtherDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.buttonOtherDirectory.Location = new System.Drawing.Point(594, 81);
+ this.buttonOtherDirectory.Name = "buttonOtherDirectory";
+ this.buttonOtherDirectory.Size = new System.Drawing.Size(75, 26);
+ this.buttonOtherDirectory.TabIndex = 8;
+ this.buttonOtherDirectory.Text = "Choose...";
+ this.buttonOtherDirectory.UseVisualStyleBackColor = true;
+ this.buttonOtherDirectory.Click += new System.EventHandler(this.buttonOtherDirectory_Click);
+ //
+ // labelOtherInstallDirectory
+ //
+ this.labelOtherInstallDirectory.Location = new System.Drawing.Point(6, 80);
+ this.labelOtherInstallDirectory.Name = "labelOtherInstallDirectory";
+ this.labelOtherInstallDirectory.Size = new System.Drawing.Size(175, 30);
+ this.labelOtherInstallDirectory.TabIndex = 7;
+ this.labelOtherInstallDirectory.Text = "Other items installation directory:";
+ this.labelOtherInstallDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // textBoxOtherDirectory
+ //
+ this.textBoxOtherDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.labelTimeTableDisplayMode.AutoEllipsis = true;
- this.labelTimeTableDisplayMode.Location = new System.Drawing.Point(3, 17);
- this.labelTimeTableDisplayMode.Name = "labelTimeTableDisplayMode";
- this.labelTimeTableDisplayMode.Size = new System.Drawing.Size(153, 18);
- this.labelTimeTableDisplayMode.TabIndex = 0;
- this.labelTimeTableDisplayMode.Text = "Timetable Display Mode:";
- this.labelTimeTableDisplayMode.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.textBoxOtherDirectory.BackColor = System.Drawing.SystemColors.Control;
+ this.textBoxOtherDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.textBoxOtherDirectory.Location = new System.Drawing.Point(200, 84);
+ this.textBoxOtherDirectory.Name = "textBoxOtherDirectory";
+ this.textBoxOtherDirectory.ReadOnly = true;
+ this.textBoxOtherDirectory.Size = new System.Drawing.Size(387, 20);
+ this.textBoxOtherDirectory.TabIndex = 6;
//
- // groupBoxRailDriver
+ // buttonTrainInstallationDirectory
//
- this.groupBoxRailDriver.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxRailDriver.Controls.Add(this.labelRailDriverCalibration);
- this.groupBoxRailDriver.Controls.Add(this.buttonRailDriverCalibration);
- this.groupBoxRailDriver.Controls.Add(this.comboBoxRailDriverUnits);
- this.groupBoxRailDriver.Controls.Add(this.labelRailDriverSpeedUnits);
- this.groupBoxRailDriver.ForeColor = System.Drawing.Color.Black;
- this.groupBoxRailDriver.Location = new System.Drawing.Point(0, 230);
- this.groupBoxRailDriver.Name = "groupBoxRailDriver";
- this.groupBoxRailDriver.Size = new System.Drawing.Size(316, 75);
- this.groupBoxRailDriver.TabIndex = 21;
- this.groupBoxRailDriver.TabStop = false;
- this.groupBoxRailDriver.Text = "RailDriver";
+ this.buttonTrainInstallationDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.buttonTrainInstallationDirectory.BackColor = System.Drawing.SystemColors.ButtonFace;
+ this.buttonTrainInstallationDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.buttonTrainInstallationDirectory.Location = new System.Drawing.Point(594, 49);
+ this.buttonTrainInstallationDirectory.Name = "buttonTrainInstallationDirectory";
+ this.buttonTrainInstallationDirectory.Size = new System.Drawing.Size(75, 26);
+ this.buttonTrainInstallationDirectory.TabIndex = 5;
+ this.buttonTrainInstallationDirectory.Text = "Choose...";
+ this.buttonTrainInstallationDirectory.UseVisualStyleBackColor = true;
+ this.buttonTrainInstallationDirectory.Click += new System.EventHandler(this.buttonTrainInstallationDirectory_Click);
//
- // labelRailDriverCalibration
+ // labelTrainInstallDirectory
//
- this.labelRailDriverCalibration.AutoSize = true;
- this.labelRailDriverCalibration.Location = new System.Drawing.Point(7, 46);
- this.labelRailDriverCalibration.Name = "labelRailDriverCalibration";
- this.labelRailDriverCalibration.Size = new System.Drawing.Size(78, 13);
- this.labelRailDriverCalibration.TabIndex = 5;
- this.labelRailDriverCalibration.Text = "Set Calibration:";
+ this.labelTrainInstallDirectory.AutoSize = true;
+ this.labelTrainInstallDirectory.Location = new System.Drawing.Point(6, 52);
+ this.labelTrainInstallDirectory.Name = "labelTrainInstallDirectory";
+ this.labelTrainInstallDirectory.Size = new System.Drawing.Size(129, 13);
+ this.labelTrainInstallDirectory.TabIndex = 4;
+ this.labelTrainInstallDirectory.Text = "Train installation directory:";
//
- // buttonRailDriverCalibration
+ // textBoxTrainDirectory
//
- this.buttonRailDriverCalibration.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonRailDriverCalibration.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonRailDriverCalibration.Location = new System.Drawing.Point(230, 42);
- this.buttonRailDriverCalibration.Name = "buttonRailDriverCalibration";
- this.buttonRailDriverCalibration.Size = new System.Drawing.Size(75, 26);
- this.buttonRailDriverCalibration.TabIndex = 4;
- this.buttonRailDriverCalibration.Text = "Launch...";
- this.buttonRailDriverCalibration.UseVisualStyleBackColor = true;
- this.buttonRailDriverCalibration.Click += new System.EventHandler(this.buttonRailDriverCalibration_Click);
+ this.textBoxTrainDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.textBoxTrainDirectory.BackColor = System.Drawing.SystemColors.Control;
+ this.textBoxTrainDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.textBoxTrainDirectory.Location = new System.Drawing.Point(200, 51);
+ this.textBoxTrainDirectory.Name = "textBoxTrainDirectory";
+ this.textBoxTrainDirectory.ReadOnly = true;
+ this.textBoxTrainDirectory.Size = new System.Drawing.Size(387, 20);
+ this.textBoxTrainDirectory.TabIndex = 3;
//
- // comboBoxRailDriverUnits
+ // buttonSetRouteDirectory
//
- this.comboBoxRailDriverUnits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboBoxRailDriverUnits.FormattingEnabled = true;
- this.comboBoxRailDriverUnits.Items.AddRange(new object[] {
- "Miles per Hour (MPH)",
- "Kilometers per Hour (KPH)"});
- this.comboBoxRailDriverUnits.Location = new System.Drawing.Point(140, 16);
- this.comboBoxRailDriverUnits.Name = "comboBoxRailDriverUnits";
- this.comboBoxRailDriverUnits.Size = new System.Drawing.Size(165, 21);
- this.comboBoxRailDriverUnits.TabIndex = 3;
- this.comboBoxRailDriverUnits.SelectedIndexChanged += new System.EventHandler(this.comboBoxRailDriverUnits_SelectedIndexChanged);
+ this.buttonSetRouteDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.buttonSetRouteDirectory.BackColor = System.Drawing.SystemColors.ButtonFace;
+ this.buttonSetRouteDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.buttonSetRouteDirectory.Location = new System.Drawing.Point(594, 18);
+ this.buttonSetRouteDirectory.Name = "buttonSetRouteDirectory";
+ this.buttonSetRouteDirectory.Size = new System.Drawing.Size(75, 26);
+ this.buttonSetRouteDirectory.TabIndex = 2;
+ this.buttonSetRouteDirectory.Text = "Choose...";
+ this.buttonSetRouteDirectory.UseVisualStyleBackColor = true;
+ this.buttonSetRouteDirectory.Click += new System.EventHandler(this.buttonSetRouteDirectory_Click);
//
- // labelRailDriverSpeedUnits
+ // labelRouteInstallDirectory
//
- this.labelRailDriverSpeedUnits.Location = new System.Drawing.Point(7, 14);
- this.labelRailDriverSpeedUnits.Name = "labelRailDriverSpeedUnits";
- this.labelRailDriverSpeedUnits.Size = new System.Drawing.Size(130, 30);
- this.labelRailDriverSpeedUnits.TabIndex = 2;
- this.labelRailDriverSpeedUnits.Text = "LED Display speed units:";
- this.labelRailDriverSpeedUnits.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.labelRouteInstallDirectory.AutoSize = true;
+ this.labelRouteInstallDirectory.Location = new System.Drawing.Point(6, 21);
+ this.labelRouteInstallDirectory.Name = "labelRouteInstallDirectory";
+ this.labelRouteInstallDirectory.Size = new System.Drawing.Size(134, 13);
+ this.labelRouteInstallDirectory.TabIndex = 1;
+ this.labelRouteInstallDirectory.Text = "Route installation directory:";
//
- // groupboxDistance
+ // textBoxRouteDirectory
//
- this.groupboxDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.textBoxRouteDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxDistance.Controls.Add(this.comboboxMotionBlur);
- this.groupboxDistance.Controls.Add(this.labelMotionBlur);
- this.groupboxDistance.Controls.Add(this.labelDistanceUnit);
- this.groupboxDistance.Controls.Add(this.updownDistance);
- this.groupboxDistance.Controls.Add(this.labelDistance);
- this.groupboxDistance.ForeColor = System.Drawing.Color.Black;
- this.groupboxDistance.Location = new System.Drawing.Point(0, 0);
- this.groupboxDistance.Name = "groupboxDistance";
- this.groupboxDistance.Size = new System.Drawing.Size(316, 80);
- this.groupboxDistance.TabIndex = 8;
- this.groupboxDistance.TabStop = false;
- this.groupboxDistance.Text = "Distance effects";
+ this.textBoxRouteDirectory.BackColor = System.Drawing.SystemColors.Control;
+ this.textBoxRouteDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.textBoxRouteDirectory.Location = new System.Drawing.Point(200, 20);
+ this.textBoxRouteDirectory.Name = "textBoxRouteDirectory";
+ this.textBoxRouteDirectory.ReadOnly = true;
+ this.textBoxRouteDirectory.Size = new System.Drawing.Size(387, 20);
+ this.textBoxRouteDirectory.TabIndex = 0;
//
- // comboboxMotionBlur
+ // panelOptionsLeft
//
- this.comboboxMotionBlur.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.comboboxMotionBlur.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboboxMotionBlur.FormattingEnabled = true;
- this.comboboxMotionBlur.Location = new System.Drawing.Point(144, 48);
- this.comboboxMotionBlur.Name = "comboboxMotionBlur";
- this.comboboxMotionBlur.Size = new System.Drawing.Size(152, 21);
- this.comboboxMotionBlur.TabIndex = 4;
+ this.panelOptionsLeft.Controls.Add(this.groupboxDisplayMode);
+ this.panelOptionsLeft.Controls.Add(this.groupboxWindow);
+ this.panelOptionsLeft.Controls.Add(this.groupboxFullscreen);
+ this.panelOptionsLeft.Controls.Add(this.groupboxInterpolation);
+ this.panelOptionsLeft.Location = new System.Drawing.Point(8, 72);
+ this.panelOptionsLeft.Name = "panelOptionsLeft";
+ this.panelOptionsLeft.Size = new System.Drawing.Size(316, 576);
+ this.panelOptionsLeft.TabIndex = 16;
//
- // labelMotionBlur
+ // groupboxDisplayMode
//
- this.labelMotionBlur.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.groupboxDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.labelMotionBlur.AutoEllipsis = true;
- this.labelMotionBlur.Location = new System.Drawing.Point(5, 51);
- this.labelMotionBlur.Name = "labelMotionBlur";
- this.labelMotionBlur.Size = new System.Drawing.Size(140, 18);
- this.labelMotionBlur.TabIndex = 3;
- this.labelMotionBlur.Text = "Motion blur:";
- this.labelMotionBlur.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // labelDistanceUnit
- //
- this.labelDistanceUnit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.labelDistanceUnit.AutoEllipsis = true;
- this.labelDistanceUnit.Location = new System.Drawing.Point(272, 24);
- this.labelDistanceUnit.Name = "labelDistanceUnit";
- this.labelDistanceUnit.Size = new System.Drawing.Size(24, 18);
- this.labelDistanceUnit.TabIndex = 2;
- this.labelDistanceUnit.Text = "m";
+ this.groupboxDisplayMode.Controls.Add(this.comboBoxFont);
+ this.groupboxDisplayMode.Controls.Add(this.labelFontName);
+ this.groupboxDisplayMode.Controls.Add(this.labelHUDLarge);
+ this.groupboxDisplayMode.Controls.Add(this.labelHUDNormal);
+ this.groupboxDisplayMode.Controls.Add(this.labelHUDSmall);
+ this.groupboxDisplayMode.Controls.Add(this.trackBarHUDSize);
+ this.groupboxDisplayMode.Controls.Add(this.labelHUDScale);
+ this.groupboxDisplayMode.Controls.Add(this.comboboxVSync);
+ this.groupboxDisplayMode.Controls.Add(this.labelVSync);
+ this.groupboxDisplayMode.Controls.Add(this.radiobuttonFullscreen);
+ this.groupboxDisplayMode.Controls.Add(this.radiobuttonWindow);
+ this.groupboxDisplayMode.ForeColor = System.Drawing.Color.Black;
+ this.groupboxDisplayMode.Location = new System.Drawing.Point(0, 0);
+ this.groupboxDisplayMode.Name = "groupboxDisplayMode";
+ this.groupboxDisplayMode.Size = new System.Drawing.Size(316, 189);
+ this.groupboxDisplayMode.TabIndex = 4;
+ this.groupboxDisplayMode.TabStop = false;
+ this.groupboxDisplayMode.Text = "Display mode";
//
- // updownDistance
+ // comboBoxFont
//
- this.updownDistance.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownDistance.Location = new System.Drawing.Point(144, 24);
- this.updownDistance.Maximum = new decimal(new int[] {
- 100000,
- 0,
- 0,
- 0});
- this.updownDistance.Minimum = new decimal(new int[] {
- 100,
- 0,
- 0,
- 0});
- this.updownDistance.Name = "updownDistance";
- this.updownDistance.Size = new System.Drawing.Size(128, 20);
- this.updownDistance.TabIndex = 1;
- this.updownDistance.Value = new decimal(new int[] {
- 600,
- 0,
- 0,
- 0});
+ this.comboBoxFont.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboBoxFont.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBoxFont.FormattingEnabled = true;
+ this.comboBoxFont.Location = new System.Drawing.Point(45, 155);
+ this.comboBoxFont.Name = "comboBoxFont";
+ this.comboBoxFont.Size = new System.Drawing.Size(264, 21);
+ this.comboBoxFont.TabIndex = 14;
+ this.comboBoxFont.SelectionChangeCommitted += new System.EventHandler(this.comboBoxFont_SelectedIndexChanged);
//
- // labelDistance
+ // labelFontName
//
- this.labelDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelDistance.AutoEllipsis = true;
- this.labelDistance.Location = new System.Drawing.Point(9, 26);
- this.labelDistance.Name = "labelDistance";
- this.labelDistance.Size = new System.Drawing.Size(136, 18);
- this.labelDistance.TabIndex = 0;
- this.labelDistance.Text = "Viewing distance:";
- this.labelDistance.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.labelFontName.Location = new System.Drawing.Point(8, 148);
+ this.labelFontName.Name = "labelFontName";
+ this.labelFontName.Size = new System.Drawing.Size(50, 36);
+ this.labelFontName.TabIndex = 13;
+ this.labelFontName.Text = "Font:";
+ this.labelFontName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
- // groupboxControls
+ // labelHUDLarge
//
- this.groupboxControls.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxControls.Controls.Add(this.checkBoxEBAxis);
- this.groupboxControls.Controls.Add(this.trackbarJoystickAxisThreshold);
- this.groupboxControls.Controls.Add(this.checkboxJoysticksUsed);
- this.groupboxControls.Controls.Add(this.labelJoystickAxisThreshold);
- this.groupboxControls.ForeColor = System.Drawing.Color.Black;
- this.groupboxControls.Location = new System.Drawing.Point(0, 144);
- this.groupboxControls.Name = "groupboxControls";
- this.groupboxControls.Size = new System.Drawing.Size(316, 80);
- this.groupboxControls.TabIndex = 10;
- this.groupboxControls.TabStop = false;
- this.groupboxControls.Text = "Controls";
+ this.labelHUDLarge.Location = new System.Drawing.Point(258, 125);
+ this.labelHUDLarge.Name = "labelHUDLarge";
+ this.labelHUDLarge.Size = new System.Drawing.Size(72, 48);
+ this.labelHUDLarge.TabIndex = 12;
+ this.labelHUDLarge.Text = "Large";
+ this.labelHUDLarge.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
- // checkBoxEBAxis
+ // labelHUDNormal
//
- this.checkBoxEBAxis.Checked = true;
- this.checkBoxEBAxis.CheckState = System.Windows.Forms.CheckState.Checked;
- this.checkBoxEBAxis.Location = new System.Drawing.Point(8, 41);
- this.checkBoxEBAxis.Name = "checkBoxEBAxis";
- this.checkBoxEBAxis.Size = new System.Drawing.Size(190, 36);
- this.checkBoxEBAxis.TabIndex = 18;
- this.checkBoxEBAxis.Text = "Allow EB on brake axis";
- this.checkBoxEBAxis.UseVisualStyleBackColor = true;
+ this.labelHUDNormal.Location = new System.Drawing.Point(162, 125);
+ this.labelHUDNormal.Name = "labelHUDNormal";
+ this.labelHUDNormal.Size = new System.Drawing.Size(70, 48);
+ this.labelHUDNormal.TabIndex = 11;
+ this.labelHUDNormal.Text = "Normal";
+ this.labelHUDNormal.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
- // trackbarJoystickAxisThreshold
+ // labelHUDSmall
//
- this.trackbarJoystickAxisThreshold.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.trackbarJoystickAxisThreshold.LargeChange = 10;
- this.trackbarJoystickAxisThreshold.Location = new System.Drawing.Point(200, 32);
- this.trackbarJoystickAxisThreshold.Maximum = 100;
- this.trackbarJoystickAxisThreshold.Name = "trackbarJoystickAxisThreshold";
- this.trackbarJoystickAxisThreshold.Size = new System.Drawing.Size(96, 45);
- this.trackbarJoystickAxisThreshold.TabIndex = 2;
- this.trackbarJoystickAxisThreshold.TickFrequency = 10;
- this.trackbarJoystickAxisThreshold.TickStyle = System.Windows.Forms.TickStyle.Both;
+ this.labelHUDSmall.Location = new System.Drawing.Point(66, 125);
+ this.labelHUDSmall.Name = "labelHUDSmall";
+ this.labelHUDSmall.Size = new System.Drawing.Size(70, 48);
+ this.labelHUDSmall.TabIndex = 10;
+ this.labelHUDSmall.Text = "Small";
+ this.labelHUDSmall.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
- // checkboxJoysticksUsed
+ // trackBarHUDSize
//
- this.checkboxJoysticksUsed.AutoSize = true;
- this.checkboxJoysticksUsed.Location = new System.Drawing.Point(8, 24);
- this.checkboxJoysticksUsed.Name = "checkboxJoysticksUsed";
- this.checkboxJoysticksUsed.Size = new System.Drawing.Size(110, 17);
- this.checkboxJoysticksUsed.TabIndex = 0;
- this.checkboxJoysticksUsed.Text = "Joysticks enabled";
- this.checkboxJoysticksUsed.UseVisualStyleBackColor = true;
- this.checkboxJoysticksUsed.CheckedChanged += new System.EventHandler(this.checkboxJoysticksUsed_CheckedChanged);
+ this.trackBarHUDSize.LargeChange = 1;
+ this.trackBarHUDSize.Location = new System.Drawing.Point(88, 100);
+ this.trackBarHUDSize.Maximum = 2;
+ this.trackBarHUDSize.Name = "trackBarHUDSize";
+ this.trackBarHUDSize.Size = new System.Drawing.Size(220, 45);
+ this.trackBarHUDSize.TabIndex = 9;
+ this.trackBarHUDSize.Value = 1;
//
- // labelJoystickAxisThreshold
+ // labelHUDScale
//
- this.labelJoystickAxisThreshold.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.labelJoystickAxisThreshold.AutoEllipsis = true;
- this.labelJoystickAxisThreshold.Location = new System.Drawing.Point(110, 10);
- this.labelJoystickAxisThreshold.Name = "labelJoystickAxisThreshold";
- this.labelJoystickAxisThreshold.Size = new System.Drawing.Size(180, 18);
- this.labelJoystickAxisThreshold.TabIndex = 1;
- this.labelJoystickAxisThreshold.Text = "Joystick threshold:";
- this.labelJoystickAxisThreshold.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.labelHUDScale.AutoSize = true;
+ this.labelHUDScale.Location = new System.Drawing.Point(8, 106);
+ this.labelHUDScale.Name = "labelHUDScale";
+ this.labelHUDScale.Size = new System.Drawing.Size(54, 13);
+ this.labelHUDScale.TabIndex = 8;
+ this.labelHUDScale.Text = "HUD Size";
//
- // groupboxVerbosity
+ // comboboxVSync
//
- this.groupboxVerbosity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxVerbosity.Controls.Add(this.checkBoxAccessibility);
- this.groupboxVerbosity.Controls.Add(this.checkboxErrorMessages);
- this.groupboxVerbosity.Controls.Add(this.checkboxWarningMessages);
- this.groupboxVerbosity.ForeColor = System.Drawing.Color.Black;
- this.groupboxVerbosity.Location = new System.Drawing.Point(0, 396);
- this.groupboxVerbosity.Name = "groupboxVerbosity";
- this.groupboxVerbosity.Size = new System.Drawing.Size(316, 64);
- this.groupboxVerbosity.TabIndex = 12;
- this.groupboxVerbosity.TabStop = false;
- this.groupboxVerbosity.Text = "Verbosity";
+ this.comboboxVSync.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboboxVSync.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboboxVSync.FormattingEnabled = true;
+ this.comboboxVSync.Location = new System.Drawing.Point(156, 72);
+ this.comboboxVSync.Name = "comboboxVSync";
+ this.comboboxVSync.Size = new System.Drawing.Size(152, 21);
+ this.comboboxVSync.TabIndex = 7;
//
- // checkBoxAccessibility
+ // labelVSync
//
- this.checkBoxAccessibility.AutoSize = true;
- this.checkBoxAccessibility.Location = new System.Drawing.Point(176, 21);
- this.checkBoxAccessibility.Name = "checkBoxAccessibility";
- this.checkBoxAccessibility.Size = new System.Drawing.Size(106, 17);
- this.checkBoxAccessibility.TabIndex = 2;
- this.checkBoxAccessibility.Text = "Accessibility Aids";
- this.checkBoxAccessibility.UseVisualStyleBackColor = true;
+ this.labelVSync.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelVSync.AutoEllipsis = true;
+ this.labelVSync.Location = new System.Drawing.Point(8, 72);
+ this.labelVSync.Name = "labelVSync";
+ this.labelVSync.Size = new System.Drawing.Size(148, 18);
+ this.labelVSync.TabIndex = 2;
+ this.labelVSync.Text = "Vertical syncronization:";
+ this.labelVSync.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // checkboxErrorMessages
+ // radiobuttonFullscreen
//
- this.checkboxErrorMessages.AutoSize = true;
- this.checkboxErrorMessages.Location = new System.Drawing.Point(8, 38);
- this.checkboxErrorMessages.Name = "checkboxErrorMessages";
- this.checkboxErrorMessages.Size = new System.Drawing.Size(127, 17);
- this.checkboxErrorMessages.TabIndex = 1;
- this.checkboxErrorMessages.Text = "Show error messages";
- this.checkboxErrorMessages.UseVisualStyleBackColor = true;
+ this.radiobuttonFullscreen.AutoSize = true;
+ this.radiobuttonFullscreen.Location = new System.Drawing.Point(8, 48);
+ this.radiobuttonFullscreen.Name = "radiobuttonFullscreen";
+ this.radiobuttonFullscreen.Size = new System.Drawing.Size(102, 17);
+ this.radiobuttonFullscreen.TabIndex = 1;
+ this.radiobuttonFullscreen.TabStop = true;
+ this.radiobuttonFullscreen.Text = "Fullscreen mode";
+ this.radiobuttonFullscreen.UseVisualStyleBackColor = true;
//
- // checkboxWarningMessages
+ // radiobuttonWindow
//
- this.checkboxWarningMessages.AutoSize = true;
- this.checkboxWarningMessages.Location = new System.Drawing.Point(8, 21);
- this.checkboxWarningMessages.Name = "checkboxWarningMessages";
- this.checkboxWarningMessages.Size = new System.Drawing.Size(143, 17);
- this.checkboxWarningMessages.TabIndex = 0;
- this.checkboxWarningMessages.Text = "Show warning messages";
- this.checkboxWarningMessages.UseVisualStyleBackColor = true;
+ this.radiobuttonWindow.AutoSize = true;
+ this.radiobuttonWindow.Checked = true;
+ this.radiobuttonWindow.Location = new System.Drawing.Point(8, 24);
+ this.radiobuttonWindow.Name = "radiobuttonWindow";
+ this.radiobuttonWindow.Size = new System.Drawing.Size(93, 17);
+ this.radiobuttonWindow.TabIndex = 0;
+ this.radiobuttonWindow.TabStop = true;
+ this.radiobuttonWindow.Text = "Window mode";
+ this.radiobuttonWindow.UseVisualStyleBackColor = true;
//
- // groupboxSimulation
+ // groupboxWindow
//
- this.groupboxSimulation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.groupboxWindow.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxSimulation.Controls.Add(this.checkBoxLoadingSway);
- this.groupboxSimulation.Controls.Add(this.checkboxBlackBox);
- this.groupboxSimulation.Controls.Add(this.checkboxDerailments);
- this.groupboxSimulation.Controls.Add(this.checkboxCollisions);
- this.groupboxSimulation.Controls.Add(this.checkboxToppling);
- this.groupboxSimulation.ForeColor = System.Drawing.Color.Black;
- this.groupboxSimulation.Location = new System.Drawing.Point(0, 310);
- this.groupboxSimulation.Name = "groupboxSimulation";
- this.groupboxSimulation.Size = new System.Drawing.Size(316, 80);
- this.groupboxSimulation.TabIndex = 11;
- this.groupboxSimulation.TabStop = false;
- this.groupboxSimulation.Text = "Detail of simulation";
+ this.groupboxWindow.Controls.Add(this.updownWindowHeight);
+ this.groupboxWindow.Controls.Add(this.labelWindowHeight);
+ this.groupboxWindow.Controls.Add(this.updownWindowWidth);
+ this.groupboxWindow.Controls.Add(this.labelWindowWidth);
+ this.groupboxWindow.ForeColor = System.Drawing.Color.Black;
+ this.groupboxWindow.Location = new System.Drawing.Point(0, 192);
+ this.groupboxWindow.Name = "groupboxWindow";
+ this.groupboxWindow.Size = new System.Drawing.Size(316, 80);
+ this.groupboxWindow.TabIndex = 5;
+ this.groupboxWindow.TabStop = false;
+ this.groupboxWindow.Text = "Window mode";
//
- // checkBoxLoadingSway
+ // updownWindowHeight
//
- this.checkBoxLoadingSway.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.checkBoxLoadingSway.AutoSize = true;
- this.checkBoxLoadingSway.Location = new System.Drawing.Point(176, 21);
- this.checkBoxLoadingSway.Name = "checkBoxLoadingSway";
- this.checkBoxLoadingSway.Size = new System.Drawing.Size(123, 17);
- this.checkBoxLoadingSway.TabIndex = 4;
- this.checkBoxLoadingSway.Text = "Enable loading sway";
- this.checkBoxLoadingSway.UseVisualStyleBackColor = true;
+ this.updownWindowHeight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownWindowHeight.Location = new System.Drawing.Point(156, 48);
+ this.updownWindowHeight.Maximum = new decimal(new int[] {
+ 1048575,
+ 0,
+ 0,
+ 0});
+ this.updownWindowHeight.Minimum = new decimal(new int[] {
+ 16,
+ 0,
+ 0,
+ 0});
+ this.updownWindowHeight.Name = "updownWindowHeight";
+ this.updownWindowHeight.Size = new System.Drawing.Size(152, 20);
+ this.updownWindowHeight.TabIndex = 3;
+ this.updownWindowHeight.Value = new decimal(new int[] {
+ 600,
+ 0,
+ 0,
+ 0});
//
- // checkboxBlackBox
+ // labelWindowHeight
//
- this.checkboxBlackBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
+ this.labelWindowHeight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.checkboxBlackBox.AutoSize = true;
- this.checkboxBlackBox.Location = new System.Drawing.Point(176, 38);
- this.checkboxBlackBox.Name = "checkboxBlackBox";
- this.checkboxBlackBox.Size = new System.Drawing.Size(108, 17);
- this.checkboxBlackBox.TabIndex = 3;
- this.checkboxBlackBox.Text = "Enable black box";
- this.checkboxBlackBox.UseVisualStyleBackColor = true;
+ this.labelWindowHeight.AutoEllipsis = true;
+ this.labelWindowHeight.Location = new System.Drawing.Point(8, 50);
+ this.labelWindowHeight.Name = "labelWindowHeight";
+ this.labelWindowHeight.Size = new System.Drawing.Size(148, 18);
+ this.labelWindowHeight.TabIndex = 2;
+ this.labelWindowHeight.Text = "Height:";
+ this.labelWindowHeight.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // checkboxDerailments
+ // updownWindowWidth
//
- this.checkboxDerailments.AutoSize = true;
- this.checkboxDerailments.Location = new System.Drawing.Point(8, 55);
- this.checkboxDerailments.Name = "checkboxDerailments";
- this.checkboxDerailments.Size = new System.Drawing.Size(81, 17);
- this.checkboxDerailments.TabIndex = 2;
- this.checkboxDerailments.Text = "Derailments";
- this.checkboxDerailments.UseVisualStyleBackColor = true;
+ this.updownWindowWidth.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownWindowWidth.Location = new System.Drawing.Point(156, 24);
+ this.updownWindowWidth.Maximum = new decimal(new int[] {
+ 1048575,
+ 0,
+ 0,
+ 0});
+ this.updownWindowWidth.Minimum = new decimal(new int[] {
+ 16,
+ 0,
+ 0,
+ 0});
+ this.updownWindowWidth.Name = "updownWindowWidth";
+ this.updownWindowWidth.Size = new System.Drawing.Size(152, 20);
+ this.updownWindowWidth.TabIndex = 1;
+ this.updownWindowWidth.Value = new decimal(new int[] {
+ 960,
+ 0,
+ 0,
+ 0});
//
- // checkboxCollisions
+ // labelWindowWidth
//
- this.checkboxCollisions.AutoSize = true;
- this.checkboxCollisions.Location = new System.Drawing.Point(8, 38);
- this.checkboxCollisions.Name = "checkboxCollisions";
- this.checkboxCollisions.Size = new System.Drawing.Size(69, 17);
- this.checkboxCollisions.TabIndex = 1;
- this.checkboxCollisions.Text = "Collisions";
- this.checkboxCollisions.UseVisualStyleBackColor = true;
+ this.labelWindowWidth.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelWindowWidth.AutoEllipsis = true;
+ this.labelWindowWidth.Location = new System.Drawing.Point(8, 26);
+ this.labelWindowWidth.Name = "labelWindowWidth";
+ this.labelWindowWidth.Size = new System.Drawing.Size(148, 18);
+ this.labelWindowWidth.TabIndex = 0;
+ this.labelWindowWidth.Text = "Width:";
+ this.labelWindowWidth.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // checkboxToppling
+ // groupboxFullscreen
//
- this.checkboxToppling.AutoSize = true;
- this.checkboxToppling.Location = new System.Drawing.Point(8, 21);
- this.checkboxToppling.Name = "checkboxToppling";
- this.checkboxToppling.Size = new System.Drawing.Size(67, 17);
- this.checkboxToppling.TabIndex = 0;
- this.checkboxToppling.Text = "Toppling";
- this.checkboxToppling.UseVisualStyleBackColor = true;
+ this.groupboxFullscreen.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupboxFullscreen.Controls.Add(this.comboboxFullscreenBits);
+ this.groupboxFullscreen.Controls.Add(this.labelFullscreenBits);
+ this.groupboxFullscreen.Controls.Add(this.updownFullscreenHeight);
+ this.groupboxFullscreen.Controls.Add(this.labelFullscreenHeight);
+ this.groupboxFullscreen.Controls.Add(this.updownFullscreenWidth);
+ this.groupboxFullscreen.Controls.Add(this.labelFullscreenWidth);
+ this.groupboxFullscreen.ForeColor = System.Drawing.Color.Black;
+ this.groupboxFullscreen.Location = new System.Drawing.Point(0, 275);
+ this.groupboxFullscreen.Name = "groupboxFullscreen";
+ this.groupboxFullscreen.Size = new System.Drawing.Size(316, 104);
+ this.groupboxFullscreen.TabIndex = 6;
+ this.groupboxFullscreen.TabStop = false;
+ this.groupboxFullscreen.Text = "Fullscreen mode";
//
- // groupboxSound
+ // comboboxFullscreenBits
//
- this.groupboxSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.comboboxFullscreenBits.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboboxFullscreenBits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboboxFullscreenBits.FormattingEnabled = true;
+ this.comboboxFullscreenBits.Location = new System.Drawing.Point(156, 72);
+ this.comboboxFullscreenBits.Name = "comboboxFullscreenBits";
+ this.comboboxFullscreenBits.Size = new System.Drawing.Size(152, 21);
+ this.comboboxFullscreenBits.TabIndex = 5;
+ //
+ // labelFullscreenBits
+ //
+ this.labelFullscreenBits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupboxSound.Controls.Add(this.updownSoundNumber);
- this.groupboxSound.Controls.Add(this.labelSoundNumber);
- this.groupboxSound.ForeColor = System.Drawing.Color.Black;
- this.groupboxSound.Location = new System.Drawing.Point(0, 88);
- this.groupboxSound.Name = "groupboxSound";
- this.groupboxSound.Size = new System.Drawing.Size(316, 48);
- this.groupboxSound.TabIndex = 9;
- this.groupboxSound.TabStop = false;
- this.groupboxSound.Text = "Sound";
+ this.labelFullscreenBits.AutoEllipsis = true;
+ this.labelFullscreenBits.Location = new System.Drawing.Point(8, 74);
+ this.labelFullscreenBits.Name = "labelFullscreenBits";
+ this.labelFullscreenBits.Size = new System.Drawing.Size(148, 18);
+ this.labelFullscreenBits.TabIndex = 4;
+ this.labelFullscreenBits.Text = "Bits per pixel:";
+ this.labelFullscreenBits.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // updownSoundNumber
+ // updownFullscreenHeight
//
- this.updownSoundNumber.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.updownSoundNumber.Location = new System.Drawing.Point(140, 16);
- this.updownSoundNumber.Maximum = new decimal(new int[] {
- 128,
+ this.updownFullscreenHeight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownFullscreenHeight.Location = new System.Drawing.Point(156, 48);
+ this.updownFullscreenHeight.Maximum = new decimal(new int[] {
+ 1048575,
0,
0,
0});
- this.updownSoundNumber.Minimum = new decimal(new int[] {
- 8,
+ this.updownFullscreenHeight.Minimum = new decimal(new int[] {
+ 16,
0,
0,
0});
- this.updownSoundNumber.Name = "updownSoundNumber";
- this.updownSoundNumber.Size = new System.Drawing.Size(152, 20);
- this.updownSoundNumber.TabIndex = 3;
- this.updownSoundNumber.Value = new decimal(new int[] {
- 16,
+ this.updownFullscreenHeight.Name = "updownFullscreenHeight";
+ this.updownFullscreenHeight.Size = new System.Drawing.Size(152, 20);
+ this.updownFullscreenHeight.TabIndex = 3;
+ this.updownFullscreenHeight.Value = new decimal(new int[] {
+ 768,
0,
0,
0});
//
- // labelSoundNumber
+ // labelFullscreenHeight
//
- this.labelSoundNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.labelFullscreenHeight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.labelSoundNumber.Location = new System.Drawing.Point(5, 18);
- this.labelSoundNumber.Name = "labelSoundNumber";
- this.labelSoundNumber.Size = new System.Drawing.Size(136, 18);
- this.labelSoundNumber.TabIndex = 2;
- this.labelSoundNumber.Text = "Number of allowed sounds:";
- this.labelSoundNumber.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ this.labelFullscreenHeight.AutoEllipsis = true;
+ this.labelFullscreenHeight.Location = new System.Drawing.Point(8, 50);
+ this.labelFullscreenHeight.Name = "labelFullscreenHeight";
+ this.labelFullscreenHeight.Size = new System.Drawing.Size(148, 18);
+ this.labelFullscreenHeight.TabIndex = 2;
+ this.labelFullscreenHeight.Text = "Height:";
+ this.labelFullscreenHeight.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // panelOptionsPage2
+ // updownFullscreenWidth
//
- this.panelOptionsPage2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.panelOptionsPage2.Controls.Add(this.groupBoxInputDevice);
- this.panelOptionsPage2.Controls.Add(this.groupBoxObjectParser);
- this.panelOptionsPage2.Controls.Add(this.groupBoxKioskMode);
- this.panelOptionsPage2.Controls.Add(this.groupBoxAdvancedOptions);
- this.panelOptionsPage2.Controls.Add(this.groupBoxPackageOptions);
- this.panelOptionsPage2.Location = new System.Drawing.Point(0, 72);
- this.panelOptionsPage2.Name = "panelOptionsPage2";
- this.panelOptionsPage2.Size = new System.Drawing.Size(683, 553);
- this.panelOptionsPage2.TabIndex = 20;
+ this.updownFullscreenWidth.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownFullscreenWidth.Location = new System.Drawing.Point(156, 24);
+ this.updownFullscreenWidth.Maximum = new decimal(new int[] {
+ 1048575,
+ 0,
+ 0,
+ 0});
+ this.updownFullscreenWidth.Minimum = new decimal(new int[] {
+ 16,
+ 0,
+ 0,
+ 0});
+ this.updownFullscreenWidth.Name = "updownFullscreenWidth";
+ this.updownFullscreenWidth.Size = new System.Drawing.Size(152, 20);
+ this.updownFullscreenWidth.TabIndex = 1;
+ this.updownFullscreenWidth.Value = new decimal(new int[] {
+ 1024,
+ 0,
+ 0,
+ 0});
//
- // groupBoxInputDevice
+ // labelFullscreenWidth
//
- this.groupBoxInputDevice.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
+ this.labelFullscreenWidth.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxInputDevice.Controls.Add(this.labelInputDevice);
- this.groupBoxInputDevice.Controls.Add(this.listviewInputDevice);
- this.groupBoxInputDevice.Controls.Add(this.checkBoxInputDeviceEnable);
- this.groupBoxInputDevice.Controls.Add(this.buttonInputDeviceConfig);
- this.groupBoxInputDevice.ForeColor = System.Drawing.Color.Black;
- this.groupBoxInputDevice.Location = new System.Drawing.Point(6, 374);
- this.groupBoxInputDevice.Name = "groupBoxInputDevice";
- this.groupBoxInputDevice.Size = new System.Drawing.Size(674, 173);
- this.groupBoxInputDevice.TabIndex = 24;
- this.groupBoxInputDevice.TabStop = false;
- this.groupBoxInputDevice.Text = "Input Device Plugin";
+ this.labelFullscreenWidth.AutoEllipsis = true;
+ this.labelFullscreenWidth.Location = new System.Drawing.Point(8, 26);
+ this.labelFullscreenWidth.Name = "labelFullscreenWidth";
+ this.labelFullscreenWidth.Size = new System.Drawing.Size(148, 18);
+ this.labelFullscreenWidth.TabIndex = 0;
+ this.labelFullscreenWidth.Text = "Width:";
+ this.labelFullscreenWidth.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // labelInputDevice
+ // groupboxInterpolation
//
- this.labelInputDevice.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.groupboxInterpolation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.labelInputDevice.Location = new System.Drawing.Point(8, 17);
- this.labelInputDevice.Name = "labelInputDevice";
- this.labelInputDevice.Size = new System.Drawing.Size(658, 17);
- this.labelInputDevice.TabIndex = 0;
- this.labelInputDevice.Text = "WARNING: If you are turn on the Input Device Plugin(s), it may be happen the conf" +
- "lict of input setting(s).";
+ this.groupboxInterpolation.Controls.Add(this.updownAntiAliasing);
+ this.groupboxInterpolation.Controls.Add(this.labelAntiAliasing);
+ this.groupboxInterpolation.Controls.Add(this.labelTransparencyQuality);
+ this.groupboxInterpolation.Controls.Add(this.labelTransparencyPerformance);
+ this.groupboxInterpolation.Controls.Add(this.labelTransparency);
+ this.groupboxInterpolation.Controls.Add(this.updownAnisotropic);
+ this.groupboxInterpolation.Controls.Add(this.labelAnisotropic);
+ this.groupboxInterpolation.Controls.Add(this.comboboxInterpolation);
+ this.groupboxInterpolation.Controls.Add(this.labelInterpolation);
+ this.groupboxInterpolation.Controls.Add(this.trackbarTransparency);
+ this.groupboxInterpolation.ForeColor = System.Drawing.Color.Black;
+ this.groupboxInterpolation.Location = new System.Drawing.Point(0, 381);
+ this.groupboxInterpolation.Name = "groupboxInterpolation";
+ this.groupboxInterpolation.Size = new System.Drawing.Size(316, 160);
+ this.groupboxInterpolation.TabIndex = 7;
+ this.groupboxInterpolation.TabStop = false;
+ this.groupboxInterpolation.Text = "Interpolation";
//
- // listviewInputDevice
+ // updownAntiAliasing
//
- this.listviewInputDevice.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.listviewInputDevice.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
- this.columnheaderInputDeviceName,
- this.columnheaderInputDeviceStatus,
- this.columnheaderInputDeviceVersion,
- this.columnheaderInputDeviceProvider,
- this.columnheaderInputDeviceFileName});
- this.listviewInputDevice.FullRowSelect = true;
- this.listviewInputDevice.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
- this.listviewInputDevice.HideSelection = false;
- this.listviewInputDevice.LabelWrap = false;
- this.listviewInputDevice.Location = new System.Drawing.Point(8, 38);
- this.listviewInputDevice.MultiSelect = false;
- this.listviewInputDevice.Name = "listviewInputDevice";
- this.listviewInputDevice.ShowGroups = false;
- this.listviewInputDevice.Size = new System.Drawing.Size(658, 95);
- this.listviewInputDevice.TabIndex = 1;
- this.listviewInputDevice.UseCompatibleStateImageBehavior = false;
- this.listviewInputDevice.View = System.Windows.Forms.View.Details;
- this.listviewInputDevice.SelectedIndexChanged += new System.EventHandler(this.listviewInputDevice_SelectedIndexChanged);
- this.listviewInputDevice.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.listviewInputDevice_MouseDoubleClick);
+ this.updownAntiAliasing.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownAntiAliasing.Location = new System.Drawing.Point(156, 64);
+ this.updownAntiAliasing.Maximum = new decimal(new int[] {
+ 16,
+ 0,
+ 0,
+ 0});
+ this.updownAntiAliasing.Name = "updownAntiAliasing";
+ this.updownAntiAliasing.Size = new System.Drawing.Size(152, 20);
+ this.updownAntiAliasing.TabIndex = 5;
//
- // columnheaderInputDeviceName
+ // labelAntiAliasing
//
- this.columnheaderInputDeviceName.Text = "Name";
+ this.labelAntiAliasing.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelAntiAliasing.AutoEllipsis = true;
+ this.labelAntiAliasing.Location = new System.Drawing.Point(8, 66);
+ this.labelAntiAliasing.Name = "labelAntiAliasing";
+ this.labelAntiAliasing.Size = new System.Drawing.Size(148, 18);
+ this.labelAntiAliasing.TabIndex = 4;
+ this.labelAntiAliasing.Text = "Level of anti-aliasing:";
+ this.labelAntiAliasing.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // columnheaderInputDeviceStatus
+ // labelTransparencyQuality
//
- this.columnheaderInputDeviceStatus.Text = "Status";
+ this.labelTransparencyQuality.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelTransparencyQuality.AutoEllipsis = true;
+ this.labelTransparencyQuality.Location = new System.Drawing.Point(230, 136);
+ this.labelTransparencyQuality.Name = "labelTransparencyQuality";
+ this.labelTransparencyQuality.Size = new System.Drawing.Size(76, 16);
+ this.labelTransparencyQuality.TabIndex = 9;
+ this.labelTransparencyQuality.Text = "Smooth";
+ this.labelTransparencyQuality.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // columnheaderInputDeviceVersion
+ // labelTransparencyPerformance
//
- this.columnheaderInputDeviceVersion.Text = "Version";
+ this.labelTransparencyPerformance.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelTransparencyPerformance.AutoEllipsis = true;
+ this.labelTransparencyPerformance.Location = new System.Drawing.Point(130, 136);
+ this.labelTransparencyPerformance.Name = "labelTransparencyPerformance";
+ this.labelTransparencyPerformance.Size = new System.Drawing.Size(76, 16);
+ this.labelTransparencyPerformance.TabIndex = 8;
+ this.labelTransparencyPerformance.Text = "Sharp";
+ this.labelTransparencyPerformance.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
- // columnheaderInputDeviceProvider
+ // labelTransparency
//
- this.columnheaderInputDeviceProvider.Text = "Provider";
+ this.labelTransparency.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelTransparency.AutoEllipsis = true;
+ this.labelTransparency.Location = new System.Drawing.Point(8, 100);
+ this.labelTransparency.Name = "labelTransparency";
+ this.labelTransparency.Size = new System.Drawing.Size(148, 18);
+ this.labelTransparency.TabIndex = 6;
+ this.labelTransparency.Text = "Transparency:";
+ this.labelTransparency.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // columnheaderInputDeviceFileName
+ // updownAnisotropic
//
- this.columnheaderInputDeviceFileName.Text = "File Name";
- this.columnheaderInputDeviceFileName.Width = 200;
+ this.updownAnisotropic.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownAnisotropic.Enabled = false;
+ this.updownAnisotropic.Location = new System.Drawing.Point(156, 40);
+ this.updownAnisotropic.Maximum = new decimal(new int[] {
+ 16,
+ 0,
+ 0,
+ 0});
+ this.updownAnisotropic.Name = "updownAnisotropic";
+ this.updownAnisotropic.Size = new System.Drawing.Size(152, 20);
+ this.updownAnisotropic.TabIndex = 3;
//
- // checkBoxInputDeviceEnable
+ // labelAnisotropic
//
- this.checkBoxInputDeviceEnable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.checkBoxInputDeviceEnable.Enabled = false;
- this.checkBoxInputDeviceEnable.Location = new System.Drawing.Point(8, 136);
- this.checkBoxInputDeviceEnable.Name = "checkBoxInputDeviceEnable";
- this.checkBoxInputDeviceEnable.Size = new System.Drawing.Size(230, 34);
- this.checkBoxInputDeviceEnable.TabIndex = 2;
- this.checkBoxInputDeviceEnable.Text = "Enable this Input Device Plugin";
- this.checkBoxInputDeviceEnable.UseVisualStyleBackColor = true;
- this.checkBoxInputDeviceEnable.CheckedChanged += new System.EventHandler(this.checkBoxInputDeviceEnable_CheckedChanged);
+ this.labelAnisotropic.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelAnisotropic.AutoEllipsis = true;
+ this.labelAnisotropic.Enabled = false;
+ this.labelAnisotropic.Location = new System.Drawing.Point(8, 42);
+ this.labelAnisotropic.Name = "labelAnisotropic";
+ this.labelAnisotropic.Size = new System.Drawing.Size(148, 18);
+ this.labelAnisotropic.TabIndex = 2;
+ this.labelAnisotropic.Text = "Level of anisotropic filtering:";
+ this.labelAnisotropic.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // buttonInputDeviceConfig
+ // comboboxInterpolation
//
- this.buttonInputDeviceConfig.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
- this.buttonInputDeviceConfig.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonInputDeviceConfig.Enabled = false;
- this.buttonInputDeviceConfig.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonInputDeviceConfig.Location = new System.Drawing.Point(270, 140);
- this.buttonInputDeviceConfig.MaximumSize = new System.Drawing.Size(106, 25);
- this.buttonInputDeviceConfig.Name = "buttonInputDeviceConfig";
- this.buttonInputDeviceConfig.Size = new System.Drawing.Size(106, 25);
- this.buttonInputDeviceConfig.TabIndex = 3;
- this.buttonInputDeviceConfig.Text = "Config";
- this.buttonInputDeviceConfig.UseVisualStyleBackColor = true;
- this.buttonInputDeviceConfig.Click += new System.EventHandler(this.buttonInputDeviceConfig_Click);
+ this.comboboxInterpolation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboboxInterpolation.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboboxInterpolation.FormattingEnabled = true;
+ this.comboboxInterpolation.Location = new System.Drawing.Point(156, 16);
+ this.comboboxInterpolation.Name = "comboboxInterpolation";
+ this.comboboxInterpolation.Size = new System.Drawing.Size(152, 21);
+ this.comboboxInterpolation.TabIndex = 1;
+ this.comboboxInterpolation.SelectedIndexChanged += new System.EventHandler(this.comboboxInterpolation_SelectedIndexChanged);
//
- // groupBoxObjectParser
+ // labelInterpolation
//
- this.groupBoxObjectParser.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxObjectParser.Controls.Add(this.labelObjparser);
- this.groupBoxObjectParser.Controls.Add(this.comboBoxObjparser);
- this.groupBoxObjectParser.Controls.Add(this.labelXparser);
- this.groupBoxObjectParser.Controls.Add(this.comboBoxXparser);
- this.groupBoxObjectParser.ForeColor = System.Drawing.Color.Black;
- this.groupBoxObjectParser.Location = new System.Drawing.Point(375, 258);
- this.groupBoxObjectParser.Name = "groupBoxObjectParser";
- this.groupBoxObjectParser.Size = new System.Drawing.Size(305, 110);
- this.groupBoxObjectParser.TabIndex = 23;
- this.groupBoxObjectParser.TabStop = false;
- this.groupBoxObjectParser.Text = "Object Parser";
+ this.labelInterpolation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelInterpolation.AutoEllipsis = true;
+ this.labelInterpolation.Location = new System.Drawing.Point(8, 18);
+ this.labelInterpolation.Name = "labelInterpolation";
+ this.labelInterpolation.Size = new System.Drawing.Size(148, 18);
+ this.labelInterpolation.TabIndex = 0;
+ this.labelInterpolation.Text = "Mode:";
+ this.labelInterpolation.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // labelObjparser
+ // trackbarTransparency
//
- this.labelObjparser.Location = new System.Drawing.Point(7, 44);
- this.labelObjparser.Name = "labelObjparser";
- this.labelObjparser.Size = new System.Drawing.Size(113, 26);
- this.labelObjparser.TabIndex = 0;
- this.labelObjparser.Text = "Obj Object Parser:";
- this.labelObjparser.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.trackbarTransparency.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.trackbarTransparency.Location = new System.Drawing.Point(156, 88);
+ this.trackbarTransparency.Maximum = 2;
+ this.trackbarTransparency.Name = "trackbarTransparency";
+ this.trackbarTransparency.Size = new System.Drawing.Size(152, 45);
+ this.trackbarTransparency.TabIndex = 7;
+ this.trackbarTransparency.TickStyle = System.Windows.Forms.TickStyle.Both;
//
- // comboBoxObjparser
+ // panelOptionsRight
//
- this.comboBoxObjparser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboBoxObjparser.FormattingEnabled = true;
- this.comboBoxObjparser.Items.AddRange(new object[] {
- "Original",
- "Assimp"});
- this.comboBoxObjparser.Location = new System.Drawing.Point(127, 44);
- this.comboBoxObjparser.Name = "comboBoxObjparser";
- this.comboBoxObjparser.Size = new System.Drawing.Size(170, 21);
- this.comboBoxObjparser.TabIndex = 1;
+ this.panelOptionsRight.Controls.Add(this.groupBoxOther);
+ this.panelOptionsRight.Controls.Add(this.groupBoxRailDriver);
+ this.panelOptionsRight.Controls.Add(this.groupboxDistance);
+ this.panelOptionsRight.Controls.Add(this.groupboxControls);
+ this.panelOptionsRight.Controls.Add(this.groupboxVerbosity);
+ this.panelOptionsRight.Controls.Add(this.groupboxSimulation);
+ this.panelOptionsRight.Controls.Add(this.groupboxSound);
+ this.panelOptionsRight.Location = new System.Drawing.Point(332, 72);
+ this.panelOptionsRight.Name = "panelOptionsRight";
+ this.panelOptionsRight.Size = new System.Drawing.Size(316, 579);
+ this.panelOptionsRight.TabIndex = 17;
//
- // labelXparser
+ // groupBoxOther
//
- this.labelXparser.Location = new System.Drawing.Point(7, 17);
- this.labelXparser.Name = "labelXparser";
- this.labelXparser.Size = new System.Drawing.Size(113, 26);
- this.labelXparser.TabIndex = 0;
- this.labelXparser.Text = "X Object Parser:";
- this.labelXparser.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.groupBoxOther.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBoxOther.Controls.Add(this.comboBoxTimeTableDisplayMode);
+ this.groupBoxOther.Controls.Add(this.labelTimeTableDisplayMode);
+ this.groupBoxOther.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxOther.Location = new System.Drawing.Point(0, 468);
+ this.groupBoxOther.Name = "groupBoxOther";
+ this.groupBoxOther.Size = new System.Drawing.Size(316, 48);
+ this.groupBoxOther.TabIndex = 19;
+ this.groupBoxOther.TabStop = false;
+ this.groupBoxOther.Text = "Other";
//
- // comboBoxXparser
+ // comboBoxTimeTableDisplayMode
//
- this.comboBoxXparser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboBoxXparser.FormattingEnabled = true;
- this.comboBoxXparser.Items.AddRange(new object[] {
- "Original",
- "NewXParser",
- "Assimp"});
- this.comboBoxXparser.Location = new System.Drawing.Point(127, 21);
- this.comboBoxXparser.Name = "comboBoxXparser";
- this.comboBoxXparser.Size = new System.Drawing.Size(170, 21);
- this.comboBoxXparser.TabIndex = 1;
+ this.comboBoxTimeTableDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboBoxTimeTableDisplayMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBoxTimeTableDisplayMode.FormattingEnabled = true;
+ this.comboBoxTimeTableDisplayMode.Location = new System.Drawing.Point(156, 16);
+ this.comboBoxTimeTableDisplayMode.Name = "comboBoxTimeTableDisplayMode";
+ this.comboBoxTimeTableDisplayMode.Size = new System.Drawing.Size(152, 21);
+ this.comboBoxTimeTableDisplayMode.TabIndex = 1;
+ this.comboBoxTimeTableDisplayMode.SelectedIndexChanged += new System.EventHandler(this.comboBoxTimeTableDisplayMode_SelectedIndexChanged);
//
- // groupBoxKioskMode
+ // labelTimeTableDisplayMode
//
- this.groupBoxKioskMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxKioskMode.Controls.Add(this.labelKioskTimeout);
- this.groupBoxKioskMode.Controls.Add(this.numericUpDownKioskTimeout);
- this.groupBoxKioskMode.Controls.Add(this.checkBoxEnableKiosk);
- this.groupBoxKioskMode.ForeColor = System.Drawing.Color.Black;
- this.groupBoxKioskMode.Location = new System.Drawing.Point(375, 160);
- this.groupBoxKioskMode.Name = "groupBoxKioskMode";
- this.groupBoxKioskMode.Size = new System.Drawing.Size(305, 92);
- this.groupBoxKioskMode.TabIndex = 22;
- this.groupBoxKioskMode.TabStop = false;
- this.groupBoxKioskMode.Text = "Kiosk Mode";
+ this.labelTimeTableDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelTimeTableDisplayMode.AutoEllipsis = true;
+ this.labelTimeTableDisplayMode.Location = new System.Drawing.Point(3, 17);
+ this.labelTimeTableDisplayMode.Name = "labelTimeTableDisplayMode";
+ this.labelTimeTableDisplayMode.Size = new System.Drawing.Size(153, 18);
+ this.labelTimeTableDisplayMode.TabIndex = 0;
+ this.labelTimeTableDisplayMode.Text = "Timetable Display Mode:";
+ this.labelTimeTableDisplayMode.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
- // labelKioskTimeout
+ // groupBoxRailDriver
//
- this.labelKioskTimeout.Location = new System.Drawing.Point(8, 37);
- this.labelKioskTimeout.Name = "labelKioskTimeout";
- this.labelKioskTimeout.Size = new System.Drawing.Size(155, 30);
- this.labelKioskTimeout.TabIndex = 2;
- this.labelKioskTimeout.Text = "Control timeout (s)";
- this.labelKioskTimeout.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.groupBoxRailDriver.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBoxRailDriver.Controls.Add(this.labelRailDriverCalibration);
+ this.groupBoxRailDriver.Controls.Add(this.buttonRailDriverCalibration);
+ this.groupBoxRailDriver.Controls.Add(this.comboBoxRailDriverUnits);
+ this.groupBoxRailDriver.Controls.Add(this.labelRailDriverSpeedUnits);
+ this.groupBoxRailDriver.ForeColor = System.Drawing.Color.Black;
+ this.groupBoxRailDriver.Location = new System.Drawing.Point(0, 230);
+ this.groupBoxRailDriver.Name = "groupBoxRailDriver";
+ this.groupBoxRailDriver.Size = new System.Drawing.Size(316, 75);
+ this.groupBoxRailDriver.TabIndex = 21;
+ this.groupBoxRailDriver.TabStop = false;
+ this.groupBoxRailDriver.Text = "RailDriver";
//
- // numericUpDownKioskTimeout
+ // labelRailDriverCalibration
//
- this.numericUpDownKioskTimeout.DecimalPlaces = 2;
- this.numericUpDownKioskTimeout.Location = new System.Drawing.Point(166, 41);
- this.numericUpDownKioskTimeout.Maximum = new decimal(new int[] {
- 10000,
- 0,
- 0,
- 0});
- this.numericUpDownKioskTimeout.Name = "numericUpDownKioskTimeout";
- this.numericUpDownKioskTimeout.Size = new System.Drawing.Size(131, 20);
- this.numericUpDownKioskTimeout.TabIndex = 1;
+ this.labelRailDriverCalibration.AutoSize = true;
+ this.labelRailDriverCalibration.Location = new System.Drawing.Point(7, 46);
+ this.labelRailDriverCalibration.Name = "labelRailDriverCalibration";
+ this.labelRailDriverCalibration.Size = new System.Drawing.Size(78, 13);
+ this.labelRailDriverCalibration.TabIndex = 5;
+ this.labelRailDriverCalibration.Text = "Set Calibration:";
//
- // checkBoxEnableKiosk
+ // buttonRailDriverCalibration
//
- this.checkBoxEnableKiosk.AutoSize = true;
- this.checkBoxEnableKiosk.Location = new System.Drawing.Point(9, 20);
- this.checkBoxEnableKiosk.Name = "checkBoxEnableKiosk";
- this.checkBoxEnableKiosk.Size = new System.Drawing.Size(118, 17);
- this.checkBoxEnableKiosk.TabIndex = 0;
- this.checkBoxEnableKiosk.Text = "Enable Kiosk Mode";
- this.checkBoxEnableKiosk.UseVisualStyleBackColor = true;
+ this.buttonRailDriverCalibration.BackColor = System.Drawing.SystemColors.ButtonFace;
+ this.buttonRailDriverCalibration.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.buttonRailDriverCalibration.Location = new System.Drawing.Point(230, 42);
+ this.buttonRailDriverCalibration.Name = "buttonRailDriverCalibration";
+ this.buttonRailDriverCalibration.Size = new System.Drawing.Size(75, 26);
+ this.buttonRailDriverCalibration.TabIndex = 4;
+ this.buttonRailDriverCalibration.Text = "Launch...";
+ this.buttonRailDriverCalibration.UseVisualStyleBackColor = true;
+ this.buttonRailDriverCalibration.Click += new System.EventHandler(this.buttonRailDriverCalibration_Click);
//
- // groupBoxAdvancedOptions
+ // comboBoxRailDriverUnits
//
- this.groupBoxAdvancedOptions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxPanel2Extended);
- this.groupBoxAdvancedOptions.Controls.Add(this.pictureboxCursor);
- this.groupBoxAdvancedOptions.Controls.Add(this.labelCursor);
- this.groupBoxAdvancedOptions.Controls.Add(this.comboboxCursor);
- this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxHacks);
- this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxTransparencyFix);
- this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxUnloadTextures);
- this.groupBoxAdvancedOptions.Controls.Add(this.labelTimeAcceleration);
- this.groupBoxAdvancedOptions.Controls.Add(this.updownTimeAccelerationFactor);
- this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxIsUseNewRenderer);
- this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxLoadInAdvance);
- this.groupBoxAdvancedOptions.ForeColor = System.Drawing.Color.Black;
- this.groupBoxAdvancedOptions.Location = new System.Drawing.Point(6, 160);
- this.groupBoxAdvancedOptions.Name = "groupBoxAdvancedOptions";
- this.groupBoxAdvancedOptions.Size = new System.Drawing.Size(358, 208);
- this.groupBoxAdvancedOptions.TabIndex = 21;
- this.groupBoxAdvancedOptions.TabStop = false;
- this.groupBoxAdvancedOptions.Text = "Advanced Options";
+ this.comboBoxRailDriverUnits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBoxRailDriverUnits.FormattingEnabled = true;
+ this.comboBoxRailDriverUnits.Items.AddRange(new object[] {
+ "Miles per Hour (MPH)",
+ "Kilometers per Hour (KPH)"});
+ this.comboBoxRailDriverUnits.Location = new System.Drawing.Point(140, 16);
+ this.comboBoxRailDriverUnits.Name = "comboBoxRailDriverUnits";
+ this.comboBoxRailDriverUnits.Size = new System.Drawing.Size(165, 21);
+ this.comboBoxRailDriverUnits.TabIndex = 3;
+ this.comboBoxRailDriverUnits.SelectedIndexChanged += new System.EventHandler(this.comboBoxRailDriverUnits_SelectedIndexChanged);
//
- // checkBoxPanel2Extended
+ // labelRailDriverSpeedUnits
//
- this.checkBoxPanel2Extended.AutoSize = true;
- this.checkBoxPanel2Extended.Location = new System.Drawing.Point(8, 183);
- this.checkBoxPanel2Extended.Name = "checkBoxPanel2Extended";
- this.checkBoxPanel2Extended.Size = new System.Drawing.Size(159, 17);
- this.checkBoxPanel2Extended.TabIndex = 20;
- this.checkBoxPanel2Extended.Text = "Enable Panel2 extend mode";
- this.checkBoxPanel2Extended.UseVisualStyleBackColor = true;
+ this.labelRailDriverSpeedUnits.Location = new System.Drawing.Point(7, 14);
+ this.labelRailDriverSpeedUnits.Name = "labelRailDriverSpeedUnits";
+ this.labelRailDriverSpeedUnits.Size = new System.Drawing.Size(130, 30);
+ this.labelRailDriverSpeedUnits.TabIndex = 2;
+ this.labelRailDriverSpeedUnits.Text = "LED Display speed units:";
+ this.labelRailDriverSpeedUnits.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
- // pictureboxCursor
+ // groupboxDistance
//
- this.pictureboxCursor.Location = new System.Drawing.Point(8, 145);
- this.pictureboxCursor.Name = "pictureboxCursor";
- this.pictureboxCursor.Size = new System.Drawing.Size(32, 32);
- this.pictureboxCursor.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
- this.pictureboxCursor.TabIndex = 18;
- this.pictureboxCursor.TabStop = false;
+ this.groupboxDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupboxDistance.Controls.Add(this.comboboxMotionBlur);
+ this.groupboxDistance.Controls.Add(this.labelMotionBlur);
+ this.groupboxDistance.Controls.Add(this.labelDistanceUnit);
+ this.groupboxDistance.Controls.Add(this.updownDistance);
+ this.groupboxDistance.Controls.Add(this.labelDistance);
+ this.groupboxDistance.ForeColor = System.Drawing.Color.Black;
+ this.groupboxDistance.Location = new System.Drawing.Point(0, 0);
+ this.groupboxDistance.Name = "groupboxDistance";
+ this.groupboxDistance.Size = new System.Drawing.Size(316, 80);
+ this.groupboxDistance.TabIndex = 8;
+ this.groupboxDistance.TabStop = false;
+ this.groupboxDistance.Text = "Distance effects";
//
- // labelCursor
+ // comboboxMotionBlur
//
- this.labelCursor.AutoSize = true;
- this.labelCursor.Location = new System.Drawing.Point(48, 140);
- this.labelCursor.Name = "labelCursor";
- this.labelCursor.Size = new System.Drawing.Size(37, 13);
- this.labelCursor.TabIndex = 17;
- this.labelCursor.Text = "Cursor";
+ this.comboboxMotionBlur.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboboxMotionBlur.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboboxMotionBlur.FormattingEnabled = true;
+ this.comboboxMotionBlur.Location = new System.Drawing.Point(144, 48);
+ this.comboboxMotionBlur.Name = "comboboxMotionBlur";
+ this.comboboxMotionBlur.Size = new System.Drawing.Size(152, 21);
+ this.comboboxMotionBlur.TabIndex = 4;
//
- // comboboxCursor
+ // labelMotionBlur
//
- this.comboboxCursor.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboboxCursor.FormattingEnabled = true;
- this.comboboxCursor.Location = new System.Drawing.Point(48, 158);
- this.comboboxCursor.Name = "comboboxCursor";
- this.comboboxCursor.Size = new System.Drawing.Size(108, 21);
- this.comboboxCursor.TabIndex = 19;
- this.comboboxCursor.SelectedIndexChanged += new System.EventHandler(this.comboboxCursor_SelectedIndexChanged);
+ this.labelMotionBlur.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelMotionBlur.AutoEllipsis = true;
+ this.labelMotionBlur.Location = new System.Drawing.Point(5, 51);
+ this.labelMotionBlur.Name = "labelMotionBlur";
+ this.labelMotionBlur.Size = new System.Drawing.Size(140, 18);
+ this.labelMotionBlur.TabIndex = 3;
+ this.labelMotionBlur.Text = "Motion blur:";
+ this.labelMotionBlur.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
- // checkBoxHacks
+ // labelDistanceUnit
//
- this.checkBoxHacks.AutoSize = true;
- this.checkBoxHacks.Location = new System.Drawing.Point(8, 100);
- this.checkBoxHacks.Name = "checkBoxHacks";
- this.checkBoxHacks.Size = new System.Drawing.Size(203, 17);
- this.checkBoxHacks.TabIndex = 15;
- this.checkBoxHacks.Text = "Enable hacks for buggy older content";
- this.checkBoxHacks.UseVisualStyleBackColor = true;
+ this.labelDistanceUnit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelDistanceUnit.AutoEllipsis = true;
+ this.labelDistanceUnit.Location = new System.Drawing.Point(272, 24);
+ this.labelDistanceUnit.Name = "labelDistanceUnit";
+ this.labelDistanceUnit.Size = new System.Drawing.Size(24, 18);
+ this.labelDistanceUnit.TabIndex = 2;
+ this.labelDistanceUnit.Text = "m";
//
- // checkBoxTransparencyFix
+ // updownDistance
//
- this.checkBoxTransparencyFix.AutoSize = true;
- this.checkBoxTransparencyFix.Location = new System.Drawing.Point(8, 81);
- this.checkBoxTransparencyFix.Name = "checkBoxTransparencyFix";
- this.checkBoxTransparencyFix.Size = new System.Drawing.Size(259, 17);
- this.checkBoxTransparencyFix.TabIndex = 14;
- this.checkBoxTransparencyFix.Text = "Attempt to fix transparency issues in older content";
- this.checkBoxTransparencyFix.UseVisualStyleBackColor = true;
+ this.updownDistance.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownDistance.Location = new System.Drawing.Point(144, 24);
+ this.updownDistance.Maximum = new decimal(new int[] {
+ 100000,
+ 0,
+ 0,
+ 0});
+ this.updownDistance.Minimum = new decimal(new int[] {
+ 100,
+ 0,
+ 0,
+ 0});
+ this.updownDistance.Name = "updownDistance";
+ this.updownDistance.Size = new System.Drawing.Size(128, 20);
+ this.updownDistance.TabIndex = 1;
+ this.updownDistance.Value = new decimal(new int[] {
+ 600,
+ 0,
+ 0,
+ 0});
//
- // checkBoxUnloadTextures
+ // labelDistance
//
- this.checkBoxUnloadTextures.AutoSize = true;
- this.checkBoxUnloadTextures.Location = new System.Drawing.Point(8, 62);
- this.checkBoxUnloadTextures.Name = "checkBoxUnloadTextures";
- this.checkBoxUnloadTextures.Size = new System.Drawing.Size(138, 17);
- this.checkBoxUnloadTextures.TabIndex = 13;
- this.checkBoxUnloadTextures.Text = "Unload unused textures";
- this.checkBoxUnloadTextures.UseVisualStyleBackColor = true;
- this.checkBoxUnloadTextures.CheckedChanged += new System.EventHandler(this.checkBoxUnloadTextures_CheckedChanged);
+ this.labelDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelDistance.AutoEllipsis = true;
+ this.labelDistance.Location = new System.Drawing.Point(9, 26);
+ this.labelDistance.Name = "labelDistance";
+ this.labelDistance.Size = new System.Drawing.Size(136, 18);
+ this.labelDistance.TabIndex = 0;
+ this.labelDistance.Text = "Viewing distance:";
+ this.labelDistance.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
- // labelTimeAcceleration
+ // groupboxControls
//
- this.labelTimeAcceleration.AutoSize = true;
- this.labelTimeAcceleration.Location = new System.Drawing.Point(8, 123);
- this.labelTimeAcceleration.Name = "labelTimeAcceleration";
- this.labelTimeAcceleration.Size = new System.Drawing.Size(126, 13);
- this.labelTimeAcceleration.TabIndex = 10;
- this.labelTimeAcceleration.Text = "Accelerated Time Factor:";
+ this.groupboxControls.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupboxControls.Controls.Add(this.checkBoxEBAxis);
+ this.groupboxControls.Controls.Add(this.trackbarJoystickAxisThreshold);
+ this.groupboxControls.Controls.Add(this.checkboxJoysticksUsed);
+ this.groupboxControls.Controls.Add(this.labelJoystickAxisThreshold);
+ this.groupboxControls.ForeColor = System.Drawing.Color.Black;
+ this.groupboxControls.Location = new System.Drawing.Point(0, 144);
+ this.groupboxControls.Name = "groupboxControls";
+ this.groupboxControls.Size = new System.Drawing.Size(316, 80);
+ this.groupboxControls.TabIndex = 10;
+ this.groupboxControls.TabStop = false;
+ this.groupboxControls.Text = "Controls";
//
- // updownTimeAccelerationFactor
+ // checkBoxEBAxis
//
- this.updownTimeAccelerationFactor.Location = new System.Drawing.Point(200, 122);
- this.updownTimeAccelerationFactor.Maximum = new decimal(new int[] {
- 5,
- 0,
- 0,
- 0});
- this.updownTimeAccelerationFactor.Name = "updownTimeAccelerationFactor";
- this.updownTimeAccelerationFactor.Size = new System.Drawing.Size(52, 20);
- this.updownTimeAccelerationFactor.TabIndex = 16;
- this.updownTimeAccelerationFactor.ValueChanged += new System.EventHandler(this.updownTimeAccelerationFactor_ValueChanged);
+ this.checkBoxEBAxis.Checked = true;
+ this.checkBoxEBAxis.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxEBAxis.Location = new System.Drawing.Point(8, 41);
+ this.checkBoxEBAxis.Name = "checkBoxEBAxis";
+ this.checkBoxEBAxis.Size = new System.Drawing.Size(190, 36);
+ this.checkBoxEBAxis.TabIndex = 18;
+ this.checkBoxEBAxis.Text = "Allow EB on brake axis";
+ this.checkBoxEBAxis.UseVisualStyleBackColor = true;
//
- // checkBoxIsUseNewRenderer
+ // trackbarJoystickAxisThreshold
//
- this.checkBoxIsUseNewRenderer.AutoSize = true;
- this.checkBoxIsUseNewRenderer.Location = new System.Drawing.Point(8, 43);
- this.checkBoxIsUseNewRenderer.Name = "checkBoxIsUseNewRenderer";
- this.checkBoxIsUseNewRenderer.Size = new System.Drawing.Size(159, 17);
- this.checkBoxIsUseNewRenderer.TabIndex = 2;
- this.checkBoxIsUseNewRenderer.Text = "Disable OpenGL display lists";
- this.checkBoxIsUseNewRenderer.UseVisualStyleBackColor = true;
+ this.trackbarJoystickAxisThreshold.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.trackbarJoystickAxisThreshold.LargeChange = 10;
+ this.trackbarJoystickAxisThreshold.Location = new System.Drawing.Point(200, 32);
+ this.trackbarJoystickAxisThreshold.Maximum = 100;
+ this.trackbarJoystickAxisThreshold.Name = "trackbarJoystickAxisThreshold";
+ this.trackbarJoystickAxisThreshold.Size = new System.Drawing.Size(96, 45);
+ this.trackbarJoystickAxisThreshold.TabIndex = 2;
+ this.trackbarJoystickAxisThreshold.TickFrequency = 10;
+ this.trackbarJoystickAxisThreshold.TickStyle = System.Windows.Forms.TickStyle.Both;
//
- // checkBoxLoadInAdvance
+ // checkboxJoysticksUsed
//
- this.checkBoxLoadInAdvance.AutoSize = true;
- this.checkBoxLoadInAdvance.Location = new System.Drawing.Point(8, 24);
- this.checkBoxLoadInAdvance.Name = "checkBoxLoadInAdvance";
- this.checkBoxLoadInAdvance.Size = new System.Drawing.Size(106, 17);
- this.checkBoxLoadInAdvance.TabIndex = 1;
- this.checkBoxLoadInAdvance.Text = "Load in advance";
- this.checkBoxLoadInAdvance.UseVisualStyleBackColor = true;
- this.checkBoxLoadInAdvance.CheckedChanged += new System.EventHandler(this.checkBoxLoadInAdvance_CheckedChanged);
+ this.checkboxJoysticksUsed.AutoSize = true;
+ this.checkboxJoysticksUsed.Location = new System.Drawing.Point(8, 24);
+ this.checkboxJoysticksUsed.Name = "checkboxJoysticksUsed";
+ this.checkboxJoysticksUsed.Size = new System.Drawing.Size(110, 17);
+ this.checkboxJoysticksUsed.TabIndex = 0;
+ this.checkboxJoysticksUsed.Text = "Joysticks enabled";
+ this.checkboxJoysticksUsed.UseVisualStyleBackColor = true;
+ this.checkboxJoysticksUsed.CheckedChanged += new System.EventHandler(this.checkboxJoysticksUsed_CheckedChanged);
//
- // groupBoxPackageOptions
+ // labelJoystickAxisThreshold
//
- this.groupBoxPackageOptions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.labelJoystickAxisThreshold.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.labelJoystickAxisThreshold.AutoEllipsis = true;
+ this.labelJoystickAxisThreshold.Location = new System.Drawing.Point(110, 10);
+ this.labelJoystickAxisThreshold.Name = "labelJoystickAxisThreshold";
+ this.labelJoystickAxisThreshold.Size = new System.Drawing.Size(180, 18);
+ this.labelJoystickAxisThreshold.TabIndex = 1;
+ this.labelJoystickAxisThreshold.Text = "Joystick threshold:";
+ this.labelJoystickAxisThreshold.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ //
+ // groupboxVerbosity
+ //
+ this.groupboxVerbosity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.groupBoxPackageOptions.Controls.Add(this.comboBoxCompressionFormat);
- this.groupBoxPackageOptions.Controls.Add(this.labelPackageCompression);
- this.groupBoxPackageOptions.Controls.Add(this.buttonOtherDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.labelOtherInstallDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.textBoxOtherDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.buttonTrainInstallationDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.labelTrainInstallDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.textBoxTrainDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.buttonSetRouteDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.labelRouteInstallDirectory);
- this.groupBoxPackageOptions.Controls.Add(this.textBoxRouteDirectory);
- this.groupBoxPackageOptions.ForeColor = System.Drawing.Color.Black;
- this.groupBoxPackageOptions.Location = new System.Drawing.Point(6, 0);
- this.groupBoxPackageOptions.Name = "groupBoxPackageOptions";
- this.groupBoxPackageOptions.Size = new System.Drawing.Size(674, 154);
- this.groupBoxPackageOptions.TabIndex = 19;
- this.groupBoxPackageOptions.TabStop = false;
- this.groupBoxPackageOptions.Text = "Package Management";
+ this.groupboxVerbosity.Controls.Add(this.checkBoxAccessibility);
+ this.groupboxVerbosity.Controls.Add(this.checkboxErrorMessages);
+ this.groupboxVerbosity.Controls.Add(this.checkboxWarningMessages);
+ this.groupboxVerbosity.ForeColor = System.Drawing.Color.Black;
+ this.groupboxVerbosity.Location = new System.Drawing.Point(0, 396);
+ this.groupboxVerbosity.Name = "groupboxVerbosity";
+ this.groupboxVerbosity.Size = new System.Drawing.Size(316, 64);
+ this.groupboxVerbosity.TabIndex = 12;
+ this.groupboxVerbosity.TabStop = false;
+ this.groupboxVerbosity.Text = "Verbosity";
//
- // comboBoxCompressionFormat
+ // checkBoxAccessibility
//
- this.comboBoxCompressionFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.comboBoxCompressionFormat.Items.AddRange(new object[] {
- "LZMA ZIP ( .zip )",
- "GZip ( .tgz )",
- "BZip2 ( .bz2 )"});
- this.comboBoxCompressionFormat.Location = new System.Drawing.Point(200, 117);
- this.comboBoxCompressionFormat.Name = "comboBoxCompressionFormat";
- this.comboBoxCompressionFormat.Size = new System.Drawing.Size(188, 21);
- this.comboBoxCompressionFormat.TabIndex = 10;
- this.comboBoxCompressionFormat.SelectedIndexChanged += new System.EventHandler(this.comboBoxCompressionFormat_SelectedIndexChanged);
+ this.checkBoxAccessibility.AutoSize = true;
+ this.checkBoxAccessibility.Location = new System.Drawing.Point(176, 21);
+ this.checkBoxAccessibility.Name = "checkBoxAccessibility";
+ this.checkBoxAccessibility.Size = new System.Drawing.Size(106, 17);
+ this.checkBoxAccessibility.TabIndex = 2;
+ this.checkBoxAccessibility.Text = "Accessibility Aids";
+ this.checkBoxAccessibility.UseVisualStyleBackColor = true;
//
- // labelPackageCompression
+ // checkboxErrorMessages
//
- this.labelPackageCompression.AutoSize = true;
- this.labelPackageCompression.Location = new System.Drawing.Point(6, 121);
- this.labelPackageCompression.Name = "labelPackageCompression";
- this.labelPackageCompression.Size = new System.Drawing.Size(147, 13);
- this.labelPackageCompression.TabIndex = 9;
- this.labelPackageCompression.Text = "Package compression format:";
+ this.checkboxErrorMessages.AutoSize = true;
+ this.checkboxErrorMessages.Location = new System.Drawing.Point(8, 38);
+ this.checkboxErrorMessages.Name = "checkboxErrorMessages";
+ this.checkboxErrorMessages.Size = new System.Drawing.Size(127, 17);
+ this.checkboxErrorMessages.TabIndex = 1;
+ this.checkboxErrorMessages.Text = "Show error messages";
+ this.checkboxErrorMessages.UseVisualStyleBackColor = true;
//
- // buttonOtherDirectory
+ // checkboxWarningMessages
//
- this.buttonOtherDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.buttonOtherDirectory.BackColor = System.Drawing.SystemColors.Control;
- this.buttonOtherDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonOtherDirectory.Location = new System.Drawing.Point(594, 81);
- this.buttonOtherDirectory.Name = "buttonOtherDirectory";
- this.buttonOtherDirectory.Size = new System.Drawing.Size(75, 26);
- this.buttonOtherDirectory.TabIndex = 8;
- this.buttonOtherDirectory.Text = "Choose...";
- this.buttonOtherDirectory.UseVisualStyleBackColor = true;
- this.buttonOtherDirectory.Click += new System.EventHandler(this.buttonOtherDirectory_Click);
+ this.checkboxWarningMessages.AutoSize = true;
+ this.checkboxWarningMessages.Location = new System.Drawing.Point(8, 21);
+ this.checkboxWarningMessages.Name = "checkboxWarningMessages";
+ this.checkboxWarningMessages.Size = new System.Drawing.Size(143, 17);
+ this.checkboxWarningMessages.TabIndex = 0;
+ this.checkboxWarningMessages.Text = "Show warning messages";
+ this.checkboxWarningMessages.UseVisualStyleBackColor = true;
//
- // labelOtherInstallDirectory
+ // groupboxSimulation
//
- this.labelOtherInstallDirectory.Location = new System.Drawing.Point(6, 80);
- this.labelOtherInstallDirectory.Name = "labelOtherInstallDirectory";
- this.labelOtherInstallDirectory.Size = new System.Drawing.Size(175, 30);
- this.labelOtherInstallDirectory.TabIndex = 7;
- this.labelOtherInstallDirectory.Text = "Other items installation directory:";
- this.labelOtherInstallDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.groupboxSimulation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupboxSimulation.Controls.Add(this.checkBoxLoadingSway);
+ this.groupboxSimulation.Controls.Add(this.checkboxBlackBox);
+ this.groupboxSimulation.Controls.Add(this.checkboxDerailments);
+ this.groupboxSimulation.Controls.Add(this.checkboxCollisions);
+ this.groupboxSimulation.Controls.Add(this.checkboxToppling);
+ this.groupboxSimulation.ForeColor = System.Drawing.Color.Black;
+ this.groupboxSimulation.Location = new System.Drawing.Point(0, 310);
+ this.groupboxSimulation.Name = "groupboxSimulation";
+ this.groupboxSimulation.Size = new System.Drawing.Size(316, 80);
+ this.groupboxSimulation.TabIndex = 11;
+ this.groupboxSimulation.TabStop = false;
+ this.groupboxSimulation.Text = "Detail of simulation";
//
- // textBoxOtherDirectory
+ // checkBoxLoadingSway
//
- this.textBoxOtherDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.checkBoxLoadingSway.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.textBoxOtherDirectory.BackColor = System.Drawing.SystemColors.Control;
- this.textBoxOtherDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxOtherDirectory.Location = new System.Drawing.Point(200, 84);
- this.textBoxOtherDirectory.Name = "textBoxOtherDirectory";
- this.textBoxOtherDirectory.ReadOnly = true;
- this.textBoxOtherDirectory.Size = new System.Drawing.Size(387, 20);
- this.textBoxOtherDirectory.TabIndex = 6;
+ this.checkBoxLoadingSway.AutoSize = true;
+ this.checkBoxLoadingSway.Location = new System.Drawing.Point(176, 21);
+ this.checkBoxLoadingSway.Name = "checkBoxLoadingSway";
+ this.checkBoxLoadingSway.Size = new System.Drawing.Size(123, 17);
+ this.checkBoxLoadingSway.TabIndex = 4;
+ this.checkBoxLoadingSway.Text = "Enable loading sway";
+ this.checkBoxLoadingSway.UseVisualStyleBackColor = true;
//
- // buttonTrainInstallationDirectory
+ // checkboxBlackBox
//
- this.buttonTrainInstallationDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.buttonTrainInstallationDirectory.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonTrainInstallationDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonTrainInstallationDirectory.Location = new System.Drawing.Point(594, 49);
- this.buttonTrainInstallationDirectory.Name = "buttonTrainInstallationDirectory";
- this.buttonTrainInstallationDirectory.Size = new System.Drawing.Size(75, 26);
- this.buttonTrainInstallationDirectory.TabIndex = 5;
- this.buttonTrainInstallationDirectory.Text = "Choose...";
- this.buttonTrainInstallationDirectory.UseVisualStyleBackColor = true;
- this.buttonTrainInstallationDirectory.Click += new System.EventHandler(this.buttonTrainInstallationDirectory_Click);
+ this.checkboxBlackBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.checkboxBlackBox.AutoSize = true;
+ this.checkboxBlackBox.Location = new System.Drawing.Point(176, 38);
+ this.checkboxBlackBox.Name = "checkboxBlackBox";
+ this.checkboxBlackBox.Size = new System.Drawing.Size(108, 17);
+ this.checkboxBlackBox.TabIndex = 3;
+ this.checkboxBlackBox.Text = "Enable black box";
+ this.checkboxBlackBox.UseVisualStyleBackColor = true;
//
- // labelTrainInstallDirectory
+ // checkboxDerailments
//
- this.labelTrainInstallDirectory.AutoSize = true;
- this.labelTrainInstallDirectory.Location = new System.Drawing.Point(6, 52);
- this.labelTrainInstallDirectory.Name = "labelTrainInstallDirectory";
- this.labelTrainInstallDirectory.Size = new System.Drawing.Size(129, 13);
- this.labelTrainInstallDirectory.TabIndex = 4;
- this.labelTrainInstallDirectory.Text = "Train installation directory:";
+ this.checkboxDerailments.AutoSize = true;
+ this.checkboxDerailments.Location = new System.Drawing.Point(8, 55);
+ this.checkboxDerailments.Name = "checkboxDerailments";
+ this.checkboxDerailments.Size = new System.Drawing.Size(81, 17);
+ this.checkboxDerailments.TabIndex = 2;
+ this.checkboxDerailments.Text = "Derailments";
+ this.checkboxDerailments.UseVisualStyleBackColor = true;
//
- // textBoxTrainDirectory
+ // checkboxCollisions
//
- this.textBoxTrainDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.textBoxTrainDirectory.BackColor = System.Drawing.SystemColors.Control;
- this.textBoxTrainDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxTrainDirectory.Location = new System.Drawing.Point(200, 51);
- this.textBoxTrainDirectory.Name = "textBoxTrainDirectory";
- this.textBoxTrainDirectory.ReadOnly = true;
- this.textBoxTrainDirectory.Size = new System.Drawing.Size(387, 20);
- this.textBoxTrainDirectory.TabIndex = 3;
+ this.checkboxCollisions.AutoSize = true;
+ this.checkboxCollisions.Location = new System.Drawing.Point(8, 38);
+ this.checkboxCollisions.Name = "checkboxCollisions";
+ this.checkboxCollisions.Size = new System.Drawing.Size(69, 17);
+ this.checkboxCollisions.TabIndex = 1;
+ this.checkboxCollisions.Text = "Collisions";
+ this.checkboxCollisions.UseVisualStyleBackColor = true;
//
- // buttonSetRouteDirectory
+ // checkboxToppling
//
- this.buttonSetRouteDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.buttonSetRouteDirectory.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonSetRouteDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonSetRouteDirectory.Location = new System.Drawing.Point(594, 18);
- this.buttonSetRouteDirectory.Name = "buttonSetRouteDirectory";
- this.buttonSetRouteDirectory.Size = new System.Drawing.Size(75, 26);
- this.buttonSetRouteDirectory.TabIndex = 2;
- this.buttonSetRouteDirectory.Text = "Choose...";
- this.buttonSetRouteDirectory.UseVisualStyleBackColor = true;
- this.buttonSetRouteDirectory.Click += new System.EventHandler(this.buttonSetRouteDirectory_Click);
+ this.checkboxToppling.AutoSize = true;
+ this.checkboxToppling.Location = new System.Drawing.Point(8, 21);
+ this.checkboxToppling.Name = "checkboxToppling";
+ this.checkboxToppling.Size = new System.Drawing.Size(67, 17);
+ this.checkboxToppling.TabIndex = 0;
+ this.checkboxToppling.Text = "Toppling";
+ this.checkboxToppling.UseVisualStyleBackColor = true;
//
- // labelRouteInstallDirectory
+ // groupboxSound
//
- this.labelRouteInstallDirectory.AutoSize = true;
- this.labelRouteInstallDirectory.Location = new System.Drawing.Point(6, 21);
- this.labelRouteInstallDirectory.Name = "labelRouteInstallDirectory";
- this.labelRouteInstallDirectory.Size = new System.Drawing.Size(134, 13);
- this.labelRouteInstallDirectory.TabIndex = 1;
- this.labelRouteInstallDirectory.Text = "Route installation directory:";
+ this.groupboxSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupboxSound.Controls.Add(this.updownSoundNumber);
+ this.groupboxSound.Controls.Add(this.labelSoundNumber);
+ this.groupboxSound.ForeColor = System.Drawing.Color.Black;
+ this.groupboxSound.Location = new System.Drawing.Point(0, 88);
+ this.groupboxSound.Name = "groupboxSound";
+ this.groupboxSound.Size = new System.Drawing.Size(316, 48);
+ this.groupboxSound.TabIndex = 9;
+ this.groupboxSound.TabStop = false;
+ this.groupboxSound.Text = "Sound";
//
- // textBoxRouteDirectory
+ // updownSoundNumber
//
- this.textBoxRouteDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ this.updownSoundNumber.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.updownSoundNumber.Location = new System.Drawing.Point(140, 16);
+ this.updownSoundNumber.Maximum = new decimal(new int[] {
+ 128,
+ 0,
+ 0,
+ 0});
+ this.updownSoundNumber.Minimum = new decimal(new int[] {
+ 8,
+ 0,
+ 0,
+ 0});
+ this.updownSoundNumber.Name = "updownSoundNumber";
+ this.updownSoundNumber.Size = new System.Drawing.Size(152, 20);
+ this.updownSoundNumber.TabIndex = 3;
+ this.updownSoundNumber.Value = new decimal(new int[] {
+ 16,
+ 0,
+ 0,
+ 0});
+ //
+ // labelSoundNumber
+ //
+ this.labelSoundNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.textBoxRouteDirectory.BackColor = System.Drawing.SystemColors.Control;
- this.textBoxRouteDirectory.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxRouteDirectory.Location = new System.Drawing.Point(200, 20);
- this.textBoxRouteDirectory.Name = "textBoxRouteDirectory";
- this.textBoxRouteDirectory.ReadOnly = true;
- this.textBoxRouteDirectory.Size = new System.Drawing.Size(387, 20);
- this.textBoxRouteDirectory.TabIndex = 0;
+ this.labelSoundNumber.Location = new System.Drawing.Point(5, 18);
+ this.labelSoundNumber.Name = "labelSoundNumber";
+ this.labelSoundNumber.Size = new System.Drawing.Size(136, 18);
+ this.labelSoundNumber.TabIndex = 2;
+ this.labelSoundNumber.Text = "Number of allowed sounds:";
+ this.labelSoundNumber.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// pictureboxLanguage
//
@@ -3032,7 +3072,7 @@ private void InitializeComponent() {
//
this.labelFillerThree.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelFillerThree.BackColor = System.Drawing.Color.Silver;
- this.labelFillerThree.Location = new System.Drawing.Point(0, 583);
+ this.labelFillerThree.Location = new System.Drawing.Point(0, 613);
this.labelFillerThree.Name = "labelFillerThree";
this.labelFillerThree.Size = new System.Drawing.Size(160, 48);
this.labelFillerThree.TabIndex = 4;
@@ -3153,7 +3193,7 @@ private void InitializeComponent() {
this.panelReview.Controls.Add(this.labelReviewTitleBackground);
this.panelReview.Location = new System.Drawing.Point(160, 0);
this.panelReview.Name = "panelReview";
- this.panelReview.Size = new System.Drawing.Size(699, 631);
+ this.panelReview.Size = new System.Drawing.Size(699, 661);
this.panelReview.TabIndex = 10;
//
// comboboxBlackBoxFormat
@@ -3161,7 +3201,7 @@ private void InitializeComponent() {
this.comboboxBlackBoxFormat.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.comboboxBlackBoxFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboboxBlackBoxFormat.FormattingEnabled = true;
- this.comboboxBlackBoxFormat.Location = new System.Drawing.Point(104, 599);
+ this.comboboxBlackBoxFormat.Location = new System.Drawing.Point(104, 629);
this.comboboxBlackBoxFormat.Name = "comboboxBlackBoxFormat";
this.comboboxBlackBoxFormat.Size = new System.Drawing.Size(144, 21);
this.comboboxBlackBoxFormat.TabIndex = 12;
@@ -3171,7 +3211,7 @@ private void InitializeComponent() {
this.labelBlackBoxFormat.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelBlackBoxFormat.AutoEllipsis = true;
this.labelBlackBoxFormat.ForeColor = System.Drawing.Color.Black;
- this.labelBlackBoxFormat.Location = new System.Drawing.Point(8, 602);
+ this.labelBlackBoxFormat.Location = new System.Drawing.Point(8, 632);
this.labelBlackBoxFormat.Name = "labelBlackBoxFormat";
this.labelBlackBoxFormat.Size = new System.Drawing.Size(96, 18);
this.labelBlackBoxFormat.TabIndex = 11;
@@ -3238,7 +3278,7 @@ private void InitializeComponent() {
//
this.buttonBlackBoxExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonBlackBoxExport.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonBlackBoxExport.Location = new System.Drawing.Point(256, 597);
+ this.buttonBlackBoxExport.Location = new System.Drawing.Point(256, 627);
this.buttonBlackBoxExport.Name = "buttonBlackBoxExport";
this.buttonBlackBoxExport.Size = new System.Drawing.Size(120, 26);
this.buttonBlackBoxExport.TabIndex = 13;
@@ -3254,7 +3294,7 @@ private void InitializeComponent() {
this.labelBlackBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(107)))), ((int)(((byte)(107)))));
this.labelBlackBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelBlackBox.ForeColor = System.Drawing.Color.White;
- this.labelBlackBox.Location = new System.Drawing.Point(8, 567);
+ this.labelBlackBox.Location = new System.Drawing.Point(8, 597);
this.labelBlackBox.Name = "labelBlackBox";
this.labelBlackBox.Size = new System.Drawing.Size(683, 24);
this.labelBlackBox.TabIndex = 10;
@@ -3272,7 +3312,7 @@ private void InitializeComponent() {
this.groupboxScore.ForeColor = System.Drawing.Color.Black;
this.groupboxScore.Location = new System.Drawing.Point(272, 176);
this.groupboxScore.Name = "groupboxScore";
- this.groupboxScore.Size = new System.Drawing.Size(419, 383);
+ this.groupboxScore.Size = new System.Drawing.Size(419, 413);
this.groupboxScore.TabIndex = 0;
this.groupboxScore.TabStop = false;
this.groupboxScore.Text = "Log";
@@ -3281,7 +3321,7 @@ private void InitializeComponent() {
//
this.checkboxScorePenalties.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.checkboxScorePenalties.AutoSize = true;
- this.checkboxScorePenalties.Location = new System.Drawing.Point(8, 356);
+ this.checkboxScorePenalties.Location = new System.Drawing.Point(8, 386);
this.checkboxScorePenalties.Name = "checkboxScorePenalties";
this.checkboxScorePenalties.Size = new System.Drawing.Size(120, 17);
this.checkboxScorePenalties.TabIndex = 1;
@@ -3294,7 +3334,7 @@ private void InitializeComponent() {
this.buttonScoreExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonScoreExport.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonScoreExport.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonScoreExport.Location = new System.Drawing.Point(291, 350);
+ this.buttonScoreExport.Location = new System.Drawing.Point(291, 380);
this.buttonScoreExport.Name = "buttonScoreExport";
this.buttonScoreExport.Size = new System.Drawing.Size(120, 26);
this.buttonScoreExport.TabIndex = 2;
@@ -3321,7 +3361,7 @@ private void InitializeComponent() {
this.listviewScore.MultiSelect = false;
this.listviewScore.Name = "listviewScore";
this.listviewScore.ShowGroups = false;
- this.listviewScore.Size = new System.Drawing.Size(403, 327);
+ this.listviewScore.Size = new System.Drawing.Size(403, 357);
this.listviewScore.TabIndex = 0;
this.listviewScore.UseCompatibleStateImageBehavior = false;
this.listviewScore.View = System.Windows.Forms.View.Details;
@@ -3632,14 +3672,14 @@ private void InitializeComponent() {
this.panelControls.Controls.Add(this.groupboxControl);
this.panelControls.Location = new System.Drawing.Point(160, 0);
this.panelControls.Name = "panelControls";
- this.panelControls.Size = new System.Drawing.Size(699, 631);
+ this.panelControls.Size = new System.Drawing.Size(699, 661);
this.panelControls.TabIndex = 13;
//
// buttonControlReset
//
this.buttonControlReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonControlReset.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlReset.Location = new System.Drawing.Point(8, 293);
+ this.buttonControlReset.Location = new System.Drawing.Point(8, 323);
this.buttonControlReset.Name = "buttonControlReset";
this.buttonControlReset.Size = new System.Drawing.Size(96, 26);
this.buttonControlReset.TabIndex = 12;
@@ -3651,7 +3691,7 @@ private void InitializeComponent() {
//
this.buttonControlsExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonControlsExport.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlsExport.Location = new System.Drawing.Point(320, 262);
+ this.buttonControlsExport.Location = new System.Drawing.Point(320, 292);
this.buttonControlsExport.Name = "buttonControlsExport";
this.buttonControlsExport.Size = new System.Drawing.Size(96, 26);
this.buttonControlsExport.TabIndex = 7;
@@ -3663,7 +3703,7 @@ private void InitializeComponent() {
//
this.buttonControlsImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonControlsImport.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlsImport.Location = new System.Drawing.Point(216, 262);
+ this.buttonControlsImport.Location = new System.Drawing.Point(216, 292);
this.buttonControlsImport.Name = "buttonControlsImport";
this.buttonControlsImport.Size = new System.Drawing.Size(96, 26);
this.buttonControlsImport.TabIndex = 6;
@@ -3675,7 +3715,7 @@ private void InitializeComponent() {
//
this.buttonControlDown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonControlDown.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlDown.Location = new System.Drawing.Point(595, 262);
+ this.buttonControlDown.Location = new System.Drawing.Point(595, 292);
this.buttonControlDown.Name = "buttonControlDown";
this.buttonControlDown.Size = new System.Drawing.Size(96, 26);
this.buttonControlDown.TabIndex = 9;
@@ -3687,7 +3727,7 @@ private void InitializeComponent() {
//
this.buttonControlUp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonControlUp.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlUp.Location = new System.Drawing.Point(491, 262);
+ this.buttonControlUp.Location = new System.Drawing.Point(491, 292);
this.buttonControlUp.Name = "buttonControlUp";
this.buttonControlUp.Size = new System.Drawing.Size(96, 26);
this.buttonControlUp.TabIndex = 8;
@@ -3699,7 +3739,7 @@ private void InitializeComponent() {
//
this.buttonControlRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonControlRemove.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlRemove.Location = new System.Drawing.Point(112, 262);
+ this.buttonControlRemove.Location = new System.Drawing.Point(112, 292);
this.buttonControlRemove.Name = "buttonControlRemove";
this.buttonControlRemove.Size = new System.Drawing.Size(96, 26);
this.buttonControlRemove.TabIndex = 5;
@@ -3711,7 +3751,7 @@ private void InitializeComponent() {
//
this.buttonControlAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonControlAdd.BackColor = System.Drawing.SystemColors.ButtonFace;
- this.buttonControlAdd.Location = new System.Drawing.Point(8, 262);
+ this.buttonControlAdd.Location = new System.Drawing.Point(8, 292);
this.buttonControlAdd.Name = "buttonControlAdd";
this.buttonControlAdd.Size = new System.Drawing.Size(96, 26);
this.buttonControlAdd.TabIndex = 4;
@@ -3725,7 +3765,7 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.groupboxJoysticks.Controls.Add(this.pictureboxJoysticks);
this.groupboxJoysticks.ForeColor = System.Drawing.Color.Black;
- this.groupboxJoysticks.Location = new System.Drawing.Point(8, 455);
+ this.groupboxJoysticks.Location = new System.Drawing.Point(8, 485);
this.groupboxJoysticks.Name = "groupboxJoysticks";
this.groupboxJoysticks.Size = new System.Drawing.Size(683, 168);
this.groupboxJoysticks.TabIndex = 11;
@@ -3764,7 +3804,7 @@ private void InitializeComponent() {
this.listviewControls.MultiSelect = false;
this.listviewControls.Name = "listviewControls";
this.listviewControls.ShowGroups = false;
- this.listviewControls.Size = new System.Drawing.Size(683, 213);
+ this.listviewControls.Size = new System.Drawing.Size(683, 243);
this.listviewControls.TabIndex = 3;
this.listviewControls.UseCompatibleStateImageBehavior = false;
this.listviewControls.View = System.Windows.Forms.View.Details;
@@ -3839,7 +3879,7 @@ private void InitializeComponent() {
this.groupboxControl.Controls.Add(this.radiobuttonKeyboard);
this.groupboxControl.Enabled = false;
this.groupboxControl.ForeColor = System.Drawing.Color.Black;
- this.groupboxControl.Location = new System.Drawing.Point(8, 319);
+ this.groupboxControl.Location = new System.Drawing.Point(8, 349);
this.groupboxControl.Name = "groupboxControl";
this.groupboxControl.Size = new System.Drawing.Size(683, 128);
this.groupboxControl.TabIndex = 10;
@@ -4048,7 +4088,7 @@ private void InitializeComponent() {
this.panelInfo.Controls.Add(this.labelVersion);
this.panelInfo.Controls.Add(this.labelInfoBottom);
this.panelInfo.Controls.Add(this.labelInfoTop);
- this.panelInfo.Location = new System.Drawing.Point(0, 487);
+ this.panelInfo.Location = new System.Drawing.Point(0, 517);
this.panelInfo.Name = "panelInfo";
this.panelInfo.Size = new System.Drawing.Size(160, 96);
this.panelInfo.TabIndex = 3;
@@ -4172,7 +4212,7 @@ private void InitializeComponent() {
this.panelPackages.Controls.Add(this.panelCreatePackage);
this.panelPackages.Location = new System.Drawing.Point(160, 0);
this.panelPackages.Name = "panelPackages";
- this.panelPackages.Size = new System.Drawing.Size(699, 631);
+ this.panelPackages.Size = new System.Drawing.Size(699, 661);
this.panelPackages.TabIndex = 14;
//
// labelPackagesTitleSeparator
@@ -4234,7 +4274,7 @@ private void InitializeComponent() {
this.panelPackageInstall.Controls.Add(this.pictureBoxPackageImage);
this.panelPackageInstall.Location = new System.Drawing.Point(0, 34);
this.panelPackageInstall.Name = "panelPackageInstall";
- this.panelPackageInstall.Size = new System.Drawing.Size(699, 597);
+ this.panelPackageInstall.Size = new System.Drawing.Size(699, 627);
this.panelPackageInstall.TabIndex = 4;
this.panelPackageInstall.DragDrop += new System.Windows.Forms.DragEventHandler(this.panelPackageInstall_DragDrop);
this.panelPackageInstall.DragEnter += new System.Windows.Forms.DragEventHandler(this.panelPackageInstall_DragEnter);
@@ -4245,7 +4285,7 @@ private void InitializeComponent() {
this.buttonBack2.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonBack2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonBack2.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonBack2.Location = new System.Drawing.Point(445, 561);
+ this.buttonBack2.Location = new System.Drawing.Point(445, 591);
this.buttonBack2.Name = "buttonBack2";
this.buttonBack2.Size = new System.Drawing.Size(120, 28);
this.buttonBack2.TabIndex = 18;
@@ -4260,7 +4300,7 @@ private void InitializeComponent() {
this.buttonNext.Enabled = false;
this.buttonNext.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonNext.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonNext.Location = new System.Drawing.Point(571, 561);
+ this.buttonNext.Location = new System.Drawing.Point(571, 591);
this.buttonNext.Name = "buttonNext";
this.buttonNext.Size = new System.Drawing.Size(120, 28);
this.buttonNext.TabIndex = 17;
@@ -4297,7 +4337,7 @@ private void InitializeComponent() {
this.buttonSelectPackage.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonSelectPackage.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonSelectPackage.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonSelectPackage.Location = new System.Drawing.Point(134, 535);
+ this.buttonSelectPackage.Location = new System.Drawing.Point(134, 565);
this.buttonSelectPackage.Name = "buttonSelectPackage";
this.buttonSelectPackage.Size = new System.Drawing.Size(180, 28);
this.buttonSelectPackage.TabIndex = 14;
@@ -4311,7 +4351,7 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.textBoxPackageDescription.BackColor = System.Drawing.SystemColors.Control;
this.textBoxPackageDescription.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxPackageDescription.Location = new System.Drawing.Point(134, 417);
+ this.textBoxPackageDescription.Location = new System.Drawing.Point(134, 447);
this.textBoxPackageDescription.Multiline = true;
this.textBoxPackageDescription.Name = "textBoxPackageDescription";
this.textBoxPackageDescription.ReadOnly = true;
@@ -4324,7 +4364,7 @@ private void InitializeComponent() {
//
this.labelPackageDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelPackageDescription.ForeColor = System.Drawing.Color.Black;
- this.labelPackageDescription.Location = new System.Drawing.Point(8, 420);
+ this.labelPackageDescription.Location = new System.Drawing.Point(8, 450);
this.labelPackageDescription.Name = "labelPackageDescription";
this.labelPackageDescription.Size = new System.Drawing.Size(120, 18);
this.labelPackageDescription.TabIndex = 12;
@@ -4335,7 +4375,7 @@ private void InitializeComponent() {
//
this.linkLabelPackageWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.linkLabelPackageWebsite.AutoSize = true;
- this.linkLabelPackageWebsite.Location = new System.Drawing.Point(134, 397);
+ this.linkLabelPackageWebsite.Location = new System.Drawing.Point(134, 427);
this.linkLabelPackageWebsite.Name = "linkLabelPackageWebsite";
this.linkLabelPackageWebsite.Size = new System.Drawing.Size(112, 13);
this.linkLabelPackageWebsite.TabIndex = 11;
@@ -4347,7 +4387,7 @@ private void InitializeComponent() {
//
this.labelPackageWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelPackageWebsite.ForeColor = System.Drawing.Color.Black;
- this.labelPackageWebsite.Location = new System.Drawing.Point(8, 397);
+ this.labelPackageWebsite.Location = new System.Drawing.Point(8, 427);
this.labelPackageWebsite.Name = "labelPackageWebsite";
this.labelPackageWebsite.Size = new System.Drawing.Size(120, 18);
this.labelPackageWebsite.TabIndex = 10;
@@ -4360,7 +4400,7 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.textBoxPackageVersion.BackColor = System.Drawing.SystemColors.Control;
this.textBoxPackageVersion.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxPackageVersion.Location = new System.Drawing.Point(134, 369);
+ this.textBoxPackageVersion.Location = new System.Drawing.Point(134, 399);
this.textBoxPackageVersion.Name = "textBoxPackageVersion";
this.textBoxPackageVersion.Size = new System.Drawing.Size(423, 20);
this.textBoxPackageVersion.TabIndex = 9;
@@ -4370,7 +4410,7 @@ private void InitializeComponent() {
//
this.labelPackageVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelPackageVersion.ForeColor = System.Drawing.Color.Black;
- this.labelPackageVersion.Location = new System.Drawing.Point(8, 372);
+ this.labelPackageVersion.Location = new System.Drawing.Point(8, 402);
this.labelPackageVersion.Name = "labelPackageVersion";
this.labelPackageVersion.Size = new System.Drawing.Size(120, 18);
this.labelPackageVersion.TabIndex = 8;
@@ -4383,7 +4423,7 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.textBoxPackageAuthor.BackColor = System.Drawing.SystemColors.Control;
this.textBoxPackageAuthor.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxPackageAuthor.Location = new System.Drawing.Point(134, 345);
+ this.textBoxPackageAuthor.Location = new System.Drawing.Point(134, 375);
this.textBoxPackageAuthor.Name = "textBoxPackageAuthor";
this.textBoxPackageAuthor.Size = new System.Drawing.Size(423, 20);
this.textBoxPackageAuthor.TabIndex = 7;
@@ -4393,7 +4433,7 @@ private void InitializeComponent() {
//
this.labelPackageAuthor.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelPackageAuthor.ForeColor = System.Drawing.Color.Black;
- this.labelPackageAuthor.Location = new System.Drawing.Point(8, 348);
+ this.labelPackageAuthor.Location = new System.Drawing.Point(8, 378);
this.labelPackageAuthor.Name = "labelPackageAuthor";
this.labelPackageAuthor.Size = new System.Drawing.Size(120, 18);
this.labelPackageAuthor.TabIndex = 6;
@@ -4406,7 +4446,7 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.textBoxPackageName.BackColor = System.Drawing.SystemColors.Control;
this.textBoxPackageName.ForeColor = System.Drawing.SystemColors.ControlText;
- this.textBoxPackageName.Location = new System.Drawing.Point(134, 321);
+ this.textBoxPackageName.Location = new System.Drawing.Point(134, 351);
this.textBoxPackageName.Name = "textBoxPackageName";
this.textBoxPackageName.Size = new System.Drawing.Size(423, 20);
this.textBoxPackageName.TabIndex = 5;
@@ -4416,7 +4456,7 @@ private void InitializeComponent() {
//
this.labelPackageName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelPackageName.ForeColor = System.Drawing.Color.Black;
- this.labelPackageName.Location = new System.Drawing.Point(8, 324);
+ this.labelPackageName.Location = new System.Drawing.Point(8, 354);
this.labelPackageName.Name = "labelPackageName";
this.labelPackageName.Size = new System.Drawing.Size(120, 18);
this.labelPackageName.TabIndex = 4;
@@ -4430,7 +4470,7 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Right)));
this.pictureBoxPackageImage.Location = new System.Drawing.Point(8, 54);
this.pictureBoxPackageImage.Name = "pictureBoxPackageImage";
- this.pictureBoxPackageImage.Size = new System.Drawing.Size(683, 241);
+ this.pictureBoxPackageImage.Size = new System.Drawing.Size(683, 271);
this.pictureBoxPackageImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureBoxPackageImage.TabIndex = 3;
this.pictureBoxPackageImage.TabStop = false;
@@ -4449,7 +4489,7 @@ private void InitializeComponent() {
this.panelUninstallResult.Controls.Add(this.buttonUninstallFinish);
this.panelUninstallResult.Location = new System.Drawing.Point(0, 34);
this.panelUninstallResult.Name = "panelUninstallResult";
- this.panelUninstallResult.Size = new System.Drawing.Size(699, 597);
+ this.panelUninstallResult.Size = new System.Drawing.Size(699, 627);
this.panelUninstallResult.TabIndex = 25;
//
// textBoxUninstallResult
@@ -4464,7 +4504,7 @@ private void InitializeComponent() {
this.textBoxUninstallResult.Name = "textBoxUninstallResult";
this.textBoxUninstallResult.ReadOnly = true;
this.textBoxUninstallResult.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
- this.textBoxUninstallResult.Size = new System.Drawing.Size(683, 438);
+ this.textBoxUninstallResult.Size = new System.Drawing.Size(683, 468);
this.textBoxUninstallResult.TabIndex = 19;
//
// labelUninstallLog
@@ -4516,7 +4556,7 @@ private void InitializeComponent() {
this.buttonUninstallFinish.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonUninstallFinish.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonUninstallFinish.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonUninstallFinish.Location = new System.Drawing.Point(276, 543);
+ this.buttonUninstallFinish.Location = new System.Drawing.Point(276, 573);
this.buttonUninstallFinish.Name = "buttonUninstallFinish";
this.buttonUninstallFinish.Size = new System.Drawing.Size(146, 40);
this.buttonUninstallFinish.TabIndex = 14;
@@ -4537,7 +4577,7 @@ private void InitializeComponent() {
this.panelSuccess.Controls.Add(this.buttonInstallFinish);
this.panelSuccess.Location = new System.Drawing.Point(0, 34);
this.panelSuccess.Name = "panelSuccess";
- this.panelSuccess.Size = new System.Drawing.Size(699, 597);
+ this.panelSuccess.Size = new System.Drawing.Size(699, 627);
this.panelSuccess.TabIndex = 23;
//
// textBoxFilesInstalled
@@ -4552,7 +4592,7 @@ private void InitializeComponent() {
this.textBoxFilesInstalled.Name = "textBoxFilesInstalled";
this.textBoxFilesInstalled.ReadOnly = true;
this.textBoxFilesInstalled.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
- this.textBoxFilesInstalled.Size = new System.Drawing.Size(683, 438);
+ this.textBoxFilesInstalled.Size = new System.Drawing.Size(683, 468);
this.textBoxFilesInstalled.TabIndex = 19;
//
// labelListFilesInstalled
@@ -4604,7 +4644,7 @@ private void InitializeComponent() {
this.buttonInstallFinish.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonInstallFinish.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonInstallFinish.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonInstallFinish.Location = new System.Drawing.Point(276, 543);
+ this.buttonInstallFinish.Location = new System.Drawing.Point(276, 573);
this.buttonInstallFinish.Name = "buttonInstallFinish";
this.buttonInstallFinish.Size = new System.Drawing.Size(146, 40);
this.buttonInstallFinish.TabIndex = 14;
@@ -4626,14 +4666,14 @@ private void InitializeComponent() {
this.panelDependancyError.Controls.Add(this.buttonProceedAnyway);
this.panelDependancyError.Location = new System.Drawing.Point(0, 34);
this.panelDependancyError.Name = "panelDependancyError";
- this.panelDependancyError.Size = new System.Drawing.Size(699, 597);
+ this.panelDependancyError.Size = new System.Drawing.Size(699, 627);
this.panelDependancyError.TabIndex = 5;
//
// buttonAbort
//
this.buttonAbort.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonAbort.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.buttonAbort.Location = new System.Drawing.Point(445, 565);
+ this.buttonAbort.Location = new System.Drawing.Point(445, 595);
this.buttonAbort.Name = "buttonAbort";
this.buttonAbort.Size = new System.Drawing.Size(120, 24);
this.buttonAbort.TabIndex = 21;
@@ -4666,7 +4706,7 @@ private void InitializeComponent() {
this.dataGridViewDependancies.RowHeadersVisible = false;
this.dataGridViewDependancies.RowHeadersWidth = 90;
this.dataGridViewDependancies.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
- this.dataGridViewDependancies.Size = new System.Drawing.Size(683, 438);
+ this.dataGridViewDependancies.Size = new System.Drawing.Size(683, 468);
this.dataGridViewDependancies.TabIndex = 20;
this.dataGridViewDependancies.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridViewDependancies_CellContentClick);
//
@@ -4750,7 +4790,7 @@ private void InitializeComponent() {
//
this.buttonProceedAnyway.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonProceedAnyway.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.buttonProceedAnyway.Location = new System.Drawing.Point(571, 565);
+ this.buttonProceedAnyway.Location = new System.Drawing.Point(571, 595);
this.buttonProceedAnyway.Name = "buttonProceedAnyway";
this.buttonProceedAnyway.Size = new System.Drawing.Size(120, 24);
this.buttonProceedAnyway.TabIndex = 14;
@@ -4769,7 +4809,7 @@ private void InitializeComponent() {
this.panelPleaseWait.Controls.Add(this.pictureBoxProcessing);
this.panelPleaseWait.Location = new System.Drawing.Point(0, 34);
this.panelPleaseWait.Name = "panelPleaseWait";
- this.panelPleaseWait.Size = new System.Drawing.Size(699, 597);
+ this.panelPleaseWait.Size = new System.Drawing.Size(699, 627);
this.panelPleaseWait.TabIndex = 28;
//
// labelProgressFile
@@ -4777,7 +4817,7 @@ private void InitializeComponent() {
this.labelProgressFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.labelProgressFile.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelProgressFile.ForeColor = System.Drawing.Color.Black;
- this.labelProgressFile.Location = new System.Drawing.Point(1, 431);
+ this.labelProgressFile.Location = new System.Drawing.Point(1, 446);
this.labelProgressFile.Name = "labelProgressFile";
this.labelProgressFile.Size = new System.Drawing.Size(697, 30);
this.labelProgressFile.TabIndex = 7;
@@ -4789,7 +4829,7 @@ private void InitializeComponent() {
this.labelProgressPercent.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.labelProgressPercent.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelProgressPercent.ForeColor = System.Drawing.Color.Black;
- this.labelProgressPercent.Location = new System.Drawing.Point(290, 401);
+ this.labelProgressPercent.Location = new System.Drawing.Point(290, 416);
this.labelProgressPercent.Name = "labelProgressPercent";
this.labelProgressPercent.Size = new System.Drawing.Size(118, 30);
this.labelProgressPercent.TabIndex = 6;
@@ -4801,7 +4841,7 @@ private void InitializeComponent() {
this.labelPleaseWait.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.labelPleaseWait.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelPleaseWait.ForeColor = System.Drawing.Color.Black;
- this.labelPleaseWait.Location = new System.Drawing.Point(1, 462);
+ this.labelPleaseWait.Location = new System.Drawing.Point(1, 477);
this.labelPleaseWait.Name = "labelPleaseWait";
this.labelPleaseWait.Size = new System.Drawing.Size(697, 30);
this.labelPleaseWait.TabIndex = 5;
@@ -4811,7 +4851,7 @@ private void InitializeComponent() {
// pictureBoxProcessing
//
this.pictureBoxProcessing.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.pictureBoxProcessing.Location = new System.Drawing.Point(174, 46);
+ this.pictureBoxProcessing.Location = new System.Drawing.Point(174, 61);
this.pictureBoxProcessing.Name = "pictureBoxProcessing";
this.pictureBoxProcessing.Size = new System.Drawing.Size(350, 350);
this.pictureBoxProcessing.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
@@ -4832,7 +4872,7 @@ private void InitializeComponent() {
this.panelPackageDependsAdd.Controls.Add(this.splitContainerDependancies);
this.panelPackageDependsAdd.Location = new System.Drawing.Point(0, 34);
this.panelPackageDependsAdd.Name = "panelPackageDependsAdd";
- this.panelPackageDependsAdd.Size = new System.Drawing.Size(699, 597);
+ this.panelPackageDependsAdd.Size = new System.Drawing.Size(699, 627);
this.panelPackageDependsAdd.TabIndex = 26;
//
// buttonBack
@@ -4841,7 +4881,7 @@ private void InitializeComponent() {
this.buttonBack.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonBack.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonBack.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonBack.Location = new System.Drawing.Point(445, 561);
+ this.buttonBack.Location = new System.Drawing.Point(445, 591);
this.buttonBack.Name = "buttonBack";
this.buttonBack.Size = new System.Drawing.Size(120, 28);
this.buttonBack.TabIndex = 28;
@@ -4855,7 +4895,7 @@ private void InitializeComponent() {
this.buttonRemove.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonRemove.Enabled = false;
this.buttonRemove.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonRemove.Location = new System.Drawing.Point(8, 525);
+ this.buttonRemove.Location = new System.Drawing.Point(8, 555);
this.buttonRemove.Name = "buttonRemove";
this.buttonRemove.Size = new System.Drawing.Size(166, 26);
this.buttonRemove.TabIndex = 25;
@@ -4867,7 +4907,7 @@ private void InitializeComponent() {
//
this.labelNoDependencyReminder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelNoDependencyReminder.ForeColor = System.Drawing.Color.Black;
- this.labelNoDependencyReminder.Location = new System.Drawing.Point(8, 560);
+ this.labelNoDependencyReminder.Location = new System.Drawing.Point(8, 590);
this.labelNoDependencyReminder.Name = "labelNoDependencyReminder";
this.labelNoDependencyReminder.Size = new System.Drawing.Size(400, 48);
this.labelNoDependencyReminder.TabIndex = 24;
@@ -4903,7 +4943,7 @@ private void InitializeComponent() {
this.buttonCreatePackage.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonCreatePackage.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonCreatePackage.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonCreatePackage.Location = new System.Drawing.Point(571, 561);
+ this.buttonCreatePackage.Location = new System.Drawing.Point(571, 591);
this.buttonCreatePackage.Name = "buttonCreatePackage";
this.buttonCreatePackage.Size = new System.Drawing.Size(120, 28);
this.buttonCreatePackage.TabIndex = 14;
@@ -4933,8 +4973,8 @@ private void InitializeComponent() {
this.splitContainerDependancies.Panel2.Controls.Add(this.buttonReccomends);
this.splitContainerDependancies.Panel2.Controls.Add(this.labelSelectedDependencies);
this.splitContainerDependancies.Panel2.Controls.Add(this.buttonDepends);
- this.splitContainerDependancies.Size = new System.Drawing.Size(683, 469);
- this.splitContainerDependancies.SplitterDistance = 244;
+ this.splitContainerDependancies.Size = new System.Drawing.Size(683, 499);
+ this.splitContainerDependancies.SplitterDistance = 259;
this.splitContainerDependancies.TabIndex = 27;
//
// labelDependancyType
@@ -4985,7 +5025,7 @@ private void InitializeComponent() {
this.dataGridViewPackages2.RowHeadersVisible = false;
this.dataGridViewPackages2.RowHeadersWidth = 90;
this.dataGridViewPackages2.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
- this.dataGridViewPackages2.Size = new System.Drawing.Size(683, 162);
+ this.dataGridViewPackages2.Size = new System.Drawing.Size(683, 177);
this.dataGridViewPackages2.TabIndex = 21;
this.dataGridViewPackages2.SelectionChanged += new System.EventHandler(this.dataGridViewPackages2_SelectionChanged);
//
@@ -5053,7 +5093,7 @@ private void InitializeComponent() {
this.dataGridViewPackages3.RowHeadersVisible = false;
this.dataGridViewPackages3.RowHeadersWidth = 90;
this.dataGridViewPackages3.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
- this.dataGridViewPackages3.Size = new System.Drawing.Size(683, 161);
+ this.dataGridViewPackages3.Size = new System.Drawing.Size(683, 176);
this.dataGridViewPackages3.TabIndex = 22;
this.dataGridViewPackages3.SelectionChanged += new System.EventHandler(this.dataGridViewPackages3_SelectionChanged);
//
@@ -5148,7 +5188,7 @@ private void InitializeComponent() {
this.panelPackageList.Controls.Add(this.labelInstalledPackages);
this.panelPackageList.Location = new System.Drawing.Point(0, 34);
this.panelPackageList.Name = "panelPackageList";
- this.panelPackageList.Size = new System.Drawing.Size(699, 597);
+ this.panelPackageList.Size = new System.Drawing.Size(699, 627);
this.panelPackageList.TabIndex = 3;
//
// comboBoxPackageType
@@ -5180,7 +5220,7 @@ private void InitializeComponent() {
this.createPackageButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.createPackageButton.BackColor = System.Drawing.SystemColors.ButtonFace;
this.createPackageButton.ForeColor = System.Drawing.SystemColors.ControlText;
- this.createPackageButton.Location = new System.Drawing.Point(281, 549);
+ this.createPackageButton.Location = new System.Drawing.Point(281, 579);
this.createPackageButton.Name = "createPackageButton";
this.createPackageButton.Size = new System.Drawing.Size(136, 26);
this.createPackageButton.TabIndex = 23;
@@ -5193,7 +5233,7 @@ private void InitializeComponent() {
this.buttonUninstallPackage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonUninstallPackage.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonUninstallPackage.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonUninstallPackage.Location = new System.Drawing.Point(555, 549);
+ this.buttonUninstallPackage.Location = new System.Drawing.Point(555, 579);
this.buttonUninstallPackage.Name = "buttonUninstallPackage";
this.buttonUninstallPackage.Size = new System.Drawing.Size(136, 26);
this.buttonUninstallPackage.TabIndex = 21;
@@ -5206,7 +5246,7 @@ private void InitializeComponent() {
this.buttonInstallPackage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.buttonInstallPackage.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonInstallPackage.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonInstallPackage.Location = new System.Drawing.Point(8, 549);
+ this.buttonInstallPackage.Location = new System.Drawing.Point(8, 579);
this.buttonInstallPackage.Name = "buttonInstallPackage";
this.buttonInstallPackage.Size = new System.Drawing.Size(136, 26);
this.buttonInstallPackage.TabIndex = 20;
@@ -5238,7 +5278,7 @@ private void InitializeComponent() {
this.dataGridViewPackages.RowHeadersVisible = false;
this.dataGridViewPackages.RowHeadersWidth = 90;
this.dataGridViewPackages.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
- this.dataGridViewPackages.Size = new System.Drawing.Size(683, 454);
+ this.dataGridViewPackages.Size = new System.Drawing.Size(683, 484);
this.dataGridViewPackages.TabIndex = 19;
this.dataGridViewPackages.SelectionChanged += new System.EventHandler(this.dataGridViewPackages_SelectionChanged);
//
@@ -5300,7 +5340,7 @@ private void InitializeComponent() {
this.panelVersionError.Controls.Add(this.labelVersionHeaderBackground);
this.panelVersionError.Location = new System.Drawing.Point(0, 34);
this.panelVersionError.Name = "panelVersionError";
- this.panelVersionError.Size = new System.Drawing.Size(699, 597);
+ this.panelVersionError.Size = new System.Drawing.Size(699, 627);
this.panelVersionError.TabIndex = 24;
//
// buttonCancel
@@ -5309,7 +5349,7 @@ private void InitializeComponent() {
this.buttonCancel.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonCancel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonCancel.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonCancel.Location = new System.Drawing.Point(445, 561);
+ this.buttonCancel.Location = new System.Drawing.Point(445, 591);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(120, 28);
this.buttonCancel.TabIndex = 29;
@@ -5341,7 +5381,7 @@ private void InitializeComponent() {
//
this.buttonProceedAnyway1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonProceedAnyway1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.buttonProceedAnyway1.Location = new System.Drawing.Point(571, 565);
+ this.buttonProceedAnyway1.Location = new System.Drawing.Point(571, 595);
this.buttonProceedAnyway1.Name = "buttonProceedAnyway1";
this.buttonProceedAnyway1.Size = new System.Drawing.Size(120, 24);
this.buttonProceedAnyway1.TabIndex = 14;
@@ -5517,7 +5557,7 @@ private void InitializeComponent() {
this.panelCreatePackage.Controls.Add(this.panelNewPackage);
this.panelCreatePackage.Location = new System.Drawing.Point(0, 34);
this.panelCreatePackage.Name = "panelCreatePackage";
- this.panelCreatePackage.Size = new System.Drawing.Size(699, 597);
+ this.panelCreatePackage.Size = new System.Drawing.Size(699, 627);
this.panelCreatePackage.TabIndex = 27;
//
// buttonCancel2
@@ -5526,7 +5566,7 @@ private void InitializeComponent() {
this.buttonCancel2.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonCancel2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonCancel2.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonCancel2.Location = new System.Drawing.Point(445, 561);
+ this.buttonCancel2.Location = new System.Drawing.Point(445, 591);
this.buttonCancel2.Name = "buttonCancel2";
this.buttonCancel2.Size = new System.Drawing.Size(120, 28);
this.buttonCancel2.TabIndex = 38;
@@ -5539,7 +5579,7 @@ private void InitializeComponent() {
this.SaveFileNameButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.SaveFileNameButton.BackColor = System.Drawing.SystemColors.ButtonFace;
this.SaveFileNameButton.ForeColor = System.Drawing.SystemColors.ControlText;
- this.SaveFileNameButton.Location = new System.Drawing.Point(571, 510);
+ this.SaveFileNameButton.Location = new System.Drawing.Point(571, 540);
this.SaveFileNameButton.Name = "SaveFileNameButton";
this.SaveFileNameButton.Size = new System.Drawing.Size(120, 26);
this.SaveFileNameButton.TabIndex = 37;
@@ -5551,7 +5591,7 @@ private void InitializeComponent() {
//
this.textBoxPackageFileName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.textBoxPackageFileName.Location = new System.Drawing.Point(8, 511);
+ this.textBoxPackageFileName.Location = new System.Drawing.Point(8, 541);
this.textBoxPackageFileName.Name = "textBoxPackageFileName";
this.textBoxPackageFileName.Size = new System.Drawing.Size(557, 20);
this.textBoxPackageFileName.TabIndex = 36;
@@ -5561,7 +5601,7 @@ private void InitializeComponent() {
this.labelSaveAs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelSaveAs.AutoSize = true;
this.labelSaveAs.ForeColor = System.Drawing.Color.Black;
- this.labelSaveAs.Location = new System.Drawing.Point(8, 495);
+ this.labelSaveAs.Location = new System.Drawing.Point(8, 525);
this.labelSaveAs.Name = "labelSaveAs";
this.labelSaveAs.Size = new System.Drawing.Size(94, 13);
this.labelSaveAs.TabIndex = 35;
@@ -5572,7 +5612,7 @@ private void InitializeComponent() {
this.labelDependanciesNextStep.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelDependanciesNextStep.AutoSize = true;
this.labelDependanciesNextStep.ForeColor = System.Drawing.Color.Black;
- this.labelDependanciesNextStep.Location = new System.Drawing.Point(8, 541);
+ this.labelDependanciesNextStep.Location = new System.Drawing.Point(8, 571);
this.labelDependanciesNextStep.Name = "labelDependanciesNextStep";
this.labelDependanciesNextStep.Size = new System.Drawing.Size(360, 13);
this.labelDependanciesNextStep.TabIndex = 34;
@@ -5584,7 +5624,7 @@ private void InitializeComponent() {
this.buttonCreateProceed.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonCreateProceed.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonCreateProceed.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonCreateProceed.Location = new System.Drawing.Point(571, 561);
+ this.buttonCreateProceed.Location = new System.Drawing.Point(571, 591);
this.buttonCreateProceed.Name = "buttonCreateProceed";
this.buttonCreateProceed.Size = new System.Drawing.Size(120, 28);
this.buttonCreateProceed.TabIndex = 22;
@@ -5734,14 +5774,14 @@ private void InitializeComponent() {
this.panelReplacePackage.Controls.Add(this.dataGridViewReplacePackage);
this.panelReplacePackage.Location = new System.Drawing.Point(0, 137);
this.panelReplacePackage.Name = "panelReplacePackage";
- this.panelReplacePackage.Size = new System.Drawing.Size(699, 352);
+ this.panelReplacePackage.Size = new System.Drawing.Size(699, 382);
this.panelReplacePackage.TabIndex = 20;
//
// replacePackageButton
//
this.replacePackageButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.replacePackageButton.Enabled = false;
- this.replacePackageButton.Location = new System.Drawing.Point(270, 303);
+ this.replacePackageButton.Location = new System.Drawing.Point(270, 333);
this.replacePackageButton.Name = "replacePackageButton";
this.replacePackageButton.Size = new System.Drawing.Size(159, 23);
this.replacePackageButton.TabIndex = 25;
@@ -5782,7 +5822,7 @@ private void InitializeComponent() {
this.dataGridViewReplacePackage.RowHeadersVisible = false;
this.dataGridViewReplacePackage.RowHeadersWidth = 90;
this.dataGridViewReplacePackage.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
- this.dataGridViewReplacePackage.Size = new System.Drawing.Size(683, 274);
+ this.dataGridViewReplacePackage.Size = new System.Drawing.Size(683, 304);
this.dataGridViewReplacePackage.TabIndex = 23;
this.dataGridViewReplacePackage.SelectionChanged += new System.EventHandler(this.dataGridViewReplacePackage_SelectionChanged);
//
@@ -5828,7 +5868,7 @@ private void InitializeComponent() {
this.panelNewPackage.Enabled = false;
this.panelNewPackage.Location = new System.Drawing.Point(-2, 137);
this.panelNewPackage.Name = "panelNewPackage";
- this.panelNewPackage.Size = new System.Drawing.Size(702, 355);
+ this.panelNewPackage.Size = new System.Drawing.Size(702, 385);
this.panelNewPackage.TabIndex = 21;
//
// newPackageClearSelectionButton
@@ -5836,7 +5876,7 @@ private void InitializeComponent() {
this.newPackageClearSelectionButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.newPackageClearSelectionButton.BackColor = System.Drawing.SystemColors.ButtonFace;
this.newPackageClearSelectionButton.ForeColor = System.Drawing.SystemColors.ControlText;
- this.newPackageClearSelectionButton.Location = new System.Drawing.Point(572, 326);
+ this.newPackageClearSelectionButton.Location = new System.Drawing.Point(572, 356);
this.newPackageClearSelectionButton.Name = "newPackageClearSelectionButton";
this.newPackageClearSelectionButton.Size = new System.Drawing.Size(121, 26);
this.newPackageClearSelectionButton.TabIndex = 30;
@@ -5854,7 +5894,7 @@ private void InitializeComponent() {
this.filesToPackageBox.Multiline = true;
this.filesToPackageBox.Name = "filesToPackageBox";
this.filesToPackageBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
- this.filesToPackageBox.Size = new System.Drawing.Size(685, 250);
+ this.filesToPackageBox.Size = new System.Drawing.Size(685, 280);
this.filesToPackageBox.TabIndex = 29;
//
// addPackageItemsButton
@@ -5862,7 +5902,7 @@ private void InitializeComponent() {
this.addPackageItemsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.addPackageItemsButton.BackColor = System.Drawing.SystemColors.ButtonFace;
this.addPackageItemsButton.ForeColor = System.Drawing.SystemColors.ControlText;
- this.addPackageItemsButton.Location = new System.Drawing.Point(8, 326);
+ this.addPackageItemsButton.Location = new System.Drawing.Point(8, 356);
this.addPackageItemsButton.Name = "addPackageItemsButton";
this.addPackageItemsButton.Size = new System.Drawing.Size(121, 26);
this.addPackageItemsButton.TabIndex = 28;
@@ -5902,10 +5942,10 @@ private void InitializeComponent() {
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.White;
- this.ClientSize = new System.Drawing.Size(859, 631);
+ this.ClientSize = new System.Drawing.Size(859, 661);
this.Controls.Add(this.labelVerticalSeparator);
- this.Controls.Add(this.panelPackages);
this.Controls.Add(this.panelOptions);
+ this.Controls.Add(this.panelPackages);
this.Controls.Add(this.panelStart);
this.Controls.Add(this.panelInfo);
this.Controls.Add(this.panelPanels);
@@ -5948,7 +5988,6 @@ private void InitializeComponent() {
this.groupboxRouteDetails.ResumeLayout(false);
this.tabcontrolRouteDetails.ResumeLayout(false);
this.tabpageRouteDescription.ResumeLayout(false);
- this.tabpageRouteDescription.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureboxRouteImage)).EndInit();
this.tabpageRouteMap.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureboxRouteMap)).EndInit();
@@ -5960,6 +5999,18 @@ private void InitializeComponent() {
this.panelRouteEncoding.ResumeLayout(false);
this.panelOptions.ResumeLayout(false);
this.panelOptions.PerformLayout();
+ this.panelOptionsPage2.ResumeLayout(false);
+ this.groupBoxInputDevice.ResumeLayout(false);
+ this.groupBoxObjectParser.ResumeLayout(false);
+ this.groupBoxKioskMode.ResumeLayout(false);
+ this.groupBoxKioskMode.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDownKioskTimeout)).EndInit();
+ this.groupBoxAdvancedOptions.ResumeLayout(false);
+ this.groupBoxAdvancedOptions.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureboxCursor)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.updownTimeAccelerationFactor)).EndInit();
+ this.groupBoxPackageOptions.ResumeLayout(false);
+ this.groupBoxPackageOptions.PerformLayout();
this.panelOptionsLeft.ResumeLayout(false);
this.groupboxDisplayMode.ResumeLayout(false);
this.groupboxDisplayMode.PerformLayout();
@@ -5990,18 +6041,6 @@ private void InitializeComponent() {
this.groupboxSimulation.PerformLayout();
this.groupboxSound.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.updownSoundNumber)).EndInit();
- this.panelOptionsPage2.ResumeLayout(false);
- this.groupBoxInputDevice.ResumeLayout(false);
- this.groupBoxObjectParser.ResumeLayout(false);
- this.groupBoxKioskMode.ResumeLayout(false);
- this.groupBoxKioskMode.PerformLayout();
- ((System.ComponentModel.ISupportInitialize)(this.numericUpDownKioskTimeout)).EndInit();
- this.groupBoxAdvancedOptions.ResumeLayout(false);
- this.groupBoxAdvancedOptions.PerformLayout();
- ((System.ComponentModel.ISupportInitialize)(this.pictureboxCursor)).EndInit();
- ((System.ComponentModel.ISupportInitialize)(this.updownTimeAccelerationFactor)).EndInit();
- this.groupBoxPackageOptions.ResumeLayout(false);
- this.groupBoxPackageOptions.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureboxLanguage)).EndInit();
this.panelPanels.ResumeLayout(false);
this.panelPanels.PerformLayout();
@@ -6508,5 +6547,8 @@ private void InitializeComponent() {
private System.Windows.Forms.ComboBox comboBoxFont;
private System.Windows.Forms.Label labelFontName;
private System.Windows.Forms.Label labelNoDependencyReminder;
+ private System.Windows.Forms.Button buttonMSTSTrainsetDirectory;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TextBox textBoxMSTSTrainsetDirectory;
}
}
diff --git a/source/OpenBVE/UserInterface/formMain.Start.cs b/source/OpenBVE/UserInterface/formMain.Start.cs
index 04fc6d208d..5c0dcccfc4 100644
--- a/source/OpenBVE/UserInterface/formMain.Start.cs
+++ b/source/OpenBVE/UserInterface/formMain.Start.cs
@@ -15,6 +15,7 @@
using OpenBveApi.Interface;
using OpenBveApi.Routes;
using RouteManager2;
+using TrainManager.SafetySystems;
using Path = OpenBveApi.Path;
namespace OpenBve
@@ -660,6 +661,11 @@ private void OnTrainFolderChanged(object sender, EventArgs e)
/// Whether this is a packaged content folder
private void PopulateTrainList(string selectedFolder, ListView listView, bool packages)
{
+ string error; //ignored in this case, background thread
+ if (Program.CurrentHost.Plugins == null && !Program.CurrentHost.LoadPlugins(Program.FileSystem, Interface.CurrentOptions, out error, Program.TrainManager, Program.Renderer))
+ {
+ throw new Exception("Unable to load the required plugins- Please reinstall OpenBVE");
+ }
try
{
if (selectedFolder.Length == 0)
@@ -717,7 +723,9 @@ private void PopulateTrainList(string selectedFolder, ListView listView, bool pa
try
{
string[] Folders = Directory.GetDirectories(selectedFolder);
+ string[] Files = Directory.GetFiles(selectedFolder);
Array.Sort(Folders);
+ Array.Sort(Files);
for (int i = 0; i < Folders.Length; i++)
{
try
@@ -744,6 +752,26 @@ private void PopulateTrainList(string selectedFolder, ListView listView, bool pa
//Most likely permissions
}
}
+
+ for (int i = 0; i < Files.Length; i++)
+ {
+ for (int j = 0; j < Program.CurrentHost.Plugins.Length; j++)
+ {
+ string fileName = Path.GetFileName(Files[i]);
+ if (fileName[0] == '#' && fileName.EndsWith(".con", StringComparison.InvariantCultureIgnoreCase))
+ {
+ // MSTS / ORTS use a hash at the start of the filename to deliminate AI consists
+ // These generally have missing cabviews etc- Hide from visibility in the main menu
+ continue;
+ }
+ if (Program.CurrentHost.Plugins[j].Train != null && Program.CurrentHost.Plugins[j].Train.CanLoadTrain(Files[i]))
+ {
+ ListViewItem Item = listviewTrainFolders.Items.Add(System.IO.Path.GetFileName(Files[i]));
+ Item.ImageKey = @"msts";
+ Item.Tag = Files[i];
+ }
+ }
+ }
}
catch
{
@@ -776,7 +804,13 @@ private void listviewTrainFolders_SelectedIndexChanged(object sender, EventArgs
return;
}
if (t != null) {
- if (Directory.Exists(t)) {
+ if (t.EndsWith(".con", StringComparison.InvariantCultureIgnoreCase))
+ {
+ Result.TrainFolder = t;
+ ShowTrain(false);
+ }
+ else if (Directory.Exists(t))
+ {
try
{
string File = Path.CombineFile(t, "train.dat");
@@ -1106,8 +1140,29 @@ private void buttonTrainEncodingBig5_Click(object sender, EventArgs e) {
private readonly object StartGame = new Object();
private void buttonStart_Click(object sender, EventArgs e) {
- if (Result.RouteFile != null & Result.TrainFolder != null) {
- if (File.Exists(Result.RouteFile) & Directory.Exists(Result.TrainFolder)) {
+ if (Result.RouteFile != null & Result.TrainFolder != null)
+ {
+ bool canLoadRoute = false, canLoadTrain = false;
+ for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++)
+ {
+ if (canLoadRoute == false)
+ {
+ if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(Result.RouteFile))
+ {
+ canLoadRoute = true;
+ }
+ }
+ if (canLoadTrain == false)
+ {
+ if (Program.CurrentHost.Plugins[i].Train != null && Program.CurrentHost.Plugins[i].Train.CanLoadTrain(Result.TrainFolder))
+ {
+ canLoadTrain = true;
+ }
+ }
+ }
+
+ if (canLoadRoute && canLoadTrain)
+ {
Result.Start = true;
buttonClose_Click(StartGame, e);
//HACK: Call Application.DoEvents() to force the message pump to process all pending messages when the form closes
diff --git a/source/OpenBVE/UserInterface/formMain.cs b/source/OpenBVE/UserInterface/formMain.cs
index 5b3fd77f99..336754e1f6 100644
--- a/source/OpenBVE/UserInterface/formMain.cs
+++ b/source/OpenBVE/UserInterface/formMain.cs
@@ -153,6 +153,7 @@ private void formMain_Load(object sender, EventArgs e)
Image MechanikRouteIcon = LoadImage(MenuFolder, "icon_mechanik.png");
Image Bve5Icon = LoadImage(MenuFolder, "icon_bve5.png");
Image TrainIcon = LoadImage(MenuFolder, "icon_train.png");
+ Image MSTSIcon = LoadImage(MenuFolder, "icon_msts.png");
Image KeyboardIcon = LoadImage(MenuFolder, "icon_keyboard.png");
Image MouseIcon = LoadImage(MenuFolder, "icon_mouse.png");
Image JoystickIcon = LoadImage(MenuFolder, "icon_joystick.png");
@@ -233,6 +234,7 @@ private void formMain_Load(object sender, EventArgs e)
if (ParentIcon != null) listviewTrainFolders.SmallImageList.Images.Add("parent", ParentIcon);
if (FolderIcon != null) listviewTrainFolders.SmallImageList.Images.Add("folder", FolderIcon);
if (TrainIcon != null) listviewTrainFolders.SmallImageList.Images.Add("train", TrainIcon);
+ if (MSTSIcon != null) listviewTrainFolders.SmallImageList.Images.Add("msts", MSTSIcon);
if (DiskIcon != null) listviewTrainFolders.SmallImageList.Images.Add("disk", DiskIcon);
if (ParentIcon != null) listViewTrainPackages.SmallImageList.Images.Add("parent", ParentIcon);
if (FolderIcon != null) listViewTrainPackages.SmallImageList.Images.Add("folder", FolderIcon);
@@ -245,6 +247,7 @@ private void formMain_Load(object sender, EventArgs e)
listviewTrainRecently.Columns.Add("");
listviewTrainRecently.SmallImageList = new ImageList { TransparentColor = Color.White };
if (TrainIcon != null) listviewTrainRecently.SmallImageList.Images.Add("train", TrainIcon);
+ if (MSTSIcon != null) listviewTrainRecently.SmallImageList.Images.Add("msts", MSTSIcon);
for (int i = 0; i < Interface.CurrentOptions.RecentlyUsedTrains.Length; i++)
{
if (string.IsNullOrEmpty(Interface.CurrentOptions.RecentlyUsedTrains[i])) continue;
@@ -255,7 +258,7 @@ private void formMain_Load(object sender, EventArgs e)
continue;
}
ListViewItem Item = listviewTrainRecently.Items.Add(trainFileName);
- Item.ImageKey = @"train";
+ Item.ImageKey = trainFileName.EndsWith(".con", StringComparison.InvariantCultureIgnoreCase) ? @"msts" : @"train";
Item.Tag = Interface.CurrentOptions.RecentlyUsedTrains[i];
if (textboxTrainFolder.Items.Count == 0 || !textboxTrainFolder.Items.Contains(trainPath))
{
@@ -739,9 +742,11 @@ private void ApplyLanguage()
textBoxRouteDirectory.Text = Program.FileSystem.RouteInstallationDirectory;
textBoxTrainDirectory.Text = Program.FileSystem.TrainInstallationDirectory;
textBoxOtherDirectory.Text = Program.FileSystem.OtherInstallationDirectory;
+ textBoxMSTSTrainsetDirectory.Text = Program.FileSystem.MSTSDirectory;
labelRouteInstallDirectory.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","package_route_directory"});
labelTrainInstallDirectory.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","package_train_directory"});
labelOtherInstallDirectory.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","package_other_directory"});
+ labelOtherInstallDirectory.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "package_msts_directory" });
labelPackageCompression.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","package_compression"});
//Kiosk Mode
groupBoxKioskMode.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","kiosk_mode"});
@@ -1198,7 +1203,7 @@ private void formMain_FormClosing()
string[] a = new string[Interface.CurrentOptions.RecentlyUsedTrains.Length];
for (int i = 0; i < Interface.CurrentOptions.RecentlyUsedTrains.Length; i++)
{
- if (Directory.Exists(Interface.CurrentOptions.RecentlyUsedTrains[i]))
+ if ((Interface.CurrentOptions.RecentlyUsedTrains[i].EndsWith(".con", StringComparison.InvariantCultureIgnoreCase) && File.Exists(Interface.CurrentOptions.RecentlyUsedTrains[i])) || Directory.Exists(Interface.CurrentOptions.RecentlyUsedTrains[i]))
{
a[n] = Interface.CurrentOptions.RecentlyUsedTrains[i];
n++;
@@ -2061,5 +2066,17 @@ private void textboxTrainDescription_LinkClicked(object sender, LinkClickedEvent
{
Process.Start(e.LinkText);
}
+
+ private void buttonMSTSTrainsetDirectory_Click(object sender, EventArgs e)
+ {
+ using (var folderSelectDialog = new FolderBrowserDialog())
+ {
+ if (folderSelectDialog.ShowDialog() == DialogResult.OK)
+ {
+ Program.FileSystem.MSTSDirectory = folderSelectDialog.SelectedPath;
+ textBoxMSTSTrainsetDirectory.Text = folderSelectDialog.SelectedPath;
+ }
+ }
+ }
}
}
diff --git a/source/OpenBVE/UserInterface/formMain.resx b/source/OpenBVE/UserInterface/formMain.resx
index 77fa901946..2d26dd8152 100644
--- a/source/OpenBVE/UserInterface/formMain.resx
+++ b/source/OpenBVE/UserInterface/formMain.resx
@@ -120,10 +120,10 @@
456, 18
-
+
True
-
+
True
diff --git a/source/OpenBveApi/Objects/ObjectInterface.cs b/source/OpenBveApi/Objects/ObjectInterface.cs
index e3e6d96bb9..7d27418252 100644
--- a/source/OpenBveApi/Objects/ObjectInterface.cs
+++ b/source/OpenBveApi/Objects/ObjectInterface.cs
@@ -47,7 +47,7 @@ public virtual void SetObjectParser(object parserType)
/// Receives the object.
/// The encoding for the object
/// Whether loading the object was successful.
- public abstract bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject unifiedObject);
+ public abstract bool LoadObject(string path, System.Text.Encoding textEncoding, out UnifiedObject unifiedObject);
/// Loads the specified object.
/// The path to the file or folder that contains the object.
diff --git a/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs b/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs
index 760c52192b..c43b468bb6 100644
--- a/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs
+++ b/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs
@@ -729,7 +729,7 @@ public void Update(AbstractTrain Train, int CarIndex, double TrackPosition, Vect
internalObject.Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
}
- if (ColorFunction != null)
+ if (ColorFunction != null && Colors != null)
{
int color = (int)ColorFunction.LastResult;
if (UpdateFunctions)
diff --git a/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs b/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs
index 08cfe798d2..510b3c1af3 100644
--- a/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs
+++ b/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs
@@ -87,6 +87,7 @@ public void CreateObject(Vector3 Position, Transformation WorldTransformation, T
/// The X value
/// The Y value
/// The Z value
+ /// Controls whether the translation is added to the root matrix, or replaces it
public abstract void ApplyTranslation(double x, double y, double z, bool absoluteTranslation = false);
}
diff --git a/source/OpenBveApi/OpenBveApi.csproj b/source/OpenBveApi/OpenBveApi.csproj
index 75329db2e3..c630fb743d 100644
--- a/source/OpenBveApi/OpenBveApi.csproj
+++ b/source/OpenBveApi/OpenBveApi.csproj
@@ -265,6 +265,7 @@
+
diff --git a/source/OpenBveApi/Runtime/System/CameraViewMode.cs b/source/OpenBveApi/Runtime/System/CameraViewMode.cs
index 6f1715b063..70e5d25968 100644
--- a/source/OpenBveApi/Runtime/System/CameraViewMode.cs
+++ b/source/OpenBveApi/Runtime/System/CameraViewMode.cs
@@ -1,19 +1,26 @@
-namespace OpenBveApi.Runtime
+using System;
+
+namespace OpenBveApi.Runtime
{
+
/// Represents the available camera view modes.
+ [Flags]
public enum CameraViewMode
{
+ /// Unknown
+ /// Used for bitwise operations
+ NotDefined = 0,
/// The interior of a 2D cab
- Interior,
+ Interior = 2,
/// The interior of a 3D cab
- InteriorLookAhead,
+ InteriorLookAhead = 4,
/// An exterior camera attached to a train
- Exterior,
+ Exterior = 8,
/// A camera attached to the track
- Track,
+ Track = 16,
/// A fly-by camera attached to a point on the track
- FlyBy,
+ FlyBy = 32,
/// A fly-by zooming camera attached to a point on the track
- FlyByZooming
+ FlyByZooming = 64
}
}
diff --git a/source/OpenBveApi/System/FileSystem.cs b/source/OpenBveApi/System/FileSystem.cs
index 24f12e2243..04fdefe87f 100644
--- a/source/OpenBveApi/System/FileSystem.cs
+++ b/source/OpenBveApi/System/FileSystem.cs
@@ -56,6 +56,9 @@ public class FileSystem {
/// The Loksim3D data directory
public string LoksimDataDirectory;
+ /// The MSTS trainset directory
+ public string MSTSDirectory;
+
/// Any lines loaded from the filesystem.cfg which were not understood
internal string[] NotUnderstoodLines;
@@ -158,7 +161,7 @@ public void SaveCurrentFileSystemConfiguration()
{
string file = Path.CombineFile(SettingsFolder, "FileSystem.cfg");
StringBuilder newLines = new StringBuilder();
- newLines.AppendLine("Version=1");
+ newLines.AppendLine("Version=2");
try
{
if (File.Exists(file))
@@ -219,6 +222,11 @@ public void SaveCurrentFileSystemConfiguration()
{
newLines.AppendLine("LoksimPackageInstall=" + ReplacePath(LoksimPackageInstallationDirectory));
}
+ if (MSTSDirectory != null &&
+ Directory.Exists(OtherInstallationDirectory))
+ {
+ newLines.AppendLine("MSTSTrainset=" + ReplacePath(MSTSDirectory));
+ }
if (NotUnderstoodLines != null && NotUnderstoodLines.Length != 0)
{
for (int i = 0; i < NotUnderstoodLines.Length; i++)
@@ -350,14 +358,14 @@ private static FileSystem FromConfigurationFile(string file, HostInterface Host)
system.AppendToLogFile("WARNING: Invalid filesystem.cfg version detected.");
}
- if (v <= 1)
+ if (v <= 2)
{
//Silently upgrade to the current config version
- system.Version = 1;
+ system.Version = 2;
break;
}
- system.AppendToLogFile("WARNING: A newer filesystem.cfg version " + v + " was detected. The current version is 1.");
+ system.AppendToLogFile("WARNING: A newer filesystem.cfg version " + v + " was detected. The current version is 2.");
system.Version = v;
break;
@@ -417,6 +425,9 @@ private static FileSystem FromConfigurationFile(string file, HostInterface Host)
case "loksimpackageinstall":
system.LoksimPackageInstallationDirectory = GetAbsolutePath(value, true);
break;
+ case "mststrainset":
+ system.MSTSDirectory = GetAbsolutePath(value, true);
+ break;
default:
if (system.NotUnderstoodLines == null)
{
diff --git a/source/OpenBveApi/Train/Motor/EngineType.cs b/source/OpenBveApi/Train/Motor/EngineType.cs
new file mode 100644
index 0000000000..10417acae7
--- /dev/null
+++ b/source/OpenBveApi/Train/Motor/EngineType.cs
@@ -0,0 +1,41 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+namespace OpenBveApi.Motor
+{
+ /// Describes the different types of engine
+ public enum EngineType
+ {
+ /// No engine
+ NoEngine = 0,
+ /// Diesel prime mover, electric transmission
+ Diesel,
+ /// Diesel prime mover, hydralic transmission
+ DieselHydraulic,
+ /// Steam engine
+ Steam,
+ /// Pure electric engine
+ Electric
+ }
+}
diff --git a/source/OpenBveApi/Train/Motor/PantographState.cs b/source/OpenBveApi/Train/Motor/PantographState.cs
index f9ae1ac3c4..8df10e411f 100644
--- a/source/OpenBveApi/Train/Motor/PantographState.cs
+++ b/source/OpenBveApi/Train/Motor/PantographState.cs
@@ -27,10 +27,10 @@ namespace OpenBveApi.Motor
/// The possible states of a pantograph
public enum PantographState
{
- /// The pantograph is raised
- Raised,
/// The pantograph is lowered
Lowered,
+ /// The pantograph is raised
+ Raised,
/// The pantograph is raised, but no wire is present
Dewired
}
diff --git a/source/OpenBveApi/World/UnitConversions/Torque.cs b/source/OpenBveApi/World/UnitConversions/Torque.cs
index 913622a983..0d8223f99b 100644
--- a/source/OpenBveApi/World/UnitConversions/Torque.cs
+++ b/source/OpenBveApi/World/UnitConversions/Torque.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
//
@@ -31,6 +31,8 @@ public enum UnitOfTorque
{
/// Newton-meters per second
NewtonMetersPerSecond,
+ /// Kilo-newton-meters per second
+ KiloNewtonMetersPerSecond,
/// Foot pounds
FootPound
@@ -42,11 +44,12 @@ public class TorqueConverter : UnitConverter
static TorqueConverter()
{
BaseUnit = UnitOfTorque.NewtonMetersPerSecond;
- RegisterConversion(UnitOfTorque.FootPound, v => v * 0.7375621493, v => v / 1.3558179483);
- KnownUnits = new Dictionary
+ RegisterConversion(UnitOfTorque.KiloNewtonMetersPerSecond, v => v / 1000, v => v * 1000);
+ RegisterConversion(UnitOfTorque.FootPound, v => v * 0.7375621493, v => v / 1.3558179483);
+ KnownUnits = new Dictionary
{
// n.b. assume that torque in plain newtons is actually newton meters
- { "n/m/s", UnitOfTorque.NewtonMetersPerSecond }, { "nms", UnitOfTorque.NewtonMetersPerSecond }, { "newtonmeterspersecond", UnitOfTorque.NewtonMetersPerSecond }, { "n", UnitOfTorque.NewtonMetersPerSecond }, { "lb/ft", UnitOfTorque.FootPound }
+ {"n/m/s", UnitOfTorque.NewtonMetersPerSecond}, {"nms", UnitOfTorque.NewtonMetersPerSecond}, {"newtonmeterspersecond", UnitOfTorque.NewtonMetersPerSecond}, {"n", UnitOfTorque.NewtonMetersPerSecond}, {"knms", UnitOfTorque.KiloNewtonMetersPerSecond}, {"lb/ft", UnitOfTorque.FootPound}
};
}
diff --git a/source/Plugins/Train.MsTs/Effects/Exhaust.cs b/source/Plugins/Train.MsTs/Effects/Exhaust.cs
new file mode 100644
index 0000000000..eb2b499acc
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Effects/Exhaust.cs
@@ -0,0 +1,45 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBveApi.Math;
+
+namespace Train.MsTs
+{
+ /// Describes the properties of an exhaust animation for a MSTS model
+ internal struct Exhaust
+ {
+ /// The offset from the center of the model
+ internal Vector3 Offset;
+ /// The direction of the exhaust emissions
+ internal Vector3 Direction;
+ /// The size of the exhaust outlet (controls initial particle size)
+ internal double Size;
+ /// The maximum expanded size of a smoke particle
+ internal double SmokeMaxMagnitude;
+ /// The rate of particle emissions at idle
+ internal double SmokeInitialRate;
+ /// The rate of particle emissions at maximum power
+ internal double SmokeMaxRate;
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Handles/Handle.cs b/source/Plugins/Train.MsTs/Handles/Handle.cs
index 79cf20f144..7dc68553a6 100644
--- a/source/Plugins/Train.MsTs/Handles/Handle.cs
+++ b/source/Plugins/Train.MsTs/Handles/Handle.cs
@@ -1,4 +1,28 @@
-using System;
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
using OpenBve.Formats.MsTs;
using TrainManager.Handles;
using TrainManager.Trains;
@@ -17,41 +41,56 @@ internal partial class WagonParser
internal Tuple[] NotchDescriptions;
- internal AbstractHandle ParseHandle(Block block, TrainBase train)
+ internal AbstractHandle ParseHandle(Block block, TrainBase train, bool isPower)
{
HandleMinimum = (int)(block.ReadSingle() * 100);
HandleMaximum = (int)(block.ReadSingle() * 100);
HandleStep = (int)(block.ReadSingle() * 100);
HandleStartingPosition = (int)(block.ReadSingle() * 100);
-
- Block notchDescriptions = block.ReadSubBlock(KujuTokenID.NumNotches);
- ParseNotchDescriptionBlock(notchDescriptions);
- return new VariableHandle(train, NotchDescriptions);
+ // some handles seem to have extra numbers here, I believe ignored by the MSTS parser
+ Block notchDescriptions = block.GetSubBlock(KujuTokenID.NumNotches);
+ ParseNotchDescriptionBlock(notchDescriptions, isPower);
+ return new VariableHandle(train, isPower, NotchDescriptions);
}
- private void ParseNotchDescriptionBlock(Block block)
+ private void ParseNotchDescriptionBlock(Block block, bool isPower)
{
int numNotches = block.ReadInt32();
+ if (numNotches < 2)
+ {
+ // percentage based notch
+ NotchDescriptions = null;
+ return;
+ }
+
NotchDescriptions = new Tuple[numNotches];
for (int i = 0; i < numNotches; i++)
{
Block descriptionBlock = block.ReadSubBlock(KujuTokenID.Notch);
double notchPower = descriptionBlock.ReadSingle();
- descriptionBlock.ReadSingle(); // ??
- string notchDescription = descriptionBlock.ReadString();
- if (notchDescription.Equals("dummy", StringComparison.InvariantCultureIgnoreCase))
+ try
{
- if (i == 0)
+ descriptionBlock.ReadSingle(); // ??
+ string notchDescription = descriptionBlock.ReadString();
+ if (notchDescription.Equals("dummy", StringComparison.InvariantCultureIgnoreCase))
{
- notchDescription = "N";
- }
- else
- {
- notchDescription = "P" + i;
+ if (i == 0)
+ {
+ notchDescription = "N";
+ }
+ else
+ {
+ notchDescription = isPower ? "P" + i : "B" + i;
+ }
+
}
-
+ NotchDescriptions[i] = new Tuple(notchPower, notchDescription);
+ }
+ catch
+ {
+ // ignore
+ NotchDescriptions[i] = new Tuple(notchPower, i.ToString());
}
- NotchDescriptions[i] = new Tuple(notchPower, notchDescription);
}
}
}
diff --git a/source/Plugins/Train.MsTs/Misc/Units.cs b/source/Plugins/Train.MsTs/Misc/Units.cs
new file mode 100644
index 0000000000..5900a81e8c
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Misc/Units.cs
@@ -0,0 +1,26 @@
+// ReSharper disable UnusedMember.Global
+// ReSharper disable InconsistentNaming
+namespace Train.MsTs
+{
+ /// Units encountered in a MSTS CVF
+ internal enum Units
+ {
+ Unknown = 0,
+ Milliamps,
+ Amps,
+ Volts,
+ Kilovolts,
+ Gallons,
+ Inches_Of_Mercury,
+ Kilometers_Per_Hour,
+ Km_Per_Hour = Kilometers_Per_Hour,
+ Miles_Per_Hour,
+ Miles_Hour_Min,
+ Meters_Sec,
+ PSI,
+ Kilo_Lbs,
+ Kilopascals,
+ Bar,
+ Kgs_Per_Square_Cm
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Panel/CabComponent.cs b/source/Plugins/Train.MsTs/Panel/CabComponent.cs
index 8d034ed5a5..2555c082af 100644
--- a/source/Plugins/Train.MsTs/Panel/CabComponent.cs
+++ b/source/Plugins/Train.MsTs/Panel/CabComponent.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
//
@@ -57,15 +57,17 @@ internal class CabComponent
private int LeadingZeros;
private FrameMapping[] FrameMappings = new FrameMapping[0];
private readonly Vector3 PanelPosition;
-
+ private CabComponentStyle Style;
private Tuple[] PositiveColors;
private Tuple[] NegativeColors;
+ private Color24 ControlColor;
+ private int Accuracy;
internal void Parse()
{
if (!Enum.TryParse(myBlock.Token.ToString(), true, out Type))
{
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised CabViewComponent type.");
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS CVF Parser: Unrecognised CabViewComponent type.");
return;
}
@@ -85,60 +87,65 @@ internal void Parse()
}
}
- internal void Create(ref CarBase Car, int Layer)
+ internal void Create(ref CarBase currentCar, int componentLayer)
{
- if (File.Exists(TexturePath) || Type == CabComponentType.Digital)
+ if (!File.Exists(TexturePath) && Type != CabComponentType.Digital && Type != CabComponentType.DigitalClock)
+ {
+ return;
+ }
+ if (FrameMappings.Length < 2 && TotalFrames > 1)
{
- if (FrameMappings.Length == 0 && TotalFrames > 1)
+ // e.g. Acela power handle has 25 frames for total power value of 100% but no mappings specified
+ FrameMappings = new FrameMapping[TotalFrames];
+ // frame 0 is always mapping value 0
+ for (int i = 1; i < TotalFrames; i++)
{
- // e.g. Acela power handle has 25 frames for total power value of 100% but no mappings specified
- FrameMappings = new FrameMapping[TotalFrames];
- // frame 0 is always mapping value 0
- for (int i = 1; i < TotalFrames; i++)
- {
- FrameMappings[i].MappingValue = (double)i / TotalFrames;
- FrameMappings[i].FrameKey = i;
- }
-
+ FrameMappings[i].MappingValue = (double)i / TotalFrames;
+ FrameMappings[i].FrameKey = i;
}
- //Create element
- double rW = 1024.0 / 640.0;
- double rH = 768.0 / 480.0;
- int wday, hday;
- int j;
- string f;
- CultureInfo Culture = CultureInfo.InvariantCulture;
- switch (Type)
- {
- case CabComponentType.Dial:
- Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(null, null), out Texture tday, true);
- // correct angle position if appropriate
- if (!DirIncrease && InitialAngle > LastAngle)
- {
- InitialAngle = -(365 - InitialAngle);
- }
+ }
- //Get final position from the 640px panel (Yuck...)
- Position.X *= rW;
- Position.Y *= rH;
- Size.X *= rW;
- Size.Y *= rH;
- PivotPoint *= rH;
- j = CabviewFileParser.CreateElement(ref Car.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2((0.5 * Size.X) / (tday.Width * rW), PivotPoint / (tday.Height * rH)), Layer * CabviewFileParser.StackDistance, PanelPosition, tday, null, new Color32(255, 255, 255, 255));
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateXDirection = DirIncrease ? new Vector3(1.0, 0.0, 0.0) : new Vector3(-1.0, 0.0, 0.0);
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateYDirection = Vector3.Cross(Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZDirection, Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateXDirection);
- f = CabviewFileParser.GetStackLanguageFromSubject(Car.baseTrain, panelSubject, Units);
- InitialAngle = InitialAngle.ToRadians();
- LastAngle = LastAngle.ToRadians();
- double a0 = (InitialAngle * Maximum - LastAngle * Minimum) / (Maximum - Minimum);
- double a1 = (LastAngle - InitialAngle) / (Maximum - Minimum);
- f += " " + a1.ToString(Culture) + " * " + a0.ToString(Culture) + " +";
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZFunction = new FunctionScript(Plugin.CurrentHost, f, false);
- break;
- case CabComponentType.Lever:
- /*
+ //Create element
+ const double rW = 1024.0 / 640.0;
+ const double rH = 768.0 / 480.0;
+ int wday, hday;
+ int elementIndex;
+ string f;
+ CultureInfo culture = CultureInfo.InvariantCulture;
+ switch (Type)
+ {
+ case CabComponentType.Dial:
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(null, null), out Texture tday, true);
+ // correct angle position if appropriate
+ if (!DirIncrease && InitialAngle > LastAngle)
+ {
+ InitialAngle = -(365 - InitialAngle);
+ }
+
+ //Get final position from the 640px panel (Yuck...)
+ Position.X *= rW;
+ Position.Y *= rH;
+ Size.X *= rW;
+ Size.Y *= rH;
+ PivotPoint *= rH;
+ elementIndex = CabviewFileParser.CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2((0.5 * Size.X) / (tday.Width * rW), PivotPoint / (tday.Height * rH)), componentLayer * CabviewFileParser.StackDistance, PanelPosition, tday, null, new Color32(255, 255, 255, 255));
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateXDirection = DirIncrease ? new Vector3(1.0, 0.0, 0.0) : new Vector3(-1.0, 0.0, 0.0);
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateYDirection = Vector3.Cross(currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateZDirection, currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateXDirection);
+ f = CabviewFileParser.GetStackLanguageFromSubject(currentCar.baseTrain, panelSubject, Units);
+ InitialAngle = InitialAngle.ToRadians();
+ LastAngle = LastAngle.ToRadians();
+ double a0 = (InitialAngle * Maximum - LastAngle * Minimum) / (Maximum - Minimum);
+ double a1 = (LastAngle - InitialAngle) / (Maximum - Minimum);
+ f += " " + a1.ToString(culture) + " * " + a0.ToString(culture) + " +";
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateZFunction = new FunctionScript(Plugin.CurrentHost, f, false);
+ // backstop by default e.g. ammeter when using dynamic brakes
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateZFunction.Minimum = InitialAngle;
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].RotateZFunction.Maximum = LastAngle;
+ break;
+ case CabComponentType.Lever:
+ /*
* TODO:
* Need to revisit the actual position versus frame with MSTS content.
*
@@ -149,211 +156,246 @@ internal void Create(ref CarBase Car, int Layer)
* Oddly, all frames appear to be distinct. Need to check OR + MSTS handling
* Suspect there's a notch delay or something that should use these.
*/
- Position.X *= rW;
- Position.Y *= rH;
- Size.X *= rW;
- Size.Y *= rH;
- Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
- if (wday > 0 & hday > 0)
+ Position.X *= rW;
+ Position.Y *= rH;
+ Size.X *= rW;
+ Size.Y *= rH;
+ Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
+ if (wday > 0 & hday > 0)
+ {
+ Texture[] textures = new Texture[TotalFrames];
+ int row = 0;
+ int column = 0;
+ int frameWidth = wday / HorizontalFrames;
+ int frameHeight = hday / VerticalFrames;
+ for (int k = 0; k < TotalFrames; k++)
{
- Texture[] textures = new Texture[TotalFrames];
- int row = 0;
- int column = 0;
- int frameWidth = wday / HorizontalFrames;
- int frameHeight = hday / VerticalFrames;
- for (int k = 0; k < TotalFrames; k++)
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(column * frameWidth, row * frameHeight, frameWidth, frameHeight), null), out textures[k]);
+ if (column < HorizontalFrames - 1)
{
- Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(column * frameWidth, row * frameHeight, frameWidth, frameHeight), null), out textures[k]);
- if (column < HorizontalFrames - 1)
- {
- column++;
- }
- else
- {
- column = 0;
- row++;
- }
+ column++;
}
-
- j = -1;
- for (int k = 0; k < textures.Length; k++)
+ else
{
-
- int l = CabviewFileParser.CreateElement(ref Car.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2(0.5, 0.5), Layer * CabviewFileParser.StackDistance, PanelPosition, textures[k], null, new Color32(255, 255, 255, 255), k != 0);
- if (k == 0) j = l;
- }
-
- f = CabviewFileParser.GetStackLanguageFromSubject(Car.baseTrain, panelSubject, Units);
- switch (panelSubject)
- {
- case PanelSubject.Throttle:
- case PanelSubject.Train_Brake:
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].StateFunction = new CvfAnimation(panelSubject, FrameMappings);
- break;
- default:
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].StateFunction = new FunctionScript(Plugin.CurrentHost, f, false);
- break;
+ column = 0;
+ row++;
}
+ }
+ elementIndex = -1;
+ for (int k = 0; k < textures.Length; k++)
+ {
+
+ int l = CabviewFileParser.CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2(0.5, 0.5), componentLayer * CabviewFileParser.StackDistance, PanelPosition, textures[k], null, new Color32(255, 255, 255, 255), k != 0);
+ if (k == 0) elementIndex = l;
}
- break;
- case CabComponentType.TriState:
- case CabComponentType.TwoState:
- case CabComponentType.MultiStateDisplay:
- Position.X *= rW;
- Position.Y *= rH;
- Size.X *= rW;
- Size.Y *= rH;
- Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
- if (wday > 0 & hday > 0)
+ f = CabviewFileParser.GetStackLanguageFromSubject(currentCar.baseTrain, panelSubject, Units);
+ switch (panelSubject)
{
- Texture[] textures = new Texture[TotalFrames];
- int row = 0;
- int column = 0;
- int frameWidth = wday / HorizontalFrames;
- int frameHeight = hday / VerticalFrames;
- for (int k = 0; k < TotalFrames; k++)
- {
- Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(column * frameWidth, row * frameHeight, frameWidth, frameHeight), null), out textures[k]);
- if (column < HorizontalFrames - 1)
- {
- column++;
- }
- else
- {
- column = 0;
- row++;
- }
- }
+ case PanelSubject.Engine_Brake:
+ case PanelSubject.Throttle:
+ case PanelSubject.Train_Brake:
+ case PanelSubject.Gears:
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new CvfAnimation(Plugin.CurrentHost, panelSubject, FrameMappings);
+ break;
+ default:
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new FunctionScript(Plugin.CurrentHost, f, false);
+ break;
+ }
- j = -1;
- for (int k = 0; k < textures.Length; k++)
+ }
+
+ break;
+ case CabComponentType.TriState:
+ case CabComponentType.TwoState:
+ case CabComponentType.MultiStateDisplay:
+ case CabComponentType.CombinedControl:
+ Position.X *= rW;
+ Position.Y *= rH;
+ Size.X *= rW;
+ Size.Y *= rH;
+ Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
+ if (wday > 0 & hday > 0)
+ {
+ Texture[] textures = new Texture[TotalFrames];
+ int row = 0;
+ int column = 0;
+ int frameWidth = wday / HorizontalFrames;
+ int frameHeight = hday / VerticalFrames;
+ for (int k = 0; k < TotalFrames; k++)
+ {
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(column * frameWidth, row * frameHeight, frameWidth, frameHeight), null), out textures[k]);
+ if (column < HorizontalFrames - 1)
{
- int l = CabviewFileParser.CreateElement(ref Car.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2(0.5, 0.5), Layer * CabviewFileParser.StackDistance, PanelPosition, textures[k], null, new Color32(255, 255, 255, 255), k != 0);
- if (k == 0) j = l;
+ column++;
}
-
- f = CabviewFileParser.GetStackLanguageFromSubject(Car.baseTrain, panelSubject, Units);
- switch (panelSubject)
+ else
{
- case PanelSubject.Direction:
- case PanelSubject.Direction_Display:
- case PanelSubject.Overspeed:
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].StateFunction = new CvfAnimation(panelSubject, FrameMappings);
- break;
- default:
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].StateFunction = new FunctionScript(Plugin.CurrentHost, f, false);
- break;
+ column = 0;
+ row++;
}
+ }
-
+ elementIndex = -1;
+ for (int k = 0; k < textures.Length; k++)
+ {
+ int l = CabviewFileParser.CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2(0.5, 0.5), componentLayer * CabviewFileParser.StackDistance, PanelPosition, textures[k], null, new Color32(255, 255, 255, 255), k != 0);
+ if (k == 0) elementIndex = l;
}
- break;
- case CabComponentType.Digital:
- if (panelSubject != PanelSubject.Speedometer && panelSubject != PanelSubject.Speedlim_Display)
+ f = CabviewFileParser.GetStackLanguageFromSubject(currentCar.baseTrain, panelSubject, Units);
+ switch (panelSubject)
{
- break;
+ case PanelSubject.Direction:
+ case PanelSubject.Direction_Display:
+ case PanelSubject.Overspeed:
+ case PanelSubject.Sanders:
+ case PanelSubject.Sanding:
+ case PanelSubject.Wheelslip:
+ case PanelSubject.Alerter_Display:
+ case PanelSubject.Penalty_App:
+ case PanelSubject.Throttle_Display:
+ case PanelSubject.CP_Handle:
+ case PanelSubject.CPH_Display:
+ case PanelSubject.Friction_Braking:
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new CvfAnimation(Plugin.CurrentHost, panelSubject, FrameMappings);
+ break;
+ default:
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new FunctionScript(Plugin.CurrentHost, f, false);
+ break;
}
- Position.X *= rW;
- Position.Y *= rH;
- Color24 textColor = PositiveColors[0].Item2;
+ }
+
+ break;
+ case CabComponentType.Digital:
+ Position.X *= rW;
+ Position.Y *= rH;
+
+ Color24 textColor = PositiveColors[0].Item2;
+
+ Texture[] frameTextures = new Texture[11];
+ TexturePath = OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(Plugin.FileSystem.DataFolder, "Compatibility"), "numbers.png"); // arial 9.5pt
+ Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
+
+ for (int i = 0; i < 10; i++)
+ {
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(0, i * 24, 16, 24), null), out frameTextures[i], true);
+ }
+
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(0, 0, 16, 24), null), out frameTextures[10], true); // repeated zero [check vice MSTS]
- Texture[] frameTextures = new Texture[11];
- TexturePath = OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(Plugin.FileSystem.DataFolder, "Compatibility"), "numbers.png"); // arial 9.5pt
- Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
+ int numMaxDigits = (int)Math.Floor(Math.Log10(Maximum) + 1);
+ int numMinDigits = (int)Math.Floor(Math.Log10(Minimum) + 1);
- for (int i = 0; i < 10; i++)
+ int totalDigits = Math.Max(numMinDigits, numMaxDigits) + LeadingZeros;
+ elementIndex = -1;
+ double digitWidth = Size.X / totalDigits;
+ for (int currentDigit = 0; currentDigit < totalDigits; currentDigit++)
+ {
+ for (int k = 0; k < frameTextures.Length; k++)
{
- Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(0, i * 24, 16, 24), null), out frameTextures[i], true);
+ int l = CabviewFileParser.CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], new Vector2(Position.X + Size.X - (digitWidth * (currentDigit + 1)), Position.Y), new Vector2(digitWidth * rW, Size.Y * rH), new Vector2(0.5, 0.5), componentLayer * CabviewFileParser.StackDistance, PanelPosition, frameTextures[k], null, textColor, k != 0);
+ if (k == 0) elementIndex = l;
}
- Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(0, 0, 16, 24), null), out frameTextures[10], true); // repeated zero [check vice MSTS]
-
- int numMaxDigits = (int)Math.Floor(Math.Log10(Maximum) + 1);
- int numMinDigits = (int)Math.Floor(Math.Log10(Minimum) + 1);
+ // build color arrays and mappings
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].Colors = new Color24[NegativeColors.Length + PositiveColors.Length];
+ FrameMappings = new FrameMapping[PositiveColors.Length + NegativeColors.Length];
+ for (int i = 0; i < NegativeColors.Length; i++)
+ {
+ FrameMappings[i].MappingValue = NegativeColors[i].Item1;
+ FrameMappings[i].FrameKey = i;
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].Colors[i] = NegativeColors[i].Item2;
+ }
- int totalDigits = Math.Max(numMinDigits, numMaxDigits) + LeadingZeros;
- j = -1;
- double digitWidth = Size.X / totalDigits;
- for (int currentDigit = 0; currentDigit < totalDigits; currentDigit++)
+ for (int i = 0; i < PositiveColors.Length; i++)
{
- for (int k = 0; k < frameTextures.Length; k++)
- {
- int l = CabviewFileParser.CreateElement(ref Car.CarSections[CarSectionType.Interior].Groups[0], new Vector2(Position.X + Size.X - (digitWidth * (currentDigit + 1)), Position.Y), new Vector2(digitWidth * rW, Size.Y * rH), new Vector2(0.5, 0.5), Layer * CabviewFileParser.StackDistance, PanelPosition, frameTextures[k], null, textColor, k != 0);
- if (k == 0) j = l;
- }
+ FrameMappings[i + NegativeColors.Length].MappingValue = PositiveColors[i].Item1;
+ FrameMappings[i + NegativeColors.Length].FrameKey = i + NegativeColors.Length;
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].Colors[i + NegativeColors.Length] = PositiveColors[i].Item2;
+ }
- // build color arrays and mappings
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].Colors = new Color24[NegativeColors.Length + PositiveColors.Length];
- FrameMappings = new FrameMapping[PositiveColors.Length + NegativeColors.Length];
- for (int i = 0; i < NegativeColors.Length; i++)
+ // create color and digit functions
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new CvfAnimation(Plugin.CurrentHost, panelSubject, Units, currentDigit);
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].ColorFunction = new CvfAnimation(Plugin.CurrentHost, panelSubject, Units, FrameMappings);
+ }
+
+ break;
+ case CabComponentType.CabSignalDisplay:
+ TotalFrames = 8;
+ HorizontalFrames = 4;
+ VerticalFrames = 2;
+ Position.X *= rW;
+ Position.Y *= rH;
+ Size.X *= rW;
+ Size.Y *= rH;
+ Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
+ if (wday > 0 & hday > 0)
+ {
+ Texture[] textures = new Texture[8];
+ // 4 h-frames, 2 v-frames
+ int row = 0;
+ int column = 0;
+ int frameWidth = wday / HorizontalFrames;
+ int frameHeight = hday / VerticalFrames;
+ for (int k = 0; k < TotalFrames; k++)
+ {
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(column * frameWidth, row * frameHeight, frameWidth, frameHeight), null), out textures[k]);
+ if (column < HorizontalFrames - 1)
{
- FrameMappings[i].MappingValue = NegativeColors[i].Item1;
- FrameMappings[i].FrameKey = i;
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].Colors[i] = NegativeColors[i].Item2;
+ column++;
}
-
- for (int i = 0; i < PositiveColors.Length; i++)
+ else
{
- FrameMappings[i + NegativeColors.Length].MappingValue = PositiveColors[i].Item1;
- FrameMappings[i + NegativeColors.Length].FrameKey = i + NegativeColors.Length;
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].Colors[i + NegativeColors.Length] = PositiveColors[i].Item2;
+ column = 0;
+ row++;
}
-
- // create color and digit functions
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].StateFunction = new CvfAnimation(panelSubject, Units, currentDigit);
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].ColorFunction = new CvfAnimation(panelSubject, Units, FrameMappings);
}
- break;
- case CabComponentType.CabSignalDisplay:
- TotalFrames = 8;
- HorizontalFrames = 4;
- VerticalFrames = 2;
- Position.X *= rW;
- Position.Y *= rH;
- Size.X *= rW;
- Size.Y *= rH;
- Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
- if (wday > 0 & hday > 0)
+ elementIndex = -1;
+ for (int k = 0; k < textures.Length; k++)
{
- Texture[] textures = new Texture[8];
- // 4 h-frames, 2 v-frames
- int row = 0;
- int column = 0;
- int frameWidth = wday / HorizontalFrames;
- int frameHeight = hday / VerticalFrames;
- for (int k = 0; k < TotalFrames; k++)
- {
- Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(column * frameWidth, row * frameHeight, frameWidth, frameHeight), null), out textures[k]);
- if (column < HorizontalFrames - 1)
- {
- column++;
- }
- else
- {
- column = 0;
- row++;
- }
- }
+ int l = CabviewFileParser.CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2(0.5, 0.5), componentLayer * CabviewFileParser.StackDistance, PanelPosition, textures[k], null, new Color32(255, 255, 255, 255), k != 0);
+ if (k == 0) elementIndex = l;
+ }
- j = -1;
- for (int k = 0; k < textures.Length; k++)
- {
- int l = CabviewFileParser.CreateElement(ref Car.CarSections[CarSectionType.Interior].Groups[0], Position, Size, new Vector2(0.5, 0.5), Layer * CabviewFileParser.StackDistance, PanelPosition, textures[k], null, new Color32(255, 255, 255, 255), k != 0);
- if (k == 0) j = l;
- }
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new CvfAnimation(Plugin.CurrentHost, panelSubject);
- Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].StateFunction = new CvfAnimation(panelSubject);
+ }
+ break;
+ case CabComponentType.DigitalClock:
+ Position.X *= rW;
+ Position.Y *= rH;
+ totalDigits = Accuracy == 1 ? 8 : 5; // with or without secs
+ elementIndex = -1;
+ digitWidth = Size.X / totalDigits;
+ textColor = ControlColor;
+
+ frameTextures = new Texture[12];
+ TexturePath = OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(Plugin.FileSystem.DataFolder, "Compatibility"), "numbers.png"); // arial 9.5pt
+ Plugin.CurrentHost.QueryTextureDimensions(TexturePath, out wday, out hday);
+
+ for (int i = 0; i < 10; i++)
+ {
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(0, i * 24, 16, 24), null), out frameTextures[i], true);
+ }
+ Plugin.CurrentHost.RegisterTexture(TexturePath, new TextureParameters(new TextureClipRegion(0, 240, 16, 16), null), out frameTextures[11], true);
+ for (int currentDigit = 0; currentDigit < totalDigits; currentDigit++)
+ {
+ for (int k = 0; k < frameTextures.Length; k++)
+ {
+ int l = CabviewFileParser.CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], new Vector2(Position.X + Size.X - (digitWidth * (currentDigit + 1)), Position.Y), new Vector2(digitWidth * rW, Size.Y * rH), new Vector2(0.5, 0.5), componentLayer * CabviewFileParser.StackDistance, PanelPosition, frameTextures[k], null, textColor, k != 0);
+ if (k == 0) elementIndex = l;
}
- break;
- }
+ // create digit functions
+ currentCar.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new CvfAnimation(Plugin.CurrentHost, panelSubject, Style, Accuracy == 1 ? currentDigit : currentDigit + 3);
+ }
+ break;
}
}
@@ -380,10 +422,27 @@ private void ReadSubBlock(Block block)
TotalFrames = block.ReadInt16();
HorizontalFrames = block.ReadInt16();
VerticalFrames = block.ReadInt16();
+ FrameMappings = new FrameMapping[TotalFrames];
+ for (int i = 0; i < TotalFrames; i++)
+ {
+ FrameMappings[i].FrameKey = i;
+ var stateBlock = block.ReadSubBlock(KujuTokenID.State);
+ while (stateBlock.Length() - stateBlock.Position() > 3)
+ {
+ Block subBlock = stateBlock.ReadSubBlock(new[] { KujuTokenID.Style, KujuTokenID.SwitchVal });
+ if (subBlock.Token == KujuTokenID.SwitchVal)
+ {
+ FrameMappings[i].MappingValue = subBlock.ReadSingle();
+ break;
+ }
+ }
+
+
+ }
break;
case KujuTokenID.DirIncrease:
// rotates Clockwise (0) or AntiClockwise (1)
- DirIncrease = block.ReadInt16() == 1;
+ DirIncrease = block.ReadBool();
break;
case KujuTokenID.Orientation:
//Flip?
@@ -416,14 +475,33 @@ private void ReadSubBlock(Block block)
VerticalFrames = block.ReadInt16();
break;
case KujuTokenID.MouseControl:
- MouseControl = block.ReadInt16() == 1;
+ MouseControl = block.ReadBool();
break;
case KujuTokenID.Style:
- block.Skip((int)block.Length());
+ Style = block.ReadEnumValue(default(CabComponentStyle));
break;
case KujuTokenID.Graphic:
string s = block.ReadString();
- TexturePath = OpenBveApi.Path.CombineFile(CabviewFileParser.CurrentFolder, s);
+ if (!string.IsNullOrEmpty(s))
+ {
+ try
+ {
+ TexturePath = OpenBveApi.Path.CombineFile(CabviewFileParser.CurrentFolder, s);
+ }
+ catch
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS CVF Parser: The texture path contains invalid characters in CabComponent " + Type);
+ }
+
+ if (!File.Exists(TexturePath))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS CVF Parser: The texture file " + s + " was not found in CabComponent " + Type);
+ }
+ }
+ else
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS CVF Parser: A texture file was not specified in CabComponent " + Type);
+ }
break;
case KujuTokenID.Position:
Position.X = block.ReadSingle();
@@ -501,7 +579,12 @@ private void ReadSubBlock(Block block)
}
}
}
-
+ break;
+ case KujuTokenID.ControlColour:
+ ControlColor = new Color24((byte)block.ReadInt16(), (byte)block.ReadInt16(), (byte)block.ReadInt16());
+ break;
+ case KujuTokenID.Accuracy:
+ Accuracy = block.ReadInt16();
break;
}
}
diff --git a/source/Plugins/Train.MsTs/Panel/CvfAnimation.cs b/source/Plugins/Train.MsTs/Panel/CvfAnimation.cs
new file mode 100644
index 0000000000..84e80f143e
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Panel/CvfAnimation.cs
@@ -0,0 +1,491 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBveApi.FunctionScripting;
+using OpenBveApi.Math;
+using OpenBveApi.Motor;
+using OpenBveApi.Trains;
+using System;
+using System.Collections.Generic;
+using OpenBveApi;
+using TrainManager.Car.Systems;
+using TrainManager.Motor;
+using OpenBveApi.Hosts;
+using TrainManager.SafetySystems;
+
+namespace Train.MsTs
+{
+ /// Animation class handling CVF elements with keyframe mappings
+ internal class CvfAnimation : AnimationScript
+ {
+ internal readonly HostInterface CurrentHost;
+
+ internal readonly PanelSubject Subject;
+
+ internal readonly FrameMapping[] FrameMapping;
+
+ internal readonly int Digit;
+
+ internal readonly double UnitConversionFactor;
+
+ private double lastResult;
+
+ internal CvfAnimation(HostInterface host, PanelSubject subject)
+ {
+ CurrentHost = host;
+ Subject = subject;
+ switch (subject)
+ {
+ case PanelSubject.Aspect_Display:
+ Minimum = 0;
+ Maximum = 7;
+ break;
+ default:
+ Minimum = 0;
+ Maximum = double.MaxValue;
+ break;
+ }
+ Digit = -1;
+ }
+
+ internal CvfAnimation(HostInterface host, PanelSubject subject, FrameMapping[] frameMapping)
+ {
+ CurrentHost = host;
+ Subject = subject;
+ FrameMapping = frameMapping;
+ Minimum = 0;
+ Maximum = FrameMapping.Length;
+ Digit = -1;
+ }
+
+ internal CvfAnimation(HostInterface host, PanelSubject subject, Units unit, int digit)
+ {
+ CurrentHost = host;
+ Subject = subject;
+ switch (unit)
+ {
+ case Units.Miles_Per_Hour:
+ UnitConversionFactor = 2.2369362920544;
+ break;
+ case Units.Kilometers_Per_Hour:
+ UnitConversionFactor = 3.6;
+ break;
+ case Units.PSI:
+ UnitConversionFactor = 0.000145038;
+ break;
+ }
+ Digit = digit;
+ }
+
+ internal CvfAnimation(HostInterface host, PanelSubject subject, Units unit, FrameMapping[] frameMapping)
+ {
+ CurrentHost = host;
+ Subject = subject;
+ switch (unit)
+ {
+ case Units.Miles_Per_Hour:
+ UnitConversionFactor = 2.2369362920544;
+ break;
+ case Units.Kilometers_Per_Hour:
+ UnitConversionFactor = 3.6;
+ break;
+ }
+
+ Digit = -1;
+ FrameMapping = frameMapping;
+ }
+
+ internal CvfAnimation(HostInterface host, PanelSubject subject, CabComponentStyle style, int digit)
+ {
+ CurrentHost = host;
+ Subject = subject;
+ Digit = digit;
+ switch (style)
+ {
+ case CabComponentStyle.TwelveHour:
+ UnitConversionFactor = 1;
+ break;
+ case CabComponentStyle.TwentyFourHour:
+ UnitConversionFactor = 0;
+ break;
+ }
+ }
+
+ public double ExecuteScript(AbstractTrain train, int carIndex, Vector3 position, double trackPosition, int sectionIndex, bool isPartOfTrain, double timeElapsed, int currentState)
+ {
+ dynamic dynamicTrain = train;
+ switch (Subject)
+ {
+ case PanelSubject.CP_Handle:
+ case PanelSubject.CPH_Display:
+ // NOTE: 0.5 mapping == N
+ double mapping = 0.5;
+ if (dynamicTrain.Handles.Brake.Actual > 0)
+ {
+ mapping += (double)dynamicTrain.Handles.Brake.Actual / dynamicTrain.Handles.Brake.MaximumNotch * 0.5;
+ }
+ else
+ {
+ mapping -= (double)dynamicTrain.Handles.Power.Actual / dynamicTrain.Handles.Power.MaximumNotch * 0.5;
+ }
+ MapResult(mapping);
+ break;
+ case PanelSubject.Throttle_Display:
+ case PanelSubject.Throttle:
+ MapResult((double)dynamicTrain.Handles.Power.Actual / dynamicTrain.Handles.Power.MaximumNotch);
+ break;
+ case PanelSubject.Train_Brake:
+ MapResult((double)dynamicTrain.Handles.Brake.Actual / dynamicTrain.Handles.Brake.MaximumNotch);
+ break;
+ case PanelSubject.Friction_Braking:
+ // NOTE: Assumed at the minute this goes out at speed zero
+ bool isBraking = Math.Abs(train.CurrentSpeed) > 0 && (dynamicTrain.Handles.Brake.Actual > 0 || (dynamicTrain.Handles.HasLocoBrake && dynamicTrain.Handles.LocoBrake.Actual > 0));
+ MapResult(isBraking ? 1 : 0);
+ break;
+ case PanelSubject.Direction_Display:
+ case PanelSubject.Direction:
+ lastResult = (int)dynamicTrain.Handles.Reverser.Actual + 1;
+ break;
+ case PanelSubject.Speedlim_Display:
+ double speedLim = Math.Min(train.CurrentRouteLimit, train.CurrentSectionLimit) * UnitConversionFactor;
+ if (Digit == -1)
+ {
+ // color
+ for (int i = 0; i < FrameMapping.Length; i++)
+ {
+ if (FrameMapping[i].MappingValue <= speedLim)
+ {
+ lastResult = FrameMapping[i].FrameKey;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // digit
+ if (speedLim == double.PositiveInfinity)
+ {
+ lastResult = -1; // cheat to hide
+ }
+ else
+ {
+ lastResult = (int)(speedLim / (int)Math.Pow(10, Digit) % 10);
+ }
+ }
+ break;
+ case PanelSubject.Speedometer:
+ double currentSpeed = Math.Abs(train.CurrentSpeed) * UnitConversionFactor;
+ MapDigitalResult(currentSpeed);
+ break;
+ case PanelSubject.Aspect_Display:
+ lastResult = train.CurrentSignalAspect;
+ break;
+ case PanelSubject.Overspeed:
+ double currentLimit = Math.Min(train.CurrentRouteLimit, train.CurrentSectionLimit);
+ lastResult = Math.Abs(train.CurrentSpeed) > currentLimit ? 1 : 0;
+ break;
+ case PanelSubject.Front_Hlight:
+ lastResult = dynamicTrain.SafetySystems.Headlights.CurrentState;
+ break;
+ case PanelSubject.Pantograph:
+ case PanelSubject.Panto_Display:
+ int pantographState = 0;
+ for (int k = 0; k < dynamicTrain.Cars.Length; k++)
+ {
+ if (dynamicTrain.Cars[k].TractionModel is ElectricEngine electricEngine &&
+ electricEngine.Components.TryGetTypedValue(EngineComponent.Pantograph, out Pantograph pantograph))
+ {
+ pantographState = (int)pantograph.State;
+ break;
+ }
+ }
+ lastResult = pantographState;
+ break;
+ case PanelSubject.Gears:
+ int gearState = 0;
+ for (int k = 0; k < dynamicTrain.Cars.Length; k++)
+ {
+ if (dynamicTrain.Cars[k].TractionModel is DieselEngine dieselEngine &&
+ dieselEngine.Components.TryGetTypedValue(EngineComponent.Gearbox, out Gearbox gearbox))
+ {
+ gearState = gearbox.CurrentGear;
+ break;
+ }
+ }
+ lastResult = gearState;
+ break;
+ case PanelSubject.Sanders:
+ // sanders button is pressed
+ int sandState = 0;
+ for (int k = 0; k < dynamicTrain.Cars.Length; k++)
+ {
+ if (dynamicTrain.Cars[k].ReAdhesionDevice is Sanders sanders)
+ {
+ sandState = sanders.State >= SandersState.Active ? 1 :0;
+ break;
+ }
+ }
+ lastResult = sandState;
+ break;
+ case PanelSubject.Sanding:
+ // sand is actually being dispensed / doing something
+ sandState = 0;
+ for (int k = 0; k < dynamicTrain.Cars.Length; k++)
+ {
+ if (dynamicTrain.Cars[k].ReAdhesionDevice is Sanders sanders && train.CurrentSpeed <= sanders.MaximumSpeed)
+ {
+ sandState = sanders.State == SandersState.Active ? 1 : 0;
+ break;
+ }
+ }
+ lastResult = sandState;
+ break;
+ case PanelSubject.Engine_Brake:
+ if (!dynamicTrain.Handles.HasLocoBrake)
+ {
+ lastResult = 0;
+ break;
+ }
+ for (int i = 0; i < FrameMapping.Length; i++)
+ {
+ if (FrameMapping[i].MappingValue >= (double)dynamicTrain.Handles.LocoBrake.Actual / dynamicTrain.Handles.LocoBrake.MaximumNotch)
+ {
+ lastResult = FrameMapping[i].FrameKey;
+ break;
+ }
+ }
+ break;
+ case PanelSubject.Wheelslip:
+ int wheelSlip = 0;
+ for (int k = 0; k < dynamicTrain.Cars.Length; k++)
+ {
+ if (dynamicTrain.Cars[k].FrontAxle.CurrentWheelSlip || dynamicTrain.Cars[k].RearAxle.CurrentWheelSlip)
+ {
+ wheelSlip = 1;
+ break;
+ }
+ }
+ lastResult = wheelSlip;
+ break;
+ case PanelSubject.Clock:
+ double hour = Math.Floor(CurrentHost.InGameTime / 3600.0);
+ hour %= 24;
+ if (UnitConversionFactor == 1)
+ {
+ if (hour > 12)
+ {
+ hour -= 12;
+ }
+ }
+ double min = Math.Floor(CurrentHost.InGameTime / 60 % 60);
+ double sec = CurrentHost.InGameTime % 60;
+ switch (Digit)
+ {
+ case 7:
+ // H
+ lastResult = hour >= 10 ? (int)(hour / 10) : 0;
+ break;
+ case 6:
+ // HH
+ lastResult = (int)(hour % 10);
+ break;
+ case 5:
+ // HH:
+ lastResult = 11;
+ break;
+ case 4:
+ // HH:M
+ lastResult = min >= 10 ? (int)(min / 10) : 0;
+ break;
+ case 3:
+ // HH:MM
+ lastResult = (int)(min % 10);
+ break;
+ case 2:
+ // HH:MM:
+ lastResult = 11;
+ break;
+ case 1:
+ // HH:MM:S
+ lastResult = sec >= 10 ? (int)(sec / 10) : 0;
+ break;
+ case 0:
+ // HH:MM:SS
+ lastResult = (int)(sec % 10);
+ break;
+ }
+ break;
+ case PanelSubject.Alerter_Display:
+ // can't use an extension on a dynamic directly, have to get to known type first
+ Dictionary safetySystems = dynamicTrain.Cars[dynamicTrain.DriverCar].SafetySystems;
+ if (safetySystems.TryGetTypedValue(SafetySystem.DriverSupervisionDevice, out DriverSupervisionDevice dsd) && dsd.CurrentState == SafetySystemState.Alarm)
+ {
+ lastResult = 1;
+ }
+ if (safetySystems.TryGetTypedValue(SafetySystem.OverspeedDevice, out OverspeedDevice osd) && osd.CurrentState == SafetySystemState.Alarm)
+ {
+ lastResult = 1;
+ }
+ break;
+ case PanelSubject.Penalty_App:
+ safetySystems = dynamicTrain.Cars[dynamicTrain.DriverCar].SafetySystems;
+ if (safetySystems.TryGetTypedValue(SafetySystem.DriverSupervisionDevice, out dsd) && dsd.CurrentState == SafetySystemState.Triggered)
+ {
+ lastResult = 1;
+ }
+ if (safetySystems.TryGetTypedValue(SafetySystem.OverspeedDevice, out osd) && osd.CurrentState == SafetySystemState.Triggered)
+ {
+ lastResult = 1;
+ }
+ break;
+ case PanelSubject.Load_Meter:
+ case PanelSubject.Ammeter:
+ case PanelSubject.Ammeter_Abs:
+ double amps = 0;
+ if (dynamicTrain != null)
+ {
+ int totalMotors = 0;
+ double ampsTotal = 0;
+ for (int k = 0; k < dynamicTrain.Cars.Length; k++)
+ {
+ if (dynamicTrain.Cars[k].TractionModel is DieselEngine dieselEngine)
+ {
+ if (dieselEngine.Components.TryGetTypedValue(EngineComponent.TractionMotor, out TractionMotor t))
+ {
+ totalMotors++;
+ ampsTotal += t.CurrentAmps;
+ }
+ else if (dieselEngine.Components.TryGetTypedValue(EngineComponent.RegenerativeTractionMotor, out RegenerativeTractionMotor rt))
+ {
+ totalMotors++;
+ ampsTotal += rt.CurrentAmps;
+ }
+ }
+ }
+
+ if (totalMotors == 0)
+ {
+ amps = 0;
+ }
+ else
+ {
+ amps = ampsTotal / totalMotors;
+ if (Subject == PanelSubject.Ammeter_Abs)
+ {
+ amps = Math.Abs(amps);
+ }
+ }
+ }
+ else
+ {
+ amps = 0;
+ }
+ MapDigitalResult(amps);
+ break;
+ case PanelSubject.Brake_Pipe:
+ double bp = dynamicTrain.Cars[dynamicTrain.DriverCar].CarBrake.BrakePipe.CurrentPressure;
+ bp *= UnitConversionFactor;
+ MapDigitalResult(bp);
+ break;
+ case PanelSubject.Eq_Res:
+ double er = dynamicTrain.Cars[dynamicTrain.DriverCar].CarBrake.EqualizingReservoir.CurrentPressure;
+ er *= UnitConversionFactor;
+ MapDigitalResult(er);
+ break;
+ case PanelSubject.Brake_Cyl:
+ double bc = dynamicTrain.Cars[dynamicTrain.DriverCar].CarBrake.BrakeCylinder.CurrentPressure;
+ bc *= UnitConversionFactor;
+ MapDigitalResult(bc);
+ break;
+ case PanelSubject.Main_Res:
+ double mr = dynamicTrain.Cars[dynamicTrain.DriverCar].CarBrake.MainReservoir.CurrentPressure;
+ mr *= UnitConversionFactor;
+ MapDigitalResult(mr);
+ break;
+ }
+ return lastResult;
+ }
+
+ private void MapResult(double val)
+ {
+ for (int i = 0; i < FrameMapping.Length; i++)
+ {
+ if (FrameMapping[i].MappingValue >= val)
+ {
+ lastResult = FrameMapping[i].FrameKey;
+ break;
+ }
+ }
+ }
+
+ private void MapDigitalResult(double val)
+ {
+ if (Digit == -1)
+ {
+ // color
+ lastResult = FrameMapping[FrameMapping.Length - 1].FrameKey;
+ for (int i = 0; i < FrameMapping.Length; i++)
+ {
+ if (FrameMapping[i].MappingValue <= val)
+ {
+ if (i == FrameMapping.Length - 1 || FrameMapping[i + 1].MappingValue > val)
+ {
+ lastResult = FrameMapping[i].FrameKey;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ // digit
+ double absVal = Math.Abs(val);
+ lastResult = (int)(absVal / (int)Math.Pow(10, Digit) % 10);
+ }
+ }
+
+ public AnimationScript Clone()
+ {
+ return new CvfAnimation(CurrentHost, Subject, FrameMapping);
+ }
+
+ public double LastResult
+ {
+ get => lastResult;
+ set { }
+ }
+
+ public double Maximum
+ {
+ get;
+ set;
+ }
+
+ public double Minimum
+ {
+ get;
+ set;
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Panel/CvfParser.cs b/source/Plugins/Train.MsTs/Panel/CvfParser.cs
new file mode 100644
index 0000000000..398b52a458
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Panel/CvfParser.cs
@@ -0,0 +1,576 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using LibRender2.Trains;
+using OpenBve.Formats.MsTs;
+using OpenBveApi.Colors;
+using OpenBveApi.Graphics;
+using OpenBveApi.Interface;
+using OpenBveApi.Math;
+using OpenBveApi.Objects;
+using OpenBveApi.Textures;
+using SharpCompress.Compressors;
+using SharpCompress.Compressors.Deflate;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using OpenBveApi.World;
+using TrainManager.Car;
+using TrainManager.Trains;
+
+namespace Train.MsTs
+{
+ internal class CabviewFileParser
+ {
+ // constants
+ internal const double StackDistance = 0.000001;
+
+ /// EyeDistance is required to be 1.0 by UpdateCarSectionElement and by UpdateCameraRestriction, thus cannot be easily changed.
+ private const double eyeDistance = 1.0;
+
+ internal static string CurrentFolder;
+
+ internal static string FileName;
+
+ private static readonly List cabComponents = new List();
+
+ // parse panel config
+ internal static bool ParseCabViewFile(string fileName, ref CarBase currentCar)
+ {
+ FileName = fileName;
+ cabComponents.Clear();
+ CurrentFolder = Path.GetDirectoryName(fileName);
+ Stream fb = new FileStream(fileName, FileMode.Open, FileAccess.Read);
+
+ byte[] buffer = new byte[34];
+ fb.Read(buffer, 0, 2);
+
+ bool unicode = buffer[0] == 0xFF && buffer[1] == 0xFE;
+
+ string headerString;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ headerString = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 2, 14);
+ headerString = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+
+ // SIMISA@F means compressed
+ // SIMISA@@ means uncompressed
+ if (headerString.StartsWith("SIMISA@F"))
+ {
+ fb = new ZlibStream(fb, CompressionMode.Decompress);
+ }
+ else if (headerString.StartsWith("\r\nSIMISA"))
+ {
+ // ie us1rd2l1000r10d.s, we are going to allow this but warn
+ Console.Error.WriteLine("Improper header in " + fileName);
+ fb.Read(buffer, 0, 4);
+ }
+ else if (!headerString.StartsWith("SIMISA@@"))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS CVF Parser: Unrecognized cabview file header " + headerString + " in " + FileName);
+ return false;
+ }
+
+ string subHeader;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ subHeader = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 0, 16);
+ subHeader = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+
+ if (subHeader[7] == 't')
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ byte[] newBytes = reader.ReadBytes((int) (fb.Length - fb.Position));
+ string s = unicode ? Encoding.Unicode.GetString(newBytes) : Encoding.ASCII.GetString(newBytes);
+ TextualBlock block = new TextualBlock(s, KujuTokenID.Tr_CabViewFile);
+ ParseBlock(block);
+ }
+
+ }
+ else if (subHeader[7] != 'b')
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS CVF Parser: Unrecognized subHeader " + subHeader + " in " + FileName);
+ return false;
+ }
+ else
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ KujuTokenID currentToken = (KujuTokenID) reader.ReadUInt16();
+ if (currentToken != KujuTokenID.Tr_CabViewFile)
+ {
+ throw new Exception(); //Shape definition
+ }
+
+ reader.ReadUInt16();
+ uint remainingBytes = reader.ReadUInt32();
+ byte[] newBytes = reader.ReadBytes((int) remainingBytes);
+ BinaryBlock block = new BinaryBlock(newBytes, KujuTokenID.Tr_CabViewFile);
+ ParseBlock(block);
+ }
+ }
+
+ //Create panel
+ //Create camera restriction
+ double worldWidth, worldHeight;
+ if (Plugin.Renderer.Screen.Width >= Plugin.Renderer.Screen.Height)
+ {
+ worldWidth = 2.0 * Math.Tan(0.5 * Plugin.Renderer.Camera.HorizontalViewingAngle) * eyeDistance;
+ worldHeight = worldWidth / Plugin.Renderer.Screen.AspectRatio;
+ }
+ else
+ {
+ worldHeight = 2.0 * Math.Tan(0.5 * Plugin.Renderer.Camera.VerticalViewingAngle) * eyeDistance / Plugin.Renderer.Screen.AspectRatio;
+ worldWidth = worldHeight * Plugin.Renderer.Screen.AspectRatio;
+ }
+
+ double x0 = -panelCenter.X / panelResolution;
+ double x1 = (panelSize.X - panelCenter.X) / panelResolution;
+ double y0 = (panelCenter.Y - panelSize.Y) / panelResolution * Plugin.Renderer.Screen.AspectRatio;
+ double y1 = panelCenter.Y / panelResolution * Plugin.Renderer.Screen.AspectRatio;
+ currentCar.CameraRestriction.BottomLeft = new Vector3(x0 * worldWidth, y0 * worldHeight, eyeDistance);
+ currentCar.CameraRestriction.TopRight = new Vector3(x1 * worldWidth, y1 * worldHeight, eyeDistance);
+ currentCar.DriverYaw = Math.Atan((panelCenter.X - panelOrigin.X) * worldWidth / panelResolution);
+ currentCar.DriverPitch = Math.Atan((panelOrigin.Y - panelCenter.Y) * worldWidth / panelResolution);
+
+ if(cabViews.Count == 0 || !File.Exists(cabViews[0].FileName))
+ {
+ return false;
+ }
+ currentCar.CameraRestrictionMode = CameraRestrictionMode.On;
+ Plugin.Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On;
+ currentCar.Driver = cabViews[0].Position;
+ for (int i = 0; i < cabViews.Count; i++)
+ {
+
+ Plugin.CurrentHost.RegisterTexture(cabViews[i].FileName, new TextureParameters(null, null), out Texture tday, true);
+ switch (i)
+ {
+ case 0:
+ currentCar.CarSections.Add(CarSectionType.Interior, new CarSection(Plugin.CurrentHost, ObjectType.Overlay, true, currentCar));
+ CreateElement(ref currentCar.CarSections[CarSectionType.Interior].Groups[0], Vector2.Null, panelSize, new Vector2(0.5, 0.5), 0.0, cabViews[0].Position, tday, null, new Color32(255, 255, 255, 255));
+ currentCar.CarSections[CarSectionType.Interior].ViewDirection = new Transformation(cabViews[0].Direction.Y.ToRadians(), -cabViews[0].Direction.X.ToRadians(), -cabViews[0].Direction.Z.ToRadians());
+ break;
+ case 1:
+ currentCar.CarSections.Add(CarSectionType.HeadOutLeft, new CarSection(Plugin.CurrentHost, ObjectType.Overlay, true, currentCar));
+ CreateElement(ref currentCar.CarSections[CarSectionType.HeadOutLeft].Groups[0], Vector2.Null, panelSize, new Vector2(0.5, 0.5), 0.0, cabViews[1].Position, tday, null, new Color32(255, 255, 255, 255));
+ currentCar.CarSections[CarSectionType.HeadOutLeft].ViewDirection = new Transformation(cabViews[1].Direction.Y.ToRadians(), -cabViews[1].Direction.X.ToRadians(), -cabViews[1].Direction.Z.ToRadians());
+ break;
+ case 2:
+ currentCar.CarSections.Add(CarSectionType.HeadOutRight, new CarSection(Plugin.CurrentHost, ObjectType.Overlay, true, currentCar));
+ CreateElement(ref currentCar.CarSections[CarSectionType.HeadOutRight].Groups[0], Vector2.Null, panelSize, new Vector2(0.5, 0.5), 0.0, cabViews[2].Position, tday, null, new Color32(255, 255, 255, 255));
+ currentCar.CarSections[CarSectionType.HeadOutRight].ViewDirection = new Transformation(cabViews[2].Direction.Y.ToRadians(), -cabViews[2].Direction.X.ToRadians(), -cabViews[2].Direction.Z.ToRadians());
+ break;
+ }
+ }
+
+ int currentLayer = 1;
+ for (int i = 0; i < cabComponents.Count; i++)
+ {
+ cabComponents[i].Create(ref currentCar, currentLayer);
+ currentLayer++; // component layering stacks downwards directly through the cabview
+ }
+
+ return true;
+ }
+
+ private static CabView currentCabView;
+
+ private static readonly List cabViews = new List();
+
+ private static void ParseBlock(Block block)
+ {
+ Block newBlock;
+ switch (block.Token)
+ {
+ case KujuTokenID.CabViewControls:
+ int count = block.ReadInt16();
+ int controlCount = count;
+ while (block.Length() - block.Position() > 5)
+ {
+ newBlock = block.ReadSubBlock(true);
+ if (newBlock.Token == KujuTokenID.Skip)
+ {
+ continue;
+ }
+ CabComponent currentComponent = new CabComponent(newBlock, cabViews[0].Position); // cab components can only be applied to CabView #0, others are static views
+ currentComponent.Parse();
+ cabComponents.Add(currentComponent);
+ controlCount--;
+ }
+
+ if (controlCount != 0)
+ {
+ // control count was wrong...
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS CVF Parser: Expected " + count + " controls, but found " + (count - controlCount) + " in file " + FileName);
+ }
+
+ break;
+ case KujuTokenID.Direction:
+ currentCabView.Direction.X = block.ReadSingle();
+ currentCabView.Direction.Y = block.ReadSingle();
+ currentCabView.Direction.Z = block.ReadSingle();
+ break;
+ case KujuTokenID.Position:
+ currentCabView.Position.X = block.ReadSingle();
+ currentCabView.Position.Y = block.ReadSingle();
+ currentCabView.Position.Z = block.ReadSingle();
+ break;
+ case KujuTokenID.CabViewWindow:
+ currentCabView.TopLeft.X = block.ReadInt16();
+ currentCabView.TopLeft.Y = block.ReadInt16();
+ currentCabView.PanelSize.X = block.ReadInt16();
+ currentCabView.PanelSize.Y = block.ReadInt16();
+ break;
+ case KujuTokenID.CabViewFile:
+ case KujuTokenID.CabViewWindowFile:
+ if (string.IsNullOrEmpty(currentCabView.FileName))
+ {
+ currentCabView.SetCabView(CurrentFolder, block.ReadString());
+ }
+
+ break;
+ case KujuTokenID.CabViewType:
+ case KujuTokenID.EngineData:
+ block.Skip((int) block.Length());
+ break;
+ case KujuTokenID.Tr_CabViewFile:
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewType);
+ ParseBlock(newBlock);
+ //The main front cabview
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewFile);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewWindow);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewWindowFile); //Appears to be a duplicate of CabViewFile, some are empty or v/v
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.Position); //Position within loco X,Y,Z
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.Direction); // ?? CAMERA DIRECTION ==> ROT Y, ROT X, ROT Z
+ ParseBlock(newBlock);
+ cabViews.Add(currentCabView);
+ currentCabView = new CabView();
+ //View #2, normally L
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewFile);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewWindow);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewWindowFile); //Appears to be a duplicate of CabViewFile, some are empty or v/v
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.Position); //Position within loco X,Y,Z
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.Direction); // ?? CAMERA DIRECTION ==> ROT Y, ROT X, ROT Z
+ ParseBlock(newBlock);
+ cabViews.Add(currentCabView);
+ currentCabView = new CabView();
+ //View #3, normally R
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewFile);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewWindow);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewWindowFile); //Appears to be a duplicate of CabViewFile, some are empty or v/v
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.Position); //Position within loco X,Y,Z
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.Direction); // ?? CAMERA DIRECTION ==> ROT Y, ROT X, ROT Z
+ ParseBlock(newBlock);
+ cabViews.Add(currentCabView);
+ newBlock = block.ReadSubBlock(KujuTokenID.EngineData);
+ ParseBlock(newBlock);
+ newBlock = block.ReadSubBlock(KujuTokenID.CabViewControls);
+ ParseBlock(newBlock);
+ break;
+ }
+ }
+
+ private const double panelResolution = 1024.0;
+ private static readonly Vector2 panelSize = new Vector2(1024, 768);
+ private static readonly Vector2 panelCenter = new Vector2(0, 240);
+ private static readonly Vector2 panelOrigin = new Vector2(0, 240);
+
+ // get stack language from subject
+ internal static string GetStackLanguageFromSubject(TrainBase train, PanelSubject subject, Units subjectUnits)
+ {
+ // transform subject
+ string Code = string.Empty;
+ switch (subject)
+ {
+ case PanelSubject.Load_Meter:
+ case PanelSubject.Ammeter:
+ Code = "amps";
+ break;
+ case PanelSubject.Ammeter_Abs:
+ Code = "amps abs";
+ break;
+ case PanelSubject.Brake_Cyl:
+ switch (subjectUnits)
+ {
+ case Units.PSI:
+ Code = "brakecylinder 0.000145038 *";
+ break;
+ case Units.Inches_Of_Mercury:
+ Code = "brakecylinder 0.0002953 *";
+ break;
+ case Units.Kilopascals:
+ Code = "brakecylinder 0.001 *";
+ break;
+ case Units.Bar:
+ Code = "brakecylinder 0.00001 *";
+ break;
+ case Units.Kgs_Per_Square_Cm:
+ Code = "brakecylinder 98066.5 *";
+ break;
+ }
+ break;
+ case PanelSubject.Brake_Pipe:
+ switch (subjectUnits)
+ {
+ case Units.PSI:
+ Code = "brakepipe 0.000145038 *";
+ break;
+ case Units.Inches_Of_Mercury:
+ Code = "brakepipe 0.0002953 *";
+ break;
+ case Units.Kilopascals:
+ Code = "brakepipe 0.001 *";
+ break;
+ case Units.Bar:
+ Code = "brakepipe 0.00001 *";
+ break;
+ case Units.Kgs_Per_Square_Cm:
+ Code = "brakepipe 98066.5 *";
+ break;
+ }
+ break;
+ case PanelSubject.Main_Res:
+ case PanelSubject.Vacuum_Reservoir_Pressure:
+ switch (subjectUnits)
+ {
+ case Units.PSI:
+ Code = "mainreservoir 0.000145038 *";
+ break;
+ case Units.Inches_Of_Mercury:
+ Code = "mainreservoir 0.0002953 *";
+ break;
+ case Units.Kilopascals:
+ Code = "mainreservoir 0.001 *";
+ break;
+ case Units.Bar:
+ Code = "mainreservoir 0.00001 *";
+ break;
+ case Units.Kgs_Per_Square_Cm:
+ Code = "mainreservoir 98066.5 *";
+ break;
+ }
+ break;
+ case PanelSubject.Eq_Res:
+ switch (subjectUnits)
+ {
+ case Units.PSI:
+ Code = "equalizingreservoir 0.000145038 *";
+ break;
+ case Units.Inches_Of_Mercury:
+ Code = "equalizingreservoir 0.0002953 *";
+ break;
+ case Units.Kilopascals:
+ Code = "equalizingreservoir 0.001 *";
+ break;
+ case Units.Bar:
+ Code = "equalizingreservoir 0.00001 *";
+ break;
+ case Units.Kgs_Per_Square_Cm:
+ Code = "equalizingreservoir 98066.5 *";
+ break;
+ }
+ break;
+ case PanelSubject.Direction:
+ Code = "reverserNotch ++";
+ break;
+ case PanelSubject.Engine_Brake:
+ Code = "locoBrakeNotch";
+ break;
+ case PanelSubject.Front_Hlight:
+ Code = "headlights";
+ break;
+ case PanelSubject.Bell:
+ Code = "musichorn";
+ break;
+ case PanelSubject.Whistle:
+ case PanelSubject.Horn:
+ Code = "horn";
+ break;
+ case PanelSubject.Speedometer:
+ // use speed not speedometer at the minute as wheelslip isn't right
+ switch (subjectUnits)
+ {
+ case Units.Miles_Per_Hour:
+ Code = "speed abs 2.2369362920544 *";
+ break;
+ case Units.Kilometers_Per_Hour:
+ Code = "speed abs 3.6 *";
+ break;
+ }
+ break;
+ case PanelSubject.Throttle:
+ Code = "brakeNotchLinear 0 powerNotch ?";
+ break;
+ case PanelSubject.Train_Brake:
+ Code = "brakeNotchLinear";
+ break;
+ case PanelSubject.Wipers:
+ Code = "wiperstate";
+ break;
+ case PanelSubject.Panto_Display:
+ case PanelSubject.Pantograph:
+ Code = "pantographstate";
+ break;
+ case PanelSubject.Speedlim_Display:
+ switch (subjectUnits)
+ {
+ case Units.Miles_Per_Hour:
+ Code = "routelimit sectionlimit max 1 Minus == 1 Minus routelimit sectionlimit max 2.2369362920544 * ?";
+ break;
+ case Units.Kilometers_Per_Hour:
+ Code = "routelimit sectionlimit max 1 Minus == 1 Minus routelimit sectionlimit max 3.6 * ?";
+ break;
+ }
+ break;
+ case PanelSubject.Emergency_Brake:
+ Code = "emergencybrake";
+ break;
+ default:
+ Code = "0";
+ break;
+ }
+ return Code;
+ }
+
+ internal static int CreateElement(ref ElementsGroup Group, Vector2 TopLeft, Vector2 Size, Vector2 RelativeRotationCenter, double Distance, Vector3 Driver, Texture DaytimeTexture, Texture NighttimeTexture, Color32 Color, bool AddStateToLastElement = false)
+ {
+ if (Size.X == 0 || Size.Y == 0)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS Cabview Parser: Attempted to create an invalid size element");
+ }
+
+ double worldWidth, worldHeight;
+ if (Plugin.Renderer.Screen.Width >= Plugin.Renderer.Screen.Height)
+ {
+ worldWidth = 2.0 * Math.Tan(0.5 * Plugin.Renderer.Camera.HorizontalViewingAngle) * eyeDistance;
+ worldHeight = worldWidth / Plugin.Renderer.Screen.AspectRatio;
+ }
+ else
+ {
+ worldHeight = 2.0 * Math.Tan(0.5 * Plugin.Renderer.Camera.VerticalViewingAngle) * eyeDistance / Plugin.Renderer.Screen.AspectRatio;
+ worldWidth = worldHeight * Plugin.Renderer.Screen.AspectRatio;
+ }
+
+ double x0 = TopLeft.X / panelResolution;
+ double x1 = (TopLeft.X + Size.X) / panelResolution;
+ double y0 = (panelSize.Y - TopLeft.Y) / panelResolution * Plugin.Renderer.Screen.AspectRatio;
+ double y1 = (panelSize.Y - (TopLeft.Y + Size.Y)) / panelResolution * Plugin.Renderer.Screen.AspectRatio;
+ double xd = 0.5 - panelCenter.X / panelResolution;
+ x0 += xd;
+ x1 += xd;
+ double yt = panelSize.Y - panelResolution / Plugin.Renderer.Screen.AspectRatio;
+ double yd = (panelCenter.Y - yt) / (panelSize.Y - yt) - 0.5;
+ y0 += yd;
+ y1 += yd;
+ x0 = (x0 - 0.5) * worldWidth;
+ x1 = (x1 - 0.5) * worldWidth;
+ y0 = (y0 - 0.5) * worldHeight;
+ y1 = (y1 - 0.5) * worldHeight;
+ double xm = x0 * (1.0 - RelativeRotationCenter.X) + x1 * RelativeRotationCenter.X;
+ double ym = y0 * (1.0 - RelativeRotationCenter.Y) + y1 * RelativeRotationCenter.Y;
+ Vector3[] v = new Vector3[4];
+ v[0] = new Vector3(x0 - xm, y1 - ym, 0);
+ v[1] = new Vector3(x0 - xm, y0 - ym, 0);
+ v[2] = new Vector3(x1 - xm, y0 - ym, 0);
+ v[3] = new Vector3(x1 - xm, y1 - ym, 0);
+ Vertex t0 = new Vertex(v[0], new Vector2(0.0f, 1.0f));
+ Vertex t1 = new Vertex(v[1], new Vector2(0.0f, 0.0f));
+ Vertex t2 = new Vertex(v[2], new Vector2(1.0f, 0.0f));
+ Vertex t3 = new Vertex(v[3], new Vector2(1.0f, 1.0f));
+ StaticObject staticObject = new StaticObject(Plugin.CurrentHost);
+ staticObject.Mesh.Vertices = new VertexTemplate[] {t0, t1, t2, t3};
+ staticObject.Mesh.Faces = new[] {new MeshFace(new[] {0, 1, 2, 0, 2, 3}, FaceFlags.Triangles)}; //Must create as a single face like this to avoid Z-sort issues with overlapping bits
+ staticObject.Mesh.Materials = new MeshMaterial[1];
+ staticObject.Mesh.Materials[0].Flags = new MaterialFlags();
+ if (DaytimeTexture != null)
+ {
+ staticObject.Mesh.Materials[0].Flags |= MaterialFlags.TransparentColor;
+ }
+
+ staticObject.Mesh.Materials[0].Color = Color;
+ staticObject.Mesh.Materials[0].TransparentColor = Color24.Blue;
+ staticObject.Mesh.Materials[0].DaytimeTexture = DaytimeTexture;
+ staticObject.Mesh.Materials[0].NighttimeTexture = NighttimeTexture;
+ staticObject.Dynamic = true;
+ // calculate offset
+ Vector3 o;
+ o.X = xm + Driver.X;
+ o.Y = ym + Driver.Y;
+ o.Z = eyeDistance - Distance + Driver.Z;
+ // add object
+ if (AddStateToLastElement)
+ {
+ int n = Group.Elements.Length - 1;
+ int j = Group.Elements[n].States.Length;
+ Array.Resize(ref Group.Elements[n].States, j + 1);
+ Group.Elements[n].States[j] = new ObjectState
+ {
+ Translation = Matrix4D.CreateTranslation(o.X, o.Y, -o.Z),
+ Prototype = staticObject
+ };
+ return n;
+ }
+ else
+ {
+ int n = Group.Elements.Length;
+ Array.Resize(ref Group.Elements, n + 1);
+ Group.Elements[n] = new AnimatedObject(Plugin.CurrentHost);
+ Group.Elements[n].States = new[] {new ObjectState()};
+ Group.Elements[n].States[0].Translation = Matrix4D.CreateTranslation(o.X, o.Y, -o.Z);
+ Group.Elements[n].States[0].Prototype = staticObject;
+ Group.Elements[n].CurrentState = 0;
+ Group.Elements[n].internalObject = new ObjectState {Prototype = staticObject};
+ Plugin.CurrentHost.CreateDynamicObject(ref Group.Elements[n].internalObject);
+ return n;
+ }
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Panel/Enums/CabComponentStyle.cs b/source/Plugins/Train.MsTs/Panel/Enums/CabComponentStyle.cs
new file mode 100644
index 0000000000..ccc5ce07a0
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Panel/Enums/CabComponentStyle.cs
@@ -0,0 +1,19 @@
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum CabComponentStyle
+ {
+ None = 0,
+ Needle,
+ Pointer,
+ Solid,
+ Sprung,
+ Not_Sprung,
+ OnOff,
+ TwentyFourHour,
+ TwelveHour,
+ While_Pressed,
+ Pressed,
+ Liquid,
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Panel/Enums/CabComponentType.cs b/source/Plugins/Train.MsTs/Panel/Enums/CabComponentType.cs
new file mode 100644
index 0000000000..2f23f7b88f
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Panel/Enums/CabComponentType.cs
@@ -0,0 +1,31 @@
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum CabComponentType
+ {
+ /// None
+ None = 0,
+ /// Dial based control
+ Dial = 1,
+ /// Lever based control
+ Lever = 2,
+ /// Dial based gauge
+ Gauge = 3,
+ /// Two-state based control
+ TwoState = 4,
+ /// Tri-state based control
+ TriState = 5,
+ /// A display capable of displaying N states
+ MultiStateDisplay = 6,
+ /// In cab signalling / safety system (e.g. AWS)
+ CabSignalDisplay = 7,
+ /// Steam locomotive firebox animation
+ Firebox = 8,
+ /// A digital display
+ Digital = 9,
+ /// A digital clock
+ DigitalClock = 10,
+ /// A combined power + brake controller
+ CombinedControl = 11
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Panel/Enums/PanelSubject.cs b/source/Plugins/Train.MsTs/Panel/Enums/PanelSubject.cs
new file mode 100644
index 0000000000..51f0181bbd
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Panel/Enums/PanelSubject.cs
@@ -0,0 +1,86 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum PanelSubject
+ {
+ Accelerometer,
+ Alerter_Display,
+ Ammeter,
+ Aspect_Display,
+ AWS,
+ Bell,
+ Blower,
+ Brake_Cyl,
+ Brake_Pipe,
+ Cab_Radio,
+ Clock,
+ CP_Handle,
+ CPH_Display,
+ Cutoff,
+ Cyl_Cocks,
+ Dampers_Back,
+ Dampers_Front,
+ Direction,
+ Direction_Display,
+ Dynamic_Brake,
+ Dynamic_Brake_Display,
+ Engine_Brake,
+ Engine_Braking_Button,
+ Emergency_Brake,
+ Eq_Res,
+ Firebox,
+ Firehole,
+ Friction_Braking,
+ Front_Hlight,
+ Fuel_Gauge,
+ Gears,
+ Horn,
+ Load_Meter,
+ Line_Voltage,
+ Main_Res,
+ Overspeed,
+ Pantograph,
+ Panto_Display,
+ Penalty_App,
+ Regulator,
+ Reset,
+ Reverser_Plate,
+ Sanders,
+ Sanding,
+ Small_Ejector,
+ Speedlim_Display,
+ Speedometer,
+ Steamchest_Pr,
+ Steamheat_Pressure,
+ Steam_Inj1,
+ Steam_Inj2,
+ Steam_Pr,
+ Tender_Water,
+ Boiler_Water,
+ Throttle,
+ Throttle_Display,
+ Traction_Braking,
+ Train_Brake,
+ Vacuum_Reservoir_Pressure,
+ Water_Injector1,
+ Water_Injector2,
+ Wheelslip,
+ Whistle,
+ Wipers,
+
+ // From MSTSBin v1.7 documentation
+ Ammeter_Abs,
+ Doors_Display,
+ Pantograph2, // pantograph2 state [need to dig into this, but I think Pantograph2 was 'broken' until BIN patch, although appears in original GLOBAL folder defines and some default stock]
+ Pantographs_4c, // 4-state combined controller for pantograoh 1+2
+ Pantographs_4, // with end position
+ Pantographs_5, // 5-state combined controller for pantograph 1+2
+ RPM,
+ Speed_Projected, // projected speed in one minute
+ SpeedLimit, // signal limit, not track limit
+
+ // probably MSTSBin
+ Dynamic_Brake_Force,
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Panel/FrameMapping.cs b/source/Plugins/Train.MsTs/Panel/FrameMapping.cs
new file mode 100644
index 0000000000..719558ed61
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Panel/FrameMapping.cs
@@ -0,0 +1,35 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+namespace Train.MsTs
+{
+ /// Maps a CVF animation frame to the key value
+ internal struct FrameMapping
+ {
+ /// The frame key
+ internal int FrameKey;
+ /// The key value
+ internal double MappingValue;
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Plugin.cs b/source/Plugins/Train.MsTs/Plugin.cs
new file mode 100644
index 0000000000..e9759777e2
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Plugin.cs
@@ -0,0 +1,105 @@
+using System.IO;
+using System.Text;
+using LibRender2;
+using Microsoft.Win32;
+using OpenBveApi;
+using OpenBveApi.FileSystem;
+using OpenBveApi.Hosts;
+using OpenBveApi.Interface;
+using OpenBveApi.Trains;
+using TrainManager.Trains;
+
+namespace Train.MsTs
+{
+ public class Plugin : TrainInterface
+ {
+ internal static ConsistParser ConsistParser;
+
+ internal static WagonParser WagonParser;
+
+ internal static HostInterface CurrentHost;
+
+ internal static BaseRenderer Renderer;
+
+ internal static FileSystem FileSystem;
+
+ internal static BaseOptions CurrentOptions;
+
+ internal static bool PreviewOnly;
+ public Plugin()
+ {
+ ConsistParser = new ConsistParser(this);
+ WagonParser = new WagonParser();
+ }
+
+ public override void Load(HostInterface host, FileSystem fileSystem, BaseOptions options, object rendererReference)
+ {
+ CurrentHost = host;
+ FileSystem = fileSystem;
+ CurrentOptions = options;
+ Renderer = (BaseRenderer) rendererReference;
+ try
+ {
+ if (!string.IsNullOrEmpty(FileSystem.MSTSDirectory))
+ {
+ return;
+ }
+ FileSystem.MSTSDirectory = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft Games\\Train Simulator\\1.0", "Path", string.Empty);
+ string OrTsPath = (string)Registry.GetValue("HKEY_CURRENT_USER\\Software\\OpenRails\\ORTS\\Folders", "Train Simulator", string.Empty);
+ if (!string.IsNullOrEmpty(OrTsPath))
+ {
+ FileSystem.MSTSDirectory = OrTsPath;
+ }
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+
+ public override bool CanLoadTrain(string path)
+ {
+ return File.Exists(path) && path.ToLowerInvariant().EndsWith(".con");
+ }
+
+ public override bool LoadTrain(Encoding encoding, string trainPath, ref AbstractTrain train, ref Control[] currentControls)
+ {
+ PreviewOnly = false;
+ try
+ {
+ ConsistParser.ReadConsist(trainPath, ref train);
+ }
+ catch
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public override string GetDescription(string trainPath, Encoding userSelectedEncoding = null)
+ {
+ PreviewOnly = true;
+ AbstractTrain train = new TrainBase(TrainState.Pending, TrainType.LocalPlayerTrain);
+ try
+ {
+ ConsistParser.ReadConsist(trainPath, ref train);
+ }
+ catch
+ {
+ return string.Empty;
+ }
+
+ if(train is TrainBase trainBase && trainBase.Cars.Length != 0)
+ {
+ return trainBase.Cars[train.DriverCar].Description;
+ }
+ return string.Empty;
+ }
+
+ public override string GetImage(string trainPath)
+ {
+ return string.Empty;
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Properties/AssemblyInfo.cs b/source/Plugins/Train.MsTs/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..256878fa3a
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Train.MsTs")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Train.MsTs")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a6e3d875-ddfa-446a-aaf5-bfaff3c9ef45")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/source/Plugins/Train.MsTs/Sound/SmsParser.cs b/source/Plugins/Train.MsTs/Sound/SmsParser.cs
new file mode 100644
index 0000000000..f651092c55
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Sound/SmsParser.cs
@@ -0,0 +1,706 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBve.Formats.MsTs;
+using OpenBveApi;
+using OpenBveApi.Interface;
+using OpenBveApi.Math;
+using OpenBveApi.Motor;
+using OpenBveApi.Runtime;
+using OpenBveApi.World;
+using SharpCompress.Compressors;
+using SharpCompress.Compressors.Deflate;
+using SoundManager;
+using System;
+using System.IO;
+using System.Text;
+using TrainManager.Car;
+using TrainManager.Car.Systems;
+using TrainManager.Motor;
+using TrainManager.MsTsSounds;
+using TrainManager.SafetySystems;
+
+namespace Train.MsTs
+{
+ internal class SoundModelSystemParser
+ {
+ private static string currentFolder;
+
+ private static string currentFile;
+
+ private static Tuple[] curvePoints;
+
+ internal static bool ParseSoundFile(string fileName, ref CarBase currentCar)
+ {
+ currentFile = fileName;
+ currentFolder = System.IO.Path.GetDirectoryName(fileName);
+ Stream fb = new FileStream(fileName, FileMode.Open, FileAccess.Read);
+
+ byte[] buffer = new byte[34];
+ fb.Read(buffer, 0, 2);
+
+ bool unicode = buffer[0] == 0xFF && buffer[1] == 0xFE;
+
+ string headerString;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ headerString = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 2, 14);
+ headerString = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+
+ // SIMISA@F means compressed
+ // SIMISA@@ means uncompressed
+ if (headerString.StartsWith("SIMISA@F"))
+ {
+ fb = new ZlibStream(fb, CompressionMode.Decompress);
+ }
+ else if (headerString.StartsWith("\r\nSIMISA"))
+ {
+ // ie us1rd2l1000r10d.s, we are going to allow this but warn
+ Console.Error.WriteLine("Improper header in " + fileName);
+ fb.Read(buffer, 0, 4);
+ }
+ else if (!headerString.StartsWith("SIMISA@@"))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognized SMS file header " + headerString + " in " + fileName);
+ return false;
+ }
+
+ string subHeader;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ subHeader = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 0, 16);
+ subHeader = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+ SoundSet soundSet = new SoundSet();
+ SoundStream soundStream = new SoundStream(currentCar, CameraViewMode.NotDefined, CameraViewMode.NotDefined);
+
+ if (subHeader[7] == 't')
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ byte[] newBytes = reader.ReadBytes((int)(fb.Length - fb.Position));
+ string s = unicode ? Encoding.Unicode.GetString(newBytes) : Encoding.ASCII.GetString(newBytes);
+ TextualBlock block = new TextualBlock(s, KujuTokenID.Tr_SMS);
+ ParseBlock(block, ref soundSet, ref soundStream, ref currentCar);
+ }
+
+ }
+ else if (subHeader[7] != 'b')
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognized subHeader " + subHeader + " in " + fileName);
+ }
+ else
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ KujuTokenID currentToken = (KujuTokenID)reader.ReadUInt16();
+ if (currentToken != KujuTokenID.Tr_SMS)
+ {
+ return false;
+ }
+
+ reader.ReadUInt16();
+ uint remainingBytes = reader.ReadUInt32();
+ byte[] newBytes = reader.ReadBytes((int)remainingBytes);
+ BinaryBlock block = new BinaryBlock(newBytes, KujuTokenID.Tr_SMS);
+ ParseBlock(block, ref soundSet, ref soundStream, ref currentCar);
+ }
+ }
+
+ return false;
+ }
+
+
+ internal struct SoundSet
+ {
+ internal bool Activation;
+ internal double ActivationDistance;
+ internal double DeactivationDistance;
+ internal double Priority;
+
+ internal SoundTrigger CurrentTrigger;
+ internal KujuTokenID CurrentSoundType;
+ internal KujuTokenID VariableTriggerType;
+ internal double VariableValue;
+ internal SoundBuffer[] SoundBuffers;
+ internal int CurrentBuffer;
+ internal KujuTokenID SelectionMethod;
+ internal CameraViewMode ActivationCameraModes;
+ internal CameraViewMode DeactivationCameraModes;
+
+ internal void Create(CarBase car, SoundStream currentSoundStream)
+ {
+ switch (VariableTriggerType)
+ {
+ case KujuTokenID.Initial_Trigger:
+ currentSoundStream.Triggers.Add(new InitialTrigger(SoundBuffers, SelectionMethod, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ case KujuTokenID.Speed_Inc_Past:
+ currentSoundStream.Triggers.Add(new SpeedIncPast(SoundBuffers, SelectionMethod, VariableValue, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ case KujuTokenID.Speed_Dec_Past:
+ currentSoundStream.Triggers.Add(new SpeedDecPast(SoundBuffers, SelectionMethod, VariableValue, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ case KujuTokenID.Variable1_Inc_Past:
+ currentSoundStream.Triggers.Add(new Variable1IncPast(SoundBuffers, SelectionMethod, VariableValue, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ case KujuTokenID.Variable1_Dec_Past:
+ currentSoundStream.Triggers.Add(new Variable1DecPast(SoundBuffers, SelectionMethod, VariableValue, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ case KujuTokenID.Variable2_Inc_Past:
+ currentSoundStream.Triggers.Add(new Variable2IncPast(SoundBuffers, SelectionMethod, VariableValue, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ case KujuTokenID.Variable2_Dec_Past:
+ currentSoundStream.Triggers.Add(new Variable2DecPast(SoundBuffers, SelectionMethod, VariableValue, CurrentSoundType != KujuTokenID.PlayOneShot));
+ break;
+ }
+ }
+ }
+
+
+
+ private static void ParseBlock(Block block, ref SoundSet currentSoundSet, ref SoundStream currentSoundStream, ref CarBase car)
+ {
+ Block newBlock;
+ switch (block.Token)
+ {
+ case KujuTokenID.Tr_SMS:
+ // file root
+ while (block.Position() < block.Length() - 3)
+ {
+ try
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+ catch
+ {
+ break;
+ }
+ }
+ break;
+ case KujuTokenID.ScalabiltyGroup:
+ // root container for sound groups
+ block.ReadSingle(); // number of groups
+ while (block.Position() < block.Length())
+ {
+ try
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ throw;
+ }
+ }
+ break;
+ case KujuTokenID.Activation:
+ // control the conditions under which the sounds in the group are activated
+ currentSoundSet.Activation = true;
+ while (block.Position() < block.Length() - 3)
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+ break;
+ case KujuTokenID.Deactivation:
+ // control the conditions under which the sounds in the group are deactivated
+ currentSoundSet.Activation = false;
+ while (block.Position() < block.Length() - 3)
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+ break;
+ case KujuTokenID.Distance:
+ // absolute distance, presumably to camera
+ if (currentSoundSet.Activation)
+ {
+ currentSoundSet.ActivationDistance = block.ReadSingle();
+ }
+ else
+ {
+ currentSoundSet.DeactivationDistance = block.ReadSingle();
+ }
+ break;
+ case KujuTokenID.ExternalCam:
+ if (currentSoundSet.Activation)
+ {
+ currentSoundSet.ActivationCameraModes |= CameraViewMode.Exterior;
+ currentSoundSet.ActivationCameraModes |= CameraViewMode.Track;
+ currentSoundSet.ActivationCameraModes |= CameraViewMode.FlyBy;
+ currentSoundSet.ActivationCameraModes |= CameraViewMode.FlyByZooming;
+ }
+ else
+ {
+ currentSoundSet.DeactivationCameraModes |= CameraViewMode.Exterior;
+ currentSoundSet.DeactivationCameraModes |= CameraViewMode.Track;
+ currentSoundSet.DeactivationCameraModes |= CameraViewMode.FlyBy;
+ currentSoundSet.DeactivationCameraModes |= CameraViewMode.FlyByZooming;
+ }
+ break;
+ case KujuTokenID.CabCam:
+ if (currentSoundSet.Activation)
+ {
+ currentSoundSet.ActivationCameraModes |= CameraViewMode.Interior;
+ }
+ else
+ {
+ currentSoundSet.DeactivationCameraModes |= CameraViewMode.Interior;
+ }
+ break;
+ case KujuTokenID.PassengerCam:
+ // FIXME: Passenger cam not currently distinguished from interior cam
+ break;
+ case KujuTokenID.Streams:
+ // each stream represents a unique sound
+ int numStreams = block.ReadInt32();
+ for (int i = 0; i < numStreams; i++)
+ {
+ newBlock = block.ReadSubBlock();
+ if (newBlock.Token != KujuTokenID.Stream)
+ {
+ i--;
+ if (newBlock.Token != KujuTokenID.Skip)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Unexpected additional block " + newBlock.Token + " encounted within Stream block in SMS file " + currentFile);
+ }
+ if (block.Length() - block.Position() <= 3)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Expected " + numStreams + ", but only found " + i + " in Stream block in SMS file " + currentFile);
+ break;
+ }
+ continue;
+ }
+
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ if (block.Length() - block.Position() <= 3)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Expected " + numStreams + ", but only found " + i + " in Stream block in SMS file " + currentFile);
+ break;
+ }
+ }
+ break;
+ case KujuTokenID.Stream:
+ while (block.Position() < block.Length() - 3)
+ {
+ newBlock = block.ReadSubBlock();
+ if (newBlock.Token == KujuTokenID.Stream)
+ {
+ // EBPHNWSE121.sms - Completely bugged, copy + paste error (?)
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Unexpected Stream found within a Stream block in SMS file " + currentFile);
+ continue;
+ }
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+
+ if (currentSoundStream.Triggers.Count > 0)
+ {
+ car.Sounds.ControlledSounds.Add(currentSoundStream);
+ currentSoundStream = new SoundStream(car, currentSoundSet.ActivationCameraModes, currentSoundSet.DeactivationCameraModes);
+ }
+ break;
+ case KujuTokenID.Priority:
+ currentSoundSet.Priority = block.ReadSingle();
+ break;
+ case KujuTokenID.Triggers:
+ int numTriggers = block.ReadInt32();
+ for (int i = 0; i < numTriggers; i++)
+ {
+ // two triggers per sound set (start + stop)
+ newBlock = block.ReadSubBlock(new [] {KujuTokenID.Variable_Trigger, KujuTokenID.Initial_Trigger, KujuTokenID.Discrete_Trigger, KujuTokenID.Random_Trigger, KujuTokenID.Dist_Travelled_Trigger});
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ if (block.Length() - block.Position() <= 3)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Expected " + numTriggers + ", but only found " + i + " in Triggers block in SMS file " + currentFile);
+ break;
+ }
+ }
+ break;
+ case KujuTokenID.Initial_Trigger:
+ // when initially appears, hence nothing other than StartLoop should be valid
+ currentSoundSet.VariableTriggerType = KujuTokenID.Initial_Trigger;
+ newBlock = block.ReadSubBlock(new[] { KujuTokenID.StartLoop, KujuTokenID.StartLoopRelease, KujuTokenID.ReleaseLoopRelease, KujuTokenID.EnableTrigger, KujuTokenID.DisableTrigger, KujuTokenID.PlayOneShot, KujuTokenID.SetStreamVolume });
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ break;
+ case KujuTokenID.StartLoopRelease:
+ case KujuTokenID.StartLoop:
+ /* StartLoopRelease - Loop stops when key is released
+ * StartLoop - Loop continues when key is released
+ * ---------------------------------------------------
+ * NOTE: Handle these on a per-sound trigger, as where possible
+ * map to existing subsystems
+ */
+ currentSoundSet.CurrentSoundType = block.Token;
+ int numSounds = block.ReadInt16();
+ currentSoundSet.SoundBuffers = new SoundBuffer[numSounds];
+ currentSoundSet.SelectionMethod = KujuTokenID.SequentialSelection;
+ while (numSounds > 0 && block.Position() < block.Length() - 4)
+ {
+ newBlock = block.ReadSubBlock();
+ if (newBlock.Token == KujuTokenID.File)
+ {
+ numSounds--;
+ }
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+ currentSoundSet.Create(car, currentSoundStream);
+ break;
+ case KujuTokenID.ReleaseLoopRelease:
+ // empty block expected
+ // paired with StartLoopRelease
+ currentSoundSet.Create(car, currentSoundStream);
+ break;
+ case KujuTokenID.File:
+ if (block.ReadPath(currentFolder, out string soundFile))
+ {
+ // n.b. MSTS does not distinguish between increase / decrease sounds for handles etc.
+ // sound radii are also fudged based upon BVE values; most MSTS content just seems to use massive radii
+ switch (currentSoundSet.CurrentTrigger)
+ {
+ case SoundTrigger.VariableControlled:
+ // hack
+ Plugin.CurrentHost.RegisterSound(soundFile, currentSoundSet.ActivationDistance, out var soundHandle);
+ currentSoundSet.SoundBuffers[currentSoundSet.CurrentBuffer] = soundHandle as SoundBuffer;
+ break;
+ case SoundTrigger.ReverserToForwardBackward:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot)
+ {
+ car.baseTrain.Handles.Reverser.EngageSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.ReverserToNeutral:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot)
+ {
+ car.baseTrain.Handles.Reverser.ReleaseSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.ReverserChange:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot)
+ {
+ // as we don't know the order these may be presented in, check the buffer
+ if (car.baseTrain.Handles.Reverser.EngageSound.Buffer == null)
+ {
+ car.baseTrain.Handles.Reverser.EngageSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+
+ if (car.baseTrain.Handles.Reverser.ReleaseSound.Buffer == null)
+ {
+ car.baseTrain.Handles.Reverser.ReleaseSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ }
+ break;
+ case SoundTrigger.ThrottleChange:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot)
+ {
+ car.baseTrain.Handles.Power.Decrease = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Power.DecreaseFast = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Power.Increase = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Power.IncreaseFast = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Power.Min = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Power.Max = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.TrainBrakeChange:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot)
+ {
+ car.baseTrain.Handles.Brake.Decrease = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Brake.DecreaseFast = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Brake.Increase = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Brake.IncreaseFast = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Brake.Min = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.Brake.Max = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.EngineBrakeChange:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot && car.baseTrain.Handles.LocoBrake != null)
+ {
+ car.baseTrain.Handles.LocoBrake.Decrease = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.LocoBrake.DecreaseFast = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.LocoBrake.Increase = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.LocoBrake.IncreaseFast = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.LocoBrake.Min = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ car.baseTrain.Handles.LocoBrake.Max = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.LightSwitchToggle:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.PlayOneShot && car.baseTrain.SafetySystems.Headlights != null)
+ {
+ Plugin.CurrentHost.RegisterSound(soundFile, 2.0, out soundHandle);
+ car.baseTrain.SafetySystems.Headlights.SwitchSoundBuffer = soundHandle as SoundBuffer;
+ }
+ break;
+ case SoundTrigger.HornOn:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.StartLoopRelease && car.Horns[0] != null)
+ {
+ Plugin.CurrentHost.RegisterSound(soundFile, 30.0, out soundHandle);
+ car.Horns[0].LoopSound = soundHandle as SoundBuffer;
+ }
+ break;
+ case SoundTrigger.BellOn:
+ if (currentSoundSet.CurrentSoundType == KujuTokenID.StartLoopRelease && car.Horns[2] != null)
+ {
+ Plugin.CurrentHost.RegisterSound(soundFile, 30.0, out soundHandle);
+ car.Horns[0].LoopSound = soundHandle as SoundBuffer;
+ }
+ break;
+ case SoundTrigger.Pantograph1Up:
+ case SoundTrigger.Pantograph1Down:
+ case SoundTrigger.Pantograph1Toggle:
+ if (car.TractionModel.Components.TryGetTypedValue(EngineComponent.Pantograph, out Pantograph pantograph))
+ {
+ if (currentSoundSet.CurrentTrigger == SoundTrigger.Pantograph1Up)
+ {
+ pantograph.RaiseSound = new CarSound(Plugin.CurrentHost, soundFile, 100, Vector3.Zero);
+ }
+ else if(currentSoundSet.CurrentTrigger == SoundTrigger.Pantograph1Down)
+ {
+ pantograph.LowerSound = new CarSound(Plugin.CurrentHost, soundFile, 100, Vector3.Zero);
+ }
+ else
+ {
+ pantograph.SwitchToggle = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ }
+ else
+ {
+ // n.b. A WAG file may link to a model containing pantograph animations, or a SMS with pantograph sounds, but does not need to mention
+ // that it exists, so we may need to add it here.
+ Pantograph newPantograph = new Pantograph(car.TractionModel);
+ if (currentSoundSet.CurrentTrigger == SoundTrigger.Pantograph1Up)
+ {
+ newPantograph.RaiseSound = new CarSound(Plugin.CurrentHost, soundFile, 100, Vector3.Zero);
+ }
+ else if (currentSoundSet.CurrentTrigger == SoundTrigger.Pantograph1Down)
+ {
+ newPantograph.LowerSound = new CarSound(Plugin.CurrentHost, soundFile, 100, Vector3.Zero);
+ }
+ else
+ {
+ newPantograph.SwitchToggle = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ car.TractionModel.Components.Add(EngineComponent.Pantograph, newPantograph);
+ }
+ break;
+ case SoundTrigger.WiperOn:
+ case SoundTrigger.WiperOff:
+ car.Windscreen.Wipers.SwitchSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ break;
+ case SoundTrigger.SanderOn:
+ if (car.ReAdhesionDevice is Sanders sanders)
+ {
+ sanders.LoopSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.TrainBrakePressureDecrease:
+ if ((currentSoundStream.ActivationCameraModes & CameraViewMode.Interior) != 0)
+ {
+ car.CarBrake.AirZero = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.VigilanceAlarmOn:
+ // NOTE: appears to only apply to DSD, not overspeed
+ if (car.SafetySystems.TryGetTypedValue(SafetySystem.DriverSupervisionDevice, out DriverSupervisionDevice dsd))
+ {
+ dsd.AlarmSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ dsd.AlertSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ break;
+ case SoundTrigger.GearUp:
+ case SoundTrigger.GearDown:
+ if (car.TractionModel.Components.TryGetTypedValue(EngineComponent.Gearbox, out Gearbox gearbox))
+ {
+ if (currentSoundSet.CurrentTrigger == SoundTrigger.GearUp)
+ {
+ gearbox.GearUpSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ else
+ {
+ gearbox.GearDownSound = new CarSound(Plugin.CurrentHost, soundFile, 2.0, car.Driver);
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (currentSoundSet.CurrentTrigger != SoundTrigger.Skip)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS Sound File " + soundFile + " was not found in SMS " + currentFile);
+ }
+ }
+ int checkDigit = block.ReadInt32();
+ if (checkDigit != -1)
+ {
+ // Unknown purpose at the minute- set to -1 everywhere
+ throw new Exception();
+ }
+
+ break;
+ case KujuTokenID.SelectionMethod:
+ KujuTokenID token = block.ReadEnumValue(default(KujuTokenID));
+ switch (token)
+ {
+ case KujuTokenID.SequentialSelection:
+ break;
+ case KujuTokenID.RandomSelection:
+ break;
+ }
+ break;
+ case KujuTokenID.Discrete_Trigger:
+ currentSoundSet.CurrentTrigger = (SoundTrigger)block.ReadInt32(); // stored as integer
+ newBlock = block.ReadSubBlock(new[] { KujuTokenID.PlayOneShot, KujuTokenID.StartLoop, KujuTokenID.StartLoopRelease, KujuTokenID.ReleaseLoopRelease, KujuTokenID.ReleaseLoopReleaseWithJump, KujuTokenID.SetStreamVolume, KujuTokenID.EnableTrigger, KujuTokenID.DisableTrigger });
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ break;
+ case KujuTokenID.Variable_Trigger:
+ currentSoundSet.VariableTriggerType = block.ReadEnumValue(default(KujuTokenID));
+ switch (currentSoundSet.VariableTriggerType)
+ {
+ case KujuTokenID.StartLoop:
+ break;
+ case KujuTokenID.Speed_Inc_Past:
+ case KujuTokenID.Speed_Dec_Past:
+ currentSoundSet.VariableValue = block.ReadSingle(UnitOfVelocity.KilometersPerHour, UnitOfVelocity.MetersPerSecond); // speed in m/s
+ newBlock = block.ReadSubBlock(new[] { KujuTokenID.StartLoop, KujuTokenID.StartLoopRelease, KujuTokenID.ReleaseLoopRelease, KujuTokenID.ReleaseLoopReleaseWithJump, KujuTokenID.PlayOneShot, KujuTokenID.EnableTrigger, KujuTokenID.DisableTrigger, KujuTokenID.SetStreamVolume });
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ break;
+ case KujuTokenID.SpeedControlled:
+ break;
+ case KujuTokenID.DistanceControlled:
+ break;
+ case KujuTokenID.Distance_Inc_Past:
+ case KujuTokenID.Distance_Dec_Past:
+ break;
+ case KujuTokenID.Variable1Controlled:
+ break;
+ case KujuTokenID.Variable1_Inc_Past:
+ case KujuTokenID.Variable1_Dec_Past:
+ case KujuTokenID.Variable2_Inc_Past:
+ case KujuTokenID.Variable2_Dec_Past:
+ currentSoundSet.VariableValue = block.ReadSingle(); // variable value
+ newBlock = block.ReadSubBlock(new[] { KujuTokenID.StartLoop, KujuTokenID.StartLoopRelease, KujuTokenID.ReleaseLoopRelease, KujuTokenID.ReleaseLoopReleaseWithJump, KujuTokenID.EnableTrigger, KujuTokenID.DisableTrigger, KujuTokenID.PlayOneShot, KujuTokenID.SetStreamVolume });
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ break;
+ case KujuTokenID.Variable2Controlled:
+ break;
+ case KujuTokenID.Variable3_Inc_Past:
+ case KujuTokenID.Variable3_Dec_Past:
+ case KujuTokenID.Variable3Controlled:
+ break;
+ default:
+ throw new Exception("Unexpected enum value " + currentSoundSet.VariableTriggerType + " encounted in SMS file " + currentFile);
+ }
+ break;
+ case KujuTokenID.PlayOneShot:
+ currentSoundSet.CurrentSoundType = block.Token;
+ numSounds = block.ReadInt16();
+ currentSoundSet.SoundBuffers = new SoundBuffer[numSounds];
+ currentSoundSet.SelectionMethod = KujuTokenID.SequentialSelection;
+ while (numSounds > 0 && block.Position() < block.Length() - 4)
+ {
+ newBlock = block.ReadSubBlock();
+ if (newBlock.Token == KujuTokenID.File)
+ {
+ numSounds--;
+ }
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ }
+ currentSoundSet.Create(car, currentSoundStream);
+ break;
+ case KujuTokenID.Volume:
+ double volume = block.ReadSingle();
+ break;
+ case KujuTokenID.VolumeCurve:
+ token = block.ReadEnumValue(default(KujuTokenID));
+ switch (token)
+ {
+ case KujuTokenID.SpeedControlled:
+ case KujuTokenID.DistanceControlled:
+ case KujuTokenID.Variable1Controlled:
+ case KujuTokenID.Variable2Controlled:
+ case KujuTokenID.Variable3Controlled:
+ newBlock = block.ReadSubBlock(KujuTokenID.CurvePoints);
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ break;
+ default:
+ throw new Exception("Unexpected enum value " + token + " encounted in SMS file " + currentFile);
+ }
+
+ currentSoundStream.VolumeCurve = new MsTsVolumeCurve(car, token, curvePoints);
+ break;
+ case KujuTokenID.FrequencyCurve:
+ token = block.ReadEnumValue(default(KujuTokenID));
+ switch (token)
+ {
+ case KujuTokenID.SpeedControlled:
+ case KujuTokenID.DistanceControlled:
+ case KujuTokenID.Variable1Controlled:
+ case KujuTokenID.Variable2Controlled:
+ case KujuTokenID.Variable3Controlled:
+ newBlock = block.ReadSubBlock(KujuTokenID.CurvePoints);
+ ParseBlock(newBlock, ref currentSoundSet, ref currentSoundStream, ref car);
+ break;
+ default:
+ throw new Exception("Unexpected enum value " + token + " encounted in SMS file " + currentFile);
+ }
+
+ currentSoundStream.FrequencyCurve = new MsTsFrequencyCurve(car, token, curvePoints);
+ break;
+ case KujuTokenID.CurvePoints:
+ int numPoints = block.ReadInt32();
+ curvePoints = new Tuple[numPoints];
+ for (int i = 0; i < numPoints; i++)
+ {
+ // Normalise Variable2 values to be consistant across traction models
+ // MSTS yuck...
+ if (car.TractionModel is ElectricEngine)
+ {
+ curvePoints[i] = new Tuple(block.ReadSingle() / 100, block.ReadSingle());
+ }
+ else
+ {
+ curvePoints[i] = new Tuple(block.ReadSingle(), block.ReadSingle());
+ }
+ }
+ break;
+ case KujuTokenID.Granularity:
+ // presuming this is the step in km/h
+ break;
+ }
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Sound/TriggerTypes.cs b/source/Plugins/Train.MsTs/Sound/TriggerTypes.cs
new file mode 100644
index 0000000000..f4486ebf11
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Sound/TriggerTypes.cs
@@ -0,0 +1,98 @@
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum SoundTrigger
+ {
+ // -1 appears to be used to skip the sound
+ // unclear as to why it's not just left out, copy + paste or internal MSTS validation?
+ // some of the time, these exist, but a lot of the time the sound file is missing
+ Skip = -1,
+ VariableControlled = 0,
+ DynamicBrakeIncrease = 2,
+ DynamicBrakeOff = 3,
+ SanderOn = 4,
+ SanderOff = 5,
+ WiperOn = 6,
+ WiperOff = 7,
+ HornOn= 8,
+ HornOff = 9,
+ BellOn = 10,
+ BellOff = 11,
+ CompressorOn = 12,
+ CompressorOff = 13,
+ TrainBrakePressureIncrease = 14,
+ ReverserChange = 15,
+ ThrottleChange = 16,
+ TrainBrakeChange = 17,
+ EngineBrakeChange = 18,
+ // 19 not listed
+ DynamicBrakeChange = 20,
+ EngineBrakePressureIncrease = 21,
+ EngineBrakePressureDecrease = 22,
+ EnginePowerOn = 23,
+ EnginePowerOff = 24,
+ // 25 + 26 not listed
+ SteamEjector2On = 27,
+ SteamEjector2Off = 28,
+ //29 + 30 not listed
+ SteamEjector1On = 30,
+ SteamEjector1Off = 31,
+ DamperChange = 32,
+ BlowerChange = 33,
+ CylinderCocksToggle = 34,
+ // 35 not listed
+ FireboxDoorChange = 36,
+ LightSwitchToggle = 37,
+ WaterScoopDown = 38,
+ WaterScoopUp = 39,
+ // 40 not listed
+ FireboxDoorClose = 41,
+ SteamSafetyValveOn = 42,
+ SteamSafetyValveOff = 43,
+ SteamHeatChange = 44,
+ Pantograph1Up = 45,
+ Pantograph1Down = 46,
+ Pantograph1Toggle = 47,
+ VigilanceAlarmReset = 48,
+ // 49 - 53 not listed
+
+ //
+ // acelaeng.sms has 53 commented as Brake Normal Apply and 54 as BrakeEmergencyApply
+ //
+ // OpenRails forum suggests that trigger 53 never actually worked
+ //
+ TrainBrakePressureDecrease = 54,
+ //55 not listed
+ VigilanceAlarmOn = 56,
+ VigilanceAlarmOff = 57,
+ Couple = 58,
+ CoupleB = 59,
+ CoupleC = 60,
+ Uncouple = 61,
+ UncoupleB = 62,
+ UncoupleC = 63,
+ // 64 + 65 not listed
+ Pantograph2Up = 66,
+ Pantograph2Down = 67,
+ /*
+ * NOTE:
+ * https://open-rails.readthedocs.io/en/latest/sound.html
+ * ORTS specific triggers
+ *
+ * Not looking to handle most of these at the minute.
+ */
+ WaterPump1On = 90,
+ WaterPump1Off = 91,
+ WaterPump2On = 92,
+ WaterPump2Off = 93,
+ GearUp = 101,
+ GearDown = 102,
+ ReverserToForwardBackward = 103,
+ ReverserToNeutral = 104,
+ DoorOpen = 105,
+ DoorClose = 106,
+ MirrorOpen = 107,
+ MirrorClose = 108
+
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train.MsTs.csproj b/source/Plugins/Train.MsTs/Train.MsTs.csproj
new file mode 100644
index 0000000000..e321a68373
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train.MsTs.csproj
@@ -0,0 +1,123 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A6E3D875-DDFA-446A-AAF5-BFAFF3C9EF45}
+ Library
+ Properties
+ Train.MsTs
+ Train.MsTs
+ v4.6.1
+ 512
+ true
+
+
+ true
+ full
+ false
+ ..\..\..\bin_debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\..\bin_release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ ..\..\..\packages\SharpCompress.0.32.2\lib\net461\SharpCompress.dll
+
+
+
+ ..\..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
+
+
+
+ ..\..\..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
+
+
+
+ ..\..\..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\..\..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {68215476-302C-49F2-9F7E-AAE20A2B6B12}
+ LibRender2
+
+
+ {27134980-4415-4375-A564-40A9014DFA5F}
+ OpenBveApi
+
+
+ {90ABFA0C-ABCA-444E-ADEF-9A299AED6524}
+ SoundManager
+
+
+ {D0FCA2C5-FF75-42D8-AE80-310280A61FB1}
+ TrainManager
+
+
+ {e81b7bd8-a326-47d3-b7ee-e9c7d4d119fa}
+ Formats.Msts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/Plugins/Train.MsTs/Train/Adhesion.cs b/source/Plugins/Train.MsTs/Train/Adhesion.cs
new file mode 100644
index 0000000000..a3ca162941
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/Adhesion.cs
@@ -0,0 +1,143 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBve.Formats.MsTs;
+using OpenBveApi.Interface;
+using TrainManager.Car;
+using TrainManager.Car.Systems;
+
+namespace Train.MsTs
+{
+ internal class Adhesion
+ {
+ /// Holds a reference to the base car
+ private readonly CarBase baseCar;
+ /// The value used in wheelslip conditions
+ private readonly double WheelSlip;
+ /// The value used in normal conditions
+ private readonly double Normal;
+ /// The value used in sanding conditions
+ private readonly double Sanding;
+
+ internal Adhesion(CarBase car, bool isSteamEngine)
+ {
+ baseCar = car;
+ // Kuju suggested default values
+ // see Eng_and_wag_file_reference_guideV2.doc
+ if (isSteamEngine)
+ {
+ WheelSlip = 0.15;
+ Normal = 0.3;
+ }
+ else
+ {
+ WheelSlip = 0.2;
+ Normal = 0.4;
+ }
+
+ Sanding = 2.0;
+ }
+
+ internal Adhesion(Block block, CarBase car, bool isSteamEngine)
+ {
+ baseCar = car;
+ try
+ {
+ WheelSlip = block.ReadSingle();
+ Normal = block.ReadSingle();
+ Sanding = block.ReadSingle();
+
+ if (Sanding < 0.75 || Normal < 0.05 || WheelSlip < 0.05)
+ {
+ /*
+ * e.g. MT Class 47
+ * If we don't apply at least 75 percent of rated power when *sanding* let alone normally
+ * the ENG file is clearly bugged
+ */
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Discarding implausible Adheasion values");
+ WheelSlip = 0.2;
+ Normal = 0.4;
+ Sanding = 2.0;
+ }
+ }
+ catch
+ {
+ // Kuju suggested default values
+ // see Eng_and_wag_file_reference_guideV2.doc
+ if (isSteamEngine)
+ {
+ WheelSlip = 0.15;
+ Normal = 0.3;
+ }
+ else
+ {
+ WheelSlip = 0.2;
+ Normal = 0.4;
+ }
+
+ Sanding = 2.0;
+ }
+ }
+
+ internal double GetWheelslipValue()
+ {
+ double multiplier;
+ // https://www.trainsim.com/forums/forum/general-discussion/traction/68459-msts-diesel-sanding-effective
+ // MSTS uses a per-axle drive force calculation, so our traction model's force is divided by the number of axles
+ // whereas BVE thinks in terms of the whole car, so for a *hacky* version, we don't need the NumWheels divisor or
+ // the mass, as we're not worrying about mass per axle yet...
+ // Unlikely to be perfect, but doing it this way resolves massive wheelslip issues
+
+ if (baseCar.ReAdhesionDevice is Sanders sanders && sanders.State == SandersState.Active)
+ {
+ // Per-axle:
+ // multiplier = 0.95 * WheelSlip * Sanding * baseCar.CurrentMass / baseCar.DrivingWheels[0].TotalNumber / baseCar.CurrentMass;
+ multiplier = 0.95 * WheelSlip * Sanding;
+ }
+ else
+ {
+ if (!baseCar.FrontAxle.CurrentWheelSlip)
+ {
+ // Per-axle:
+ // multiplier = Normal * Sanding * baseCar.CurrentMass / baseCar.TrailingWheels[0].TotalNumber / baseCar.CurrentMass;
+ multiplier = Normal * Sanding;
+ }
+ else
+ {
+ // Per-axle:
+ // multiplier = Normal * Sanding * baseCar.CurrentMass / baseCar.DrivingWheels[0].TotalNumber / baseCar.CurrentMass;
+ multiplier = WheelSlip * Sanding;
+ }
+ }
+
+ if (baseCar.TractionModel.MaximumPossibleAcceleration == 0)
+ {
+ // no possible acceleration, so can't wheelslip!
+ return double.MaxValue;
+ }
+
+ return baseCar.TractionModel.MaximumPossibleAcceleration * multiplier;
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/ConsistParser.cs b/source/Plugins/Train.MsTs/Train/ConsistParser.cs
new file mode 100644
index 0000000000..53268f2a15
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/ConsistParser.cs
@@ -0,0 +1,394 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using LibRender2.Trains;
+using OpenBve.Formats.MsTs;
+using OpenBveApi.Interface;
+using OpenBveApi.Routes;
+using OpenBveApi.Trains;
+using SharpCompress.Compressors;
+using SharpCompress.Compressors.Deflate;
+using SoundManager;
+using TrainManager.BrakeSystems;
+using TrainManager.Car;
+using TrainManager.Handles;
+using TrainManager.Motor;
+using TrainManager.Power;
+using TrainManager.Trains;
+
+namespace Train.MsTs
+{
+ internal class ConsistParser
+ {
+ internal readonly Plugin Plugin;
+ internal string TrainsetDirectory;
+
+ internal ConsistParser(Plugin plugin)
+ {
+ Plugin = plugin;
+ }
+
+ internal void ReadConsist(string fileName, ref AbstractTrain parsedTrain)
+ {
+ currentCarIndex = -1;
+ TrainBase train = parsedTrain as TrainBase;
+ if (train == null)
+ {
+ throw new Exception();
+ }
+ train.Handles.Reverser = new ReverserHandle(train);
+ train.Handles.EmergencyBrake = new EmergencyHandle(train);
+ train.Handles.Power = new PowerHandle(8, 8, new double[] { }, new double[] { }, train);
+ train.Handles.Brake = new BrakeHandle(8, 8, train.Handles.EmergencyBrake, new double[] { }, new double[] { }, train);
+ train.Handles.LocoBrake = new LocoBrakeHandle(0, train.Handles.EmergencyBrake, new double[] {}, new double[] {}, train);
+ train.Handles.LocoBrakeType = LocoBrakeType.Independant;
+ train.Handles.HasLocoBrake = false;
+ train.Handles.HoldBrake = new HoldBrakeHandle(train);
+ train.Specs.AveragesPressureDistribution = true;
+ train.SafetySystems.Headlights = new LightSource(train, 2);
+ if(Directory.Exists(Plugin.FileSystem.MSTSDirectory))
+ {
+ TrainsetDirectory = OpenBveApi.Path.CombineDirectory(Plugin.FileSystem.MSTSDirectory, "TRAINS\\trainset");
+ }
+ else
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "The MSTS directory has not been set. Attempting to find the trainset directory.");
+ string currentFolder = Path.GetDirectoryName(fileName);
+ if (currentFolder == null)
+ {
+ throw new Exception("MSTS Consist Parser: Unable to determine the consist working directory.");
+ }
+ DirectoryInfo d = Directory.GetParent(currentFolder);
+ if (d == null || !d.Name.Equals("TRAINS", StringComparison.InvariantCultureIgnoreCase))
+ {
+ //FIXME: Better finding of the trainset folder (set in options?)
+ throw new Exception("MSTS Consist Parser: Unable to find the MSTS TRAINS folder.");
+ }
+ TrainsetDirectory = OpenBveApi.Path.CombineDirectory(currentFolder, "trainset");
+ }
+
+ if (!Directory.Exists(TrainsetDirectory))
+ {
+ throw new Exception("MSTS Consist Parser: Unable to find the MSTS trainset folder.");
+ }
+
+ Stream fb = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
+
+ byte[] buffer = new byte[34];
+ fb.Read(buffer, 0, 2);
+
+ bool unicode = buffer[0] == 0xFF && buffer[1] == 0xFE;
+
+ string headerString;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ headerString = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 2, 14);
+ headerString = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+
+ // SIMISA@F means compressed
+ // SIMISA@@ means uncompressed
+ if (headerString.StartsWith("SIMISA@F"))
+ {
+ fb = new ZlibStream(fb, CompressionMode.Decompress);
+ }
+ else if (headerString.StartsWith("\r\nSIMISA"))
+ {
+ // ie us1rd2l1000r10d.s, we are going to allow this but warn
+ Console.Error.WriteLine("Improper header in " + fileName);
+ fb.Read(buffer, 0, 4);
+ }
+ else if (!headerString.StartsWith("SIMISA@@"))
+ {
+ throw new Exception("Unrecognized shape file header " + headerString + " in " + fileName);
+ }
+
+ string subHeader;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ subHeader = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 0, 16);
+ subHeader = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+ if (subHeader[7] == 't')
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ byte[] newBytes = reader.ReadBytes((int)(fb.Length - fb.Position));
+ string s = unicode ? Encoding.Unicode.GetString(newBytes) : Encoding.ASCII.GetString(newBytes);
+ TextualBlock block = new TextualBlock(s, KujuTokenID.Train);
+ ParseBlock(block, ref train);
+ }
+
+ }
+ else if (subHeader[7] != 'b')
+ {
+ throw new Exception("Unrecognized subHeader \"" + subHeader + "\" in " + fileName);
+ }
+ else
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ KujuTokenID currentToken = (KujuTokenID) reader.ReadUInt16();
+ if (currentToken != KujuTokenID.Train)
+ {
+ throw new Exception(); //Shape definition
+ }
+ reader.ReadUInt16();
+ uint remainingBytes = reader.ReadUInt32();
+ byte[] newBytes = reader.ReadBytes((int) remainingBytes);
+ BinaryBlock block = new BinaryBlock(newBytes, KujuTokenID.Train);
+ ParseBlock(block, ref train);
+ }
+ }
+
+ if (train.Cars.Length == 0)
+ {
+ throw new InvalidDataException("Consist " + fileName + " appears to be invalid or malformed");
+ }
+
+ bool hasCabview = false;
+ //create couplers & other necessary properties for the thing to load
+ //TODO: Pull out MSTS properties
+ for (int i = 0; i < train.Cars.Length; i++)
+ {
+ train.Cars[i].Coupler = new Coupler(0.9 * 0.3, 1.1 * 0.3, train.Cars[i / 2], train.Cars.Length > 1 ? train.Cars[i / 2 + 1] : null);
+ train.Cars[i].CurrentCarSection = CarSectionType.NotVisible;
+ train.Cars[i].ChangeCarSection(CarSectionType.NotVisible);
+ train.Cars[i].FrontBogie.ChangeSection(-1);
+ train.Cars[i].RearBogie.ChangeSection(-1);
+ train.Cars[i].Coupler.ChangeSection(-1);
+ train.Cars[i].Specs.ExposedFrontalArea = 0.6 * train.Cars[i].Width * train.Cars[i].Height;
+ train.Cars[i].Specs.UnexposedFrontalArea = 0.2 * train.Cars[i].Width * train.Cars[i].Height;
+ train.Cars[i].Specs.CenterOfGravityHeight = 1.6;
+ train.Cars[i].Specs.CriticalTopplingAngle = 0.5 * Math.PI - Math.Atan(2 * train.Cars[i].Specs.CenterOfGravityHeight / train.Cars[i].Width);
+ if (train.Cars[i].HasInteriorView && hasCabview == false)
+ {
+ // For the minute at least, let's set our driver car to be the first car which has an interior view
+ hasCabview = true;
+ train.DriverCar = i;
+ }
+
+ train.Cars[train.Cars.Length - 1].RearAxle.Follower.TriggerType = i == train.Cars.Length - 1 ? EventTriggerType.RearCarRearAxle : EventTriggerType.OtherCarRearAxle;
+
+ if (train.Cars[i].TractionModel is TenderEngine)
+ {
+ bool hasTender = i > 0 && train.Cars[i - 1].TractionModel is Tender || i < train.Cars.Length - 2 && train.Cars[i + 1].TractionModel is Tender;
+
+ if (hasTender == false)
+ {
+ // this is actually harmless at the minute
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS Consist Parser: Steam Engine in car " + i + " requires a tender, but none is present.");
+ }
+ }
+ }
+
+ train.Cars[train.Cars.Length - 1].RearAxle.Follower.TriggerType = EventTriggerType.RearCarRearAxle;
+ train.Cars[train.DriverCar].Windscreen = new Windscreen(256, 10.0, train.Cars[train.DriverCar]);
+ train.Cars[train.DriverCar].Windscreen.Wipers = new WindscreenWiper(train.Cars[parsedTrain.DriverCar].Windscreen, WiperPosition.Left, WiperPosition.Left, 1.0, 0.0, true); // hack: zero hold time so they act as fast with two states
+ train.Specs.AveragesPressureDistribution = false;
+ train.PlaceCars(0.0);
+ }
+
+ private int currentCarIndex = -1;
+ private CarBase currentCar;
+ private bool reverseCurentCar;
+ private void ParseBlock(Block block, ref TrainBase currentTrain)
+ {
+ Block newBlock;
+ switch (block.Token)
+ {
+ default:
+ while (block.Length() - block.Position() > 2)
+ {
+ // YUCK: If valid wagon blocks are outside the TrainCfg block (incorrect terminator)
+ // MSTS actually adds them to the end of the train, e.g. see default oenoloco.con
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, ref currentTrain);
+ }
+ break;
+ case KujuTokenID.Comment:
+ case KujuTokenID.Default:
+ // presumably used internally by MSTS, not useful
+ block.Skip((int)block.Length());
+ break;
+ case KujuTokenID.Name:
+ string consistName = block.ReadString(); // displayed name for consist in-game
+ break;
+ case KujuTokenID.TrainCfg:
+ string trainName = block.ReadString(); // we're unlikely to want this, as this is just the MSTS internal dictionary key
+ while (block.Length() - block.Position() > 2)
+ {
+ try
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, ref currentTrain);
+ }
+ catch
+ {
+ // ignore
+ }
+ }
+ break;
+ case KujuTokenID.Serial:
+ /*
+ * This identifies the revision number of the consist (e.g. how many times it's been edited using the built-in MSTS tools)
+ * OpenRails ignores it.
+ * Not really helpful for our use-case at the minute.
+ */
+ break;
+ case KujuTokenID.MaxVelocity:
+ // Presumably max speed of the consist (derails over this or something?)
+ break;
+ case KujuTokenID.NextWagonUID:
+ /*
+ * This seems to identify the *next* wagon UID to be used when a train is coupled
+ * Again, OpenRails ignores it.
+ */
+ break;
+ case KujuTokenID.Durability:
+ // Dunno- Presumably used for derailment / similar physics somewhere
+ break;
+ case KujuTokenID.Engine:
+ case KujuTokenID.Wagon:
+ Array.Resize(ref currentTrain.Cars, currentTrain.Cars.Length + 1);
+ currentCarIndex++;
+ while (block.Length() - block.Position() > 2)
+ {
+ newBlock = block.ReadSubBlock(new[] { KujuTokenID.EngineData, KujuTokenID.WagonData, KujuTokenID.UiD, KujuTokenID.Flip, KujuTokenID.EngineVariables });
+ ParseBlock(newBlock, ref currentTrain);
+ }
+ currentCar.Doors = new[]
+ {
+ new Door(-1, 1000.0, 0),
+ new Door(1, 1000.0, 0)
+ };
+ if (reverseCurentCar)
+ {
+ currentCar.Reverse();
+ reverseCurentCar = false;
+ }
+ currentCar.Breaker = new Breaker(currentCar);
+ currentCar.Sounds.Plugin = new Dictionary();
+ currentTrain.Cars[currentCarIndex] = currentCar;
+ /*
+ * FIXME: Needs removing or sorting when the car is created
+ */
+ currentTrain.Cars[currentCarIndex].FrontAxle.Follower.TriggerType = currentCarIndex == 0 ? EventTriggerType.FrontCarFrontAxle : EventTriggerType.OtherCarFrontAxle;
+ currentTrain.Cars[currentCarIndex].BeaconReceiver.TriggerType = currentCarIndex == 0 ? EventTriggerType.TrainFront : EventTriggerType.None;
+ currentTrain.Cars[currentCarIndex].BeaconReceiverPosition = 0.5 * currentTrain.Cars[currentCarIndex].Length;
+ currentTrain.Cars[currentCarIndex].FrontAxle.Position = 0.4 * currentTrain.Cars[currentCarIndex].Length;
+ currentTrain.Cars[currentCarIndex].RearAxle.Position = -0.4 * currentTrain.Cars[currentCarIndex].Length;
+ break;
+ // Engine / wagon block
+ case KujuTokenID.UiD:
+ // Unique ID of engine / wagon within consist
+ // For the minute, let's just create a new car and advance our car number
+ break;
+ case KujuTokenID.WagonData:
+ case KujuTokenID.EngineData:
+ /*
+ * FIXME: All this needs to be pulled from the eng properties, or fixed so it doesn't matter
+ */
+ currentCar = new CarBase(currentTrain, currentCarIndex);
+ currentCar.HoldBrake = new CarHoldBrake(currentCar);
+ //FIXME END
+
+ /*
+ * Pull out the wagon path bits from the block next
+ * From the available documentation and experience this *appears* to be as follows:
+ * [0] - Name of the wagon to search for
+ * [1] - Search path relative to the TRAINS\trainset directory, if not found in DB
+ *
+ * If WagonName that is already in the database, but with a different folder is supplied
+ * then the original will be returned
+ * https://digital-rails.com/wordpress/2018/11/18/duplicate-wagons/
+ *
+ * HOWEVER:
+ * http://www.elvastower.com/forums/index.php?/topic/34187-or-consist-format/
+ * OpenRails seems to treat these as:
+ * [0] - WagonFileName => Must add approprite eng / wag extension
+ * [1] - Search path relative to the TRAINS\trainset directory
+ *
+ * Going to match MSTS for the minute, but possibly needs an OpenRails detection mechanism(?)
+ * Note that in all / most cases, both should be the same anyways.
+ */
+
+ string[] wagonFiles = block.ReadStringArray();
+ switch (wagonFiles.Length)
+ {
+ case 0:
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS Consist Parser: Unable to determine WagonFile to load.");
+ break;
+ case 1:
+ //Just a WagonName- This is likely invalid, but let's ignore
+ Plugin.WagonParser.Parse(TrainsetDirectory, wagonFiles[0], block.Token == KujuTokenID.EngineData, ref currentCar, ref currentTrain);
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS Consist Parser: No WagonFolder supplied, searching entire trainset folder.");
+ break;
+ case 2:
+ string wagonDirectory = OpenBveApi.Path.CombineDirectory(TrainsetDirectory, wagonFiles[1]);
+ if (!Directory.Exists(wagonDirectory))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS Consist Parser: WagonFolder " + wagonDirectory + " was not found.");
+ currentCar.Width = 2.6;
+ currentCar.Height = 3.6;
+ currentCar.Length = 25;
+ currentCar.EmptyMass = 1000;
+ currentCar.TractionModel = new BVETrailerCar(currentCar);
+ currentCar.CarBrake = new ThroughPiped(currentCar); // dummy
+ break;
+ }
+ Plugin.WagonParser.Parse(wagonDirectory, wagonFiles[0], block.Token == KujuTokenID.EngineData, ref currentCar, ref currentTrain);
+ break;
+ default:
+ Plugin.WagonParser.Parse(TrainsetDirectory, wagonFiles[1], block.Token == KujuTokenID.EngineData, ref currentCar, ref currentTrain);
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "MSTS Consist Parser: Two parameters were expected- Check for correct escaping of strings.");
+ break;
+ }
+ break;
+ case KujuTokenID.Flip:
+ // Allows a car to be reversed within a consist
+ reverseCurentCar = true;
+ break;
+ case KujuTokenID.EngineVariables:
+ // Sets properties of the train when loaded, ignore for the minute
+ break;
+ }
+
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/Enums/BrakeEquipmentType.cs b/source/Plugins/Train.MsTs/Train/Enums/BrakeEquipmentType.cs
new file mode 100644
index 0000000000..eb1603eecb
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/Enums/BrakeEquipmentType.cs
@@ -0,0 +1,55 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum BrakeEquipmentType
+ {
+ /// Handbrake is fitted
+ Handbrake = 1,
+ /// Manual brake fitted.
+ Manual_Brake = 2,
+ /// 3 position retaining valve is fitted.
+ Retainer_3_Position = 3,
+ /// 4 position retaining valve is fitted
+ /// This is meant for freight wagons only
+ Retainer_4_Position = 4,
+ /// Twin-pipe vacuum brake is fitted.
+ Vacuum_Brake = 5,
+ Vaccum_Brake = 5,
+ Vacumn_Brake = 5, // typo
+ /// Single-pipe vacuum brake is fitted.
+ Vacuum_Single_Pipe = 6,
+ Vaccum_Single_Pipe = 6,
+ /// Standard triple valve is fitted.
+ Triple_Valve = 7,
+ /// Triple valve that permits partial releasing of the brakes.
+ Graduated_Release_Triple_Valve = 8,
+ Graduate_Release_Triple_valve = 8, // typo
+ /// Electrically controlled brake system is fitted. Release and application of the brakes are independently controlled.
+ EP_Brake = 9,
+ EP_Brakes = 9,
+ /// Same functionality as ep_brake
+ ECP_Brake = 10,
+ /// Air tank used for normal service brake applications. This is required for all brake systems.
+ Auxiliary_Reservoir = 11,
+ Auxilary_Reservoir = 11, // typo
+ /// Air tank used for emergency applications.
+ /// This is optional.
+ Emergency_Brake_Reservoir = 12,
+ /// Electronic or computer controller on the vehicle that can be set to independently control any parameter of the braking system.
+ Distributor = 13,
+ /// One pipe controls and supplies the air brakes.
+ Air_Single_Pipe = 14,
+ /// One pipe for control air, one pipe for supply air
+ Air_Twin_Pipe = 15,
+ Air_Brake = 15,
+ /// Graduated triple-release valve
+ Graduated_Triple_Release_Valve = 16,
+ /// Through piped for vacuum
+ Vacuum_Piped = 17,
+ /// Through piped for air
+ Air_Piped = 18,
+ /// Brake reservoir for emergency brakes only
+ Emergency_reservoir = 19
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/Enums/BrakeSystemType.cs b/source/Plugins/Train.MsTs/Train/Enums/BrakeSystemType.cs
new file mode 100644
index 0000000000..d6bf893c61
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/Enums/BrakeSystemType.cs
@@ -0,0 +1,34 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum BrakeSystemType
+ {
+ /// One pipe controls and supplies the air brakes.
+ Air_single_pipe,
+ /// Two pipes are used. One to control the brakes, the other to charge the reserviors.
+ Air_twin_pipe,
+ /// The car uses a manual braking system.
+ Manual_Braking,
+ /// One pipe is used to supply and control the vacuum brakes.
+ Vacuum_single_pipe,
+ Vaccum_single_pipe = Vacuum_single_pipe,
+ Vacumn_single_pipe = Vaccum_single_pipe,
+ /// Two pipes are used. One controls the vacuum brakes, the other supply the vacuum reservior.
+ Vacuum_twin_pipe,
+ Vaccum_twin_pipe = Vacuum_twin_pipe,
+ /// The brakes are controlled by a computer or complex electrical control system.
+ ECP,
+ /// The brakes are a combination of standard air brakes and electrical control signals.
+ EP,
+ EP_Brake = EP,
+ /// The vehicle has no brakes
+ /// Air pipe pressure will be passed through this vehicle
+ Air_Piped,
+ /// The vehicle has no brakes
+ /// Vacuum pipe pressure will be passed through this vehicle
+ Vacuum_Piped,
+ /// The vehicle has a handbrake
+ Handbrake
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/Enums/ControlType.cs b/source/Plugins/Train.MsTs/Train/Enums/ControlType.cs
new file mode 100644
index 0000000000..763996fabd
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/Enums/ControlType.cs
@@ -0,0 +1,19 @@
+// ReSharper disable UnusedMember.Global
+namespace Train.MsTs
+{
+ internal enum CombinedControlType
+ {
+ /// Unknown control type
+ Unknown = 0,
+ /// Throttle handle
+ Throttle = 1,
+ /// Dynamic brake handle
+ Dynamic = 2,
+ /// Independant brake handle
+ Independent = 3,
+ /// Independant brake handle
+ Independant = 3,
+ /// Train brake handle
+ Train = 4
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/Friction.cs b/source/Plugins/Train.MsTs/Train/Friction.cs
new file mode 100644
index 0000000000..989d681921
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/Friction.cs
@@ -0,0 +1,98 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using OpenBve.Formats.MsTs;
+using OpenBveApi.Interface;
+using OpenBveApi.World;
+
+namespace Train.MsTs
+{
+ internal class Friction
+ {
+ /// The friction constant
+ internal double C1;
+ /// The friction exponent
+ internal double E1;
+ /// The second velocity segment start value
+ internal double V2;
+ /// The second friction constant
+ internal double C2;
+ /// The second friction exponent
+ internal double E2;
+
+ internal Friction()
+ {
+ C1 = 100;
+ E1 = 1;
+ V2 = -1;
+ C2 = 0;
+ E2 = 1;
+ }
+
+ internal Friction(Block block)
+ {
+ try
+ {
+ C1 = block.ReadSingle(UnitOfTorque.NewtonMetersPerSecond);
+ E1 = block.ReadSingle();
+ V2 = block.ReadSingle(UnitOfVelocity.MetersPerSecond);
+ C2 = block.ReadSingle(UnitOfTorque.NewtonMetersPerSecond);
+ E2 = block.ReadSingle();
+
+ if (E1 <= 0 || E2 <= 0 || V2 < 0)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: The Friction properties contain nonsensical data.");
+ C1 = 100;
+ E1 = 1;
+ V2 = -1;
+ C2 = 0;
+ E2 = 1;
+ }
+ }
+ catch
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: The Friction properties contain invalid data.");
+ C1 = 100;
+ E1 = 1;
+ V2 = -1;
+ C2 = 0;
+ E2 = 1;
+ }
+
+ }
+
+ internal double GetResistanceValue(double speed)
+ {
+ // see Eng_and_wag_file_reference_guideV2.doc
+ // Gives the result in newton-meters per second
+ if (V2 < 0 || speed <= V2)
+ {
+ return C1 * Math.Pow(speed, E1);
+ }
+
+ return C1 + Math.Pow(V2, E1) + C2 * (V2 + Math.Pow(speed - V2, E2));
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/MSTSAxle.cs b/source/Plugins/Train.MsTs/Train/MSTSAxle.cs
new file mode 100644
index 0000000000..b16e619608
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/MSTSAxle.cs
@@ -0,0 +1,62 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using OpenBveApi.Hosts;
+using OpenBveApi.Trains;
+
+namespace Train.MsTs
+{
+ /// Derived class for axles on MSTS cars
+ public class MSTSAxle : AbstractAxle
+ {
+ /// The friction properties
+ private readonly Friction FrictionProperties;
+ /// The adhesion properties
+ private readonly Adhesion AdhesionProperties;
+
+ internal MSTSAxle(HostInterface currentHost, AbstractTrain train, AbstractCar car, Friction friction, Adhesion adhesion) : base(currentHost, train, car)
+ {
+ FrictionProperties = friction;
+ AdhesionProperties = adhesion;
+ }
+
+ public override double GetResistance(double Speed, double FrontalArea, double AirDensity, double AccelerationDueToGravity)
+ {
+ return FrictionProperties.GetResistanceValue(Speed) / Math.Max(1.0, baseCar.CurrentMass);
+ }
+
+ public override double CriticalWheelSlipAccelerationForElectricMotor(double AccelerationDueToGravity)
+ {
+ return AdhesionProperties.GetWheelslipValue();
+ }
+
+ public override double CriticalWheelSlipAccelerationForFrictionBrake(double AccelerationDueToGravity)
+ {
+ // TODO: This is the BVE formula
+ double NormalForceAcceleration = Follower.WorldUp.Y * AccelerationDueToGravity;
+ return 0.35 * Follower.AdhesionMultiplier * NormalForceAcceleration;
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Train/VehicleParser.cs b/source/Plugins/Train.MsTs/Train/VehicleParser.cs
new file mode 100644
index 0000000000..d977feab33
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Train/VehicleParser.cs
@@ -0,0 +1,1185 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using LibRender2.Smoke;
+using LibRender2.Trains;
+using OpenBve.Formats.MsTs;
+using OpenBveApi.Interface;
+using OpenBveApi.Math;
+using OpenBveApi.Motor;
+using OpenBveApi.Objects;
+using OpenBveApi.Trains;
+using OpenBveApi.World;
+using SharpCompress.Compressors;
+using SharpCompress.Compressors.Deflate;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using TrainManager.BrakeSystems;
+using TrainManager.Car;
+using TrainManager.Car.Systems;
+using TrainManager.Handles;
+using TrainManager.Motor;
+using TrainManager.Power;
+using TrainManager.Trains;
+
+namespace Train.MsTs
+{
+ internal partial class WagonParser
+ {
+ private readonly Dictionary wagonCache;
+ private readonly Dictionary engineCache;
+ private readonly List soundFiles;
+ private string[] wagonFiles;
+ private double wheelRadius;
+ private bool exteriorLoaded = false;
+ private bool RequiresTender = false;
+ private bool EngineAlreadyParsed = false;
+
+ internal WagonParser()
+ {
+ wagonCache = new Dictionary();
+ engineCache = new Dictionary();
+ soundFiles = new List();
+ }
+
+ internal void Parse(string trainSetDirectory, string wagonName, bool isEngine, ref CarBase currentCar, ref TrainBase train)
+ {
+ /*
+ * Reset to 'sensible' defaults for required parameters
+ * => International Union of Railways figure for 'standard' wheel size
+ * => Default BVE brake system parameters (we know these work correctly)
+ * => Reset gearbox parameters
+ * => Set max force figures to zero
+ */
+ wheelRadius = 0.92;
+ mainReservoirMinimumPressure = 690000;
+ mainReservoirMaximumPressure = 780000;
+ brakeCylinderMaximumPressure = 440000;
+ compressionRate = 3500;
+ maxForce = 0;
+ maxBrakeForce = 0;
+ Gears = null;
+ exteriorLoaded = false;
+ wagonFiles = Directory.GetFiles(trainSetDirectory, isEngine ? "*.eng" : "*.wag", SearchOption.AllDirectories);
+ currentEngineType = EngineType.NoEngine;
+ /*
+ * MSTS maintains an internal database, as opposed to using full paths
+ * Unfortunately, this means we've got to do an approximation of the same thing!
+ * (TrainStore is / was an early MSTS attempt to deal with the same problem by moving
+ * excess eng, wag and con files out from the MSTS directory)
+ *
+ * Unclear at the minute as to whether an eng can refer to a *separate* wag file, but
+ * unless documentation specifically states otherwise, we'll assume it can
+ *
+ * So, the *first* thing we need to do is to read the engine (as this may
+ * refer to a different sub-wagon):
+ */
+ if (isEngine)
+ {
+ if (engineCache.ContainsKey(wagonName))
+ {
+ ReadWagonData(engineCache[wagonName], ref wagonName, true, ref currentCar, ref train);
+ }
+ else
+ {
+ for (int i = 0; i < wagonFiles.Length; i++)
+ {
+ if (ReadWagonData(wagonFiles[i], ref wagonName, true, ref currentCar, ref train))
+ {
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ currentCar.TractionModel = new BVETrailerCar(currentCar);
+ }
+ /*
+ * We've now found the engine properties-
+ * Now, we need to read the wagon properties to find the visual wagon to display
+ * (The Engine only holds the physics data)
+ */
+ if (wagonCache.ContainsKey(wagonName))
+ {
+ ReadWagonData(wagonCache[wagonName], ref wagonName, false, ref currentCar, ref train);
+ }
+ else
+ {
+ for (int i = 0; i < wagonFiles.Length; i++)
+ {
+ if (ReadWagonData(wagonFiles[i], ref wagonName, false, ref currentCar, ref train))
+ {
+ break;
+ }
+ }
+ }
+
+ // as properties may not be in order, set this stuff last
+ if (isEngine)
+ {
+ EngineAlreadyParsed = true;
+ // FIXME: Default BVE values
+ currentCar.Specs.JerkPowerUp = 10.0;
+ currentCar.Specs.JerkPowerDown = 10.0;
+ if (currentCar.DrivingWheels.Count == 0)
+ {
+ // An engine must implicity have at least one set of driving wheels
+ currentCar.DrivingWheels.Add(new Wheels(1, wheelRadius));
+ }
+ // NOTE: Amps figure appears to need to be divided by the total wheels (to give a per-axle figure)
+ // see NWC_40138.eng for example- This is an issue where higher amps figures are in play
+ maxEngineAmps /= currentCar.DrivingWheels[0].TotalNumber;
+ maxBrakeAmps /= currentCar.DrivingWheels[0].TotalNumber;
+
+ switch (currentEngineType)
+ {
+ case EngineType.Diesel:
+ currentCar.TractionModel = new DieselEngine(currentCar, new AccelerationCurve[] { new MSTSAccelerationCurve(currentCar, maxForce, maxContinuousForce, maxVelocity) }, dieselIdleRPM, dieselIdleRPM, dieselMaxRPM, dieselRPMChangeRate, dieselRPMChangeRate, dieselIdleUse, dieselMaxUse);
+ currentCar.TractionModel.FuelTank = new FuelTank(GetMaxDieselCapacity(currentCar.Index));
+ currentCar.TractionModel.IsRunning = true;
+
+ if (maxBrakeAmps > 0 && maxEngineAmps > 0)
+ {
+ currentCar.TractionModel.Components.Add(EngineComponent.RegenerativeTractionMotor, new RegenerativeTractionMotor(currentCar.TractionModel, maxEngineAmps, maxBrakeAmps));
+ }
+ else if (maxEngineAmps > 0)
+ {
+ currentCar.TractionModel.Components.Add(EngineComponent.TractionMotor, new TractionMotor(currentCar.TractionModel, maxEngineAmps));
+ }
+ break;
+ case EngineType.DieselHydraulic:
+ AccelerationCurve[] accelerationCurves = new AccelerationCurve[Gears.Length];
+ for (int i = 0; i < Gears.Length; i++)
+ {
+ accelerationCurves[i] = new MSTSAccelerationCurve(currentCar, Gears[i].MaxTractiveForce, maxContinuousForce, Gears[i].MaximumSpeed);
+ }
+
+ currentCar.TractionModel = new DieselEngine(currentCar, accelerationCurves, dieselIdleRPM, dieselIdleRPM, dieselMaxRPM, dieselRPMChangeRate, dieselRPMChangeRate, dieselIdleUse, dieselMaxUse);
+ currentCar.TractionModel.FuelTank = new FuelTank(GetMaxDieselCapacity(currentCar.Index));
+ currentCar.TractionModel.IsRunning = true;
+ currentCar.TractionModel.Components.Add(EngineComponent.Gearbox, new Gearbox(currentCar.TractionModel, Gears, gearboxOperationMode));
+ break;
+ case EngineType.Electric:
+ currentCar.TractionModel = new ElectricEngine(currentCar, new AccelerationCurve[] { new MSTSAccelerationCurve(currentCar, maxForce, maxContinuousForce, maxVelocity) });
+ currentCar.TractionModel.Components.Add(EngineComponent.Pantograph, new Pantograph(currentCar.TractionModel));
+
+ if (maxBrakeAmps > 0 && maxEngineAmps > 0)
+ {
+ currentCar.TractionModel.Components.Add(EngineComponent.RegenerativeTractionMotor, new RegenerativeTractionMotor(currentCar.TractionModel, maxEngineAmps, maxBrakeAmps));
+ }
+ else if (maxEngineAmps > 0)
+ {
+ currentCar.TractionModel.Components.Add(EngineComponent.TractionMotor, new TractionMotor(currentCar.TractionModel, maxEngineAmps));
+ }
+ break;
+ case EngineType.Steam:
+ // NOT YET IMPLEMENTED FULLY
+ if (RequiresTender)
+ {
+ currentCar.TractionModel = new TenderEngine(currentCar, new AccelerationCurve[] { new MSTSAccelerationCurve(currentCar, maxForce, maxContinuousForce, maxVelocity) });
+ if (currentCar.Index > 0)
+ {
+ CarBase previousCar = currentCar.baseTrain.Cars[currentCar.Index - 1];
+ if (previousCar.TractionModel is Tender tender && tender.MaxWaterLevel == -1)
+ {
+ // recreate, as values are stored in the ENG
+ previousCar.TractionModel = new Tender(previousCar, MaxFuelLevel, MaxWaterLevel);
+ }
+ }
+ }
+ else
+ {
+ currentCar.TractionModel = new TankEngine(currentCar, new AccelerationCurve[] { new MSTSAccelerationCurve(currentCar, maxForce, maxContinuousForce, maxVelocity) }, MaxFuelLevel, MaxWaterLevel);
+ }
+ break;
+ case EngineType.NoEngine:
+ currentCar.TractionModel = new BVETrailerCar(currentCar);
+ break;
+ }
+
+ if (currentCar.ReAdhesionDevice == null)
+ {
+ currentCar.ReAdhesionDevice = new BveReAdhesionDevice(currentCar, hasAntiSlipDevice ? ReadhesionDeviceType.TypeB : ReadhesionDeviceType.NotFitted);
+ }
+
+ currentCar.Windscreen = new Windscreen(0, 0, currentCar);
+ currentCar.Windscreen.Wipers = new WindscreenWiper(currentCar.Windscreen, WiperPosition.Left, WiperPosition.Left, 1.0, 1.0);
+
+ if (Exhaust.Size > 0)
+ {
+ Exhaust.Offset.Z -= 0.5 * currentCar.Length;
+ currentCar.ParticleSources.Add(new ParticleSource(Plugin.Renderer, currentCar, Exhaust.Offset, Exhaust.Size, Exhaust.SmokeMaxMagnitude, Exhaust.Direction));
+ }
+ }
+ else
+ {
+ if (currentWagonType == WagonType.Tender)
+ {
+ currentCar.TractionModel = new Tender(currentCar, MaxFuelLevel, MaxWaterLevel);
+ }
+
+ if (currentCar.TrailingWheels.Count == 0)
+ {
+ // non-engine must implicitly have at least one set of trailing wheels
+ currentCar.TrailingWheels.Add(new Wheels(1, wheelRadius));
+ }
+ }
+
+ if (brakeSystemTypes != null)
+ {
+
+ // Add brakes last, as we need the acceleration values
+ if (brakeSystemTypes.Contains(BrakeSystemType.Vacuum_Piped) || brakeSystemTypes.Contains(BrakeSystemType.Air_Piped) || (brakeSystemTypes.Length == 1 && brakeSystemTypes[0] == BrakeSystemType.Handbrake))
+ {
+ /*
+ * FIXME: Need to implement vac braked / air piped and vice-versa, but for the minute, we'll assume that if one or the other is present
+ * then the vehicle has no brakes
+ */
+ currentCar.CarBrake = new ThroughPiped(currentCar);
+ }
+ else
+ {
+ if (brakeSystemTypes.Contains(BrakeSystemType.Air_single_pipe) || brakeSystemTypes.Contains(BrakeSystemType.Air_twin_pipe) || brakeSystemTypes.Contains(BrakeSystemType.EP) || brakeSystemTypes.Contains(BrakeSystemType.ECP))
+ {
+ AirBrake airBrake;
+ // FIXME: Relationship of brake system values needs to be (close) to original proportions else the physics bug out
+ double bcVal = brakeCylinderMaximumPressure / 440000;
+ double emergencyVal = emergencyRate / 300000.0;
+ double releaseVal = releaseRate / 200000.0;
+ mainReservoirMinimumPressure = 690000.0 * bcVal;
+ mainReservoirMaximumPressure = 780000.0 * bcVal;
+ double operatingPressure = brakeCylinderMaximumPressure + 0.75 * (mainReservoirMinimumPressure - brakeCylinderMaximumPressure);
+
+ if (brakeSystemTypes.Contains(BrakeSystemType.EP) || brakeSystemTypes.Contains(BrakeSystemType.ECP))
+ {
+ // Combined air brakes and control signals
+ // Assume equivilant to ElectromagneticStraightAirBrake
+ airBrake = new ElectromagneticStraightAirBrake(EletropneumaticBrakeType.None, currentCar, 0, 0, 0, 0, new AccelerationCurve[] { new MSTSDecelerationCurve(train, maxBrakeForce == 0 ? maxForce : maxBrakeForce) });
+ airBrake.BrakePipe = new BrakePipe(operatingPressure, 10000000.0, 1500000.0, 5000000.0, true);
+ }
+ else
+ {
+ // Assume equivilant to ElectromagneticStraightAirBrake
+ airBrake = new ElectromagneticStraightAirBrake(EletropneumaticBrakeType.None, currentCar, 0, 0, 0, 0, new AccelerationCurve[] { new MSTSDecelerationCurve(train, maxBrakeForce == 0 ? maxForce : maxBrakeForce) });
+ airBrake.BrakePipe = new BrakePipe(operatingPressure, 10000000.0, 1500000.0, 5000000.0, false);
+ }
+
+ airBrake.MainReservoir = new MainReservoir(mainReservoirMinimumPressure, mainReservoirMaximumPressure, 0.01, 0.075 / train.Cars.Length);
+ airBrake.Compressor = new Compressor(5000.0, airBrake.MainReservoir, currentCar);
+ airBrake.BrakeCylinder = new BrakeCylinder(brakeCylinderMaximumPressure, brakeCylinderMaximumPressure * 1.1, 90000.0, emergencyRate, releaseRate);
+ double r = 200000.0 / airBrake.BrakeCylinder.EmergencyMaximumPressure - 1.0;
+ if (r < 0.1) r = 0.1;
+ if (r > 1.0) r = 1.0;
+ airBrake.AuxiliaryReservoir = new AuxiliaryReservoir(0.975 * operatingPressure, 200000.0, 0.5, r);
+ airBrake.EqualizingReservoir = new EqualizingReservoir(50000.0, 250000.0, 200000.0);
+ airBrake.EqualizingReservoir.NormalPressure = 1.005 * operatingPressure;
+ airBrake.StraightAirPipe = new StraightAirPipe(300000.0, emergencyRate * emergencyVal, releaseRate * releaseVal);
+
+ currentCar.CarBrake = airBrake;
+ }
+
+ if (brakeSystemTypes.Contains(BrakeSystemType.Vaccum_single_pipe) || brakeSystemTypes.Contains(BrakeSystemType.Vacuum_twin_pipe))
+ {
+ VaccumBrake vaccumBrake = new VaccumBrake(currentCar, new AccelerationCurve[] { new MSTSDecelerationCurve(train, maxBrakeForce == 0 ? maxForce : maxBrakeForce) });
+ vaccumBrake.MainReservoir = new MainReservoir(71110, 84660, 0.01, 0.075 / train.Cars.Length); // ~21in/hg - ~25in/hg
+ vaccumBrake.BrakeCylinder = new BrakeCylinder(brakeCylinderMaximumPressure, brakeCylinderMaximumPressure * 1.1, 90000.0, 300000.0, 200000.0);
+ vaccumBrake.AuxiliaryReservoir = new AuxiliaryReservoir(0.975 * brakeCylinderMaximumPressure, 200000.0, 0.5, 1.0);
+ vaccumBrake.EqualizingReservoir = new EqualizingReservoir(50000.0, 250000.0, 200000.0);
+ vaccumBrake.EqualizingReservoir.NormalPressure = 1.005 * (vaccumBrake.BrakeCylinder.EmergencyMaximumPressure + 0.75 * (vaccumBrake.MainReservoir.MinimumPressure - vaccumBrake.BrakeCylinder.EmergencyMaximumPressure));
+ vaccumBrake.BrakePipe = new BrakePipe(brakeCylinderMaximumPressure, 10000000.0, 1500000.0, 5000000.0, false);
+ currentCar.CarBrake = vaccumBrake;
+ }
+
+ currentCar.CarBrake.BrakeType = currentCar.Index == train.DriverCar || isEngine ? BrakeType.Main : BrakeType.Auxiliary;
+ currentCar.CarBrake.JerkUp = 10;
+ currentCar.CarBrake.JerkDown = 10;
+ }
+
+ currentCar.CarBrake.Initialize(TrainStartMode.ServiceBrakesAts);
+ }
+ else
+ {
+ currentCar.CarBrake = new ThroughPiped(currentCar);
+ }
+
+ currentCar.FrontAxle = new MSTSAxle(Plugin.CurrentHost, train, currentCar, friction ?? new Friction(), adhesion ?? new Adhesion(currentCar, currentEngineType == EngineType.Steam));
+ currentCar.RearAxle = new MSTSAxle(Plugin.CurrentHost, train, currentCar, friction ?? new Friction(), adhesion ?? new Adhesion(currentCar, currentEngineType == EngineType.Steam));
+
+ if (soundFiles.Count > 0)
+ {
+ for (int i = 0; i < soundFiles.Count; i++)
+ {
+ SoundModelSystemParser.ParseSoundFile(soundFiles[i], ref currentCar);
+ }
+ soundFiles.Clear();
+ }
+ }
+
+ internal bool ReadWagonData(string fileName, ref string wagonName, bool isEngine, ref CarBase car, ref TrainBase train)
+ {
+ Stream fb = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
+ vigilanceDevices = new List();
+ byte[] buffer = new byte[34];
+ fb.Read(buffer, 0, 2);
+
+ bool unicode = buffer[0] == 0xFF && buffer[1] == 0xFE;
+
+ string headerString;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ headerString = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 2, 14);
+ headerString = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+
+ // SIMISA@F means compressed
+ // SIMISA@@ means uncompressed
+ if (headerString.StartsWith("SIMISA@F"))
+ {
+ fb = new ZlibStream(fb, CompressionMode.Decompress);
+ }
+ else if (headerString.StartsWith("\r\nSIMISA"))
+ {
+ // ie us1rd2l1000r10d.s, we are going to allow this but warn
+ Console.Error.WriteLine("Improper header in " + fileName);
+ fb.Read(buffer, 0, 4);
+ }
+ else if (!headerString.StartsWith("SIMISA@@"))
+ {
+ throw new Exception("MSTS Vehicle Parser: Unrecognized vehicle file header " + headerString + " in " + fileName);
+ }
+
+ string subHeader;
+ if (unicode)
+ {
+ fb.Read(buffer, 0, 32);
+ subHeader = Encoding.Unicode.GetString(buffer, 0, 16);
+ }
+ else
+ {
+ fb.Read(buffer, 0, 16);
+ subHeader = Encoding.ASCII.GetString(buffer, 0, 8);
+ }
+ if (subHeader[7] == 't')
+ {
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ byte[] newBytes = reader.ReadBytes((int)(fb.Length - fb.Position));
+ string s = unicode ? Encoding.Unicode.GetString(newBytes) : Encoding.ASCII.GetString(newBytes);
+
+ /*
+ * Engine files contain two blocks, not in an enclosing block
+ * Assume that these can be of arbritrary order, so read using a dictionary
+ */
+ List blocks = TextualBlock.ReadBlocks(s);
+
+ List wagonBlocks = blocks.Where(b => b.Token == KujuTokenID.Wagon).ToList();
+ List engineBlocks = blocks.Where(b => b.Token == KujuTokenID.Engine).ToList();
+
+ if (wagonBlocks.Count == 0)
+ {
+ //Not found any wagon data in this file
+ return false;
+ }
+ if (isEngine && engineBlocks.Count > 0)
+ {
+ if (engineBlocks.Count > 1)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Multiple engine blocks encounted in MSTS ENG file "+ fileName);
+ }
+ return ParseBlock(engineBlocks[0], fileName, ref wagonName, true, ref car, ref train);
+ }
+ if (!isEngine && wagonBlocks.Count > 0)
+ {
+ if (wagonBlocks.Count > 1)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Multiple wagon blocks encounted in MSTS WAG file " + fileName);
+ }
+ return ParseBlock(wagonBlocks[0], fileName, ref wagonName, false, ref car, ref train);
+ }
+ return false;
+ }
+
+ }
+ if (subHeader[7] != 'b')
+ {
+ throw new Exception("Unrecognized subHeader \"" + subHeader + "\" in " + fileName);
+ }
+
+ using (BinaryReader reader = new BinaryReader(fb))
+ {
+ KujuTokenID currentToken = (KujuTokenID) reader.ReadUInt16();
+ if (currentToken != KujuTokenID.Wagon)
+ {
+ throw new Exception(); //Shape definition
+ }
+ reader.ReadUInt16();
+ uint remainingBytes = reader.ReadUInt32();
+ byte[] newBytes = reader.ReadBytes((int) remainingBytes);
+ BinaryBlock block = new BinaryBlock(newBytes, KujuTokenID.Wagon);
+ try
+ {
+ ParseBlock(block, fileName, ref wagonName, isEngine, ref car, ref train);
+ }
+ catch (InvalidDataException)
+ {
+ return false;
+ }
+
+ }
+ return true;
+ }
+
+ private double maxForce = 0;
+ private double maxContinuousForce = 0;
+ private double maxBrakeForce = 0;
+ private BrakeSystemType[] brakeSystemTypes;
+ private EngineType currentEngineType;
+ private WagonType currentWagonType;
+ private double dieselIdleRPM;
+ private double dieselMaxRPM;
+ private double dieselRPMChangeRate;
+ private double dieselIdleUse;
+ private double dieselMaxUse;
+ private double dieselCapacity;
+ private double dieselMaxTractiveEffortSpeed;
+ private double maxEngineAmps;
+ private double maxBrakeAmps;
+ private double mainReservoirMinimumPressure = 690000.0;
+ private double mainReservoirMaximumPressure = 780000.0;
+ private double brakeCylinderMaximumPressure = 440000.0;
+ private double emergencyRate;
+ private double releaseRate;
+ private double compressionRate = 3500;
+ private double maxVelocity;
+ private bool hasAntiSlipDevice;
+ private List vigilanceDevices;
+ private Exhaust Exhaust;
+ private Gear[] Gears;
+ private GearboxOperation gearboxOperationMode = GearboxOperation.Manual;
+ private double maxSandingSpeed;
+ private CouplingType couplingType;
+ private Friction friction;
+ private Adhesion adhesion;
+ private UnitOfPressure brakeSystemDefaultUnits = UnitOfPressure.PoundsPerSquareInch;
+ private double MaxWaterLevel = -1;
+ private double MaxFuelLevel = -1;
+
+ private double GetMaxDieselCapacity(int carIndex)
+ {
+ if (dieselCapacity <= 0 && MaxFuelLevel > 0)
+ {
+ return MaxFuelLevel; // if zero capacity, try the figure from EngineVariables
+ }
+
+ if (dieselCapacity == 0)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Diesel locomotive for car " + carIndex + " appears to have zero fuel capacity.");
+ }
+ return dieselCapacity;
+ }
+
+ private bool ParseBlock(Block block, string fileName, ref string wagonName, bool isEngine, ref CarBase car, ref TrainBase train)
+ {
+ Block newBlock;
+ switch (block.Token)
+ {
+ case KujuTokenID.Wagon:
+ string name = block.ReadString().Trim();
+ if (isEngine)
+ {
+ // Within an Engine block, the Wagon block defines the visual wagon to display
+ wagonName = name;
+ }
+ else
+ {
+ if (!name.Equals(wagonName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (!wagonCache.ContainsKey(name))
+ {
+ // CHECK: How do MSTS / OR mediate between files with the same key
+ wagonCache.Add(name, fileName);
+ }
+ return false;
+ }
+ while (block.Length() - block.Position() > 2)
+ {
+ try
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, false, ref car, ref train);
+ }
+ catch
+ {
+ //ignore
+ }
+ }
+ }
+ break;
+ case KujuTokenID.Engine:
+ name = block.ReadString().Trim();
+ if (!name.Equals(wagonName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (!engineCache.ContainsKey(name))
+ {
+ // CHECK: How do MSTS / OR mediate between files with the same key
+ engineCache.Add(name, fileName);
+ }
+ return false;
+ }
+ while (block.Length() - block.Position() > 2)
+ {
+ try
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, isEngine, ref car, ref train);
+ }
+ catch
+ {
+ //ignore
+ }
+ }
+ break;
+ case KujuTokenID.Type:
+ switch (block.ParentBlock.Token)
+ {
+ case KujuTokenID.Engine:
+ case KujuTokenID.Wagon:
+ if (isEngine)
+ {
+ currentEngineType = block.ReadEnumValue(default(EngineType));
+ }
+ else
+ {
+ try
+ {
+ currentWagonType = block.ReadEnumValue(default(WagonType));
+ }
+ catch
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Invalid vehicle type specified.");
+ }
+ }
+ break;
+ case KujuTokenID.Coupling:
+ couplingType = block.ReadEnumValue(default(CouplingType));
+ break;
+ }
+ break;
+ case KujuTokenID.DieselEngineType:
+ if (currentEngineType == EngineType.Diesel)
+ {
+ string type = block.ReadString();
+ switch (type.ToLowerInvariant())
+ {
+ case "hydraulic":
+ currentEngineType = EngineType.DieselHydraulic;
+ break;
+ }
+ }
+ else
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Invalid vehicle type specified.");
+ }
+ break;
+ case KujuTokenID.WagonShape:
+ if(Plugin.PreviewOnly)
+ {
+ break;
+ }
+ // Loads exterior object
+ string objectFile = OpenBveApi.Path.CombineFile(Path.GetDirectoryName(fileName), block.ReadString());
+ if (!File.Exists(objectFile))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Vehicle object file " + objectFile + " was not found");
+ return true;
+ }
+
+ for (int i = 0; i < Plugin.CurrentHost.Plugins.Length; i++)
+ {
+
+ if (Plugin.CurrentHost.Plugins[i].Object != null && Plugin.CurrentHost.Plugins[i].Object.CanLoadObject(objectFile))
+ {
+ Plugin.CurrentHost.Plugins[i].Object.LoadObject(objectFile, Path.GetDirectoryName(fileName), Encoding.Default, out UnifiedObject carObject);
+ if (exteriorLoaded)
+ {
+ CarSection exteriorCarSection = car.CarSections[CarSectionType.Exterior];
+ exteriorCarSection.AppendObject(Plugin.CurrentHost, Vector3.Zero, car, carObject);
+ car.CarSections[CarSectionType.Exterior] = exteriorCarSection;
+ }
+ else
+ {
+ car.CarSections.Add(CarSectionType.Exterior, new CarSection(Plugin.CurrentHost, ObjectType.Dynamic, false, car, carObject));
+ }
+ break;
+ }
+ }
+
+ exteriorLoaded = true;
+ break;
+ case KujuTokenID.Size:
+ // Physical size of the car
+ car.Width = block.ReadSingle(UnitOfLength.Meter);
+ if (car.Width <= 0.1) // see for example LU1938TS - typo makes the car 2.26mm high
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Vehicle width is invalid.");
+ car.Width = 2;
+ }
+ car.Height = block.ReadSingle(UnitOfLength.Meter);
+ if (car.Height <= 0.1)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Vehicle height is invalid.");
+ car.Height = 2;
+ }
+ car.Length = block.ReadSingle(UnitOfLength.Meter);
+ if (car.Length <= 0.5)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Vehicle length is invalid.");
+ car.Length = 25;
+ }
+ break;
+ case KujuTokenID.Mass:
+ // Sets the empty mass of the car
+ car.EmptyMass = block.ReadSingle(UnitOfWeight.Kilograms);
+ break;
+ case KujuTokenID.BrakeEquipmentType:
+ // Determines the brake equipment types available
+ BrakeEquipmentType[] brakeEquipmentTypes = block.ReadEnumArray(default(BrakeEquipmentType));
+ break;
+ case KujuTokenID.BrakeSystemType:
+ // Determines the brake system types available
+ brakeSystemTypes = block.ReadEnumArray(default(BrakeSystemType));
+ // WARNING: If vehicle only has vac brakes, default parameters for brake system are in/hg
+ // otherwise, default parameters are psi
+ bool hasAirBrakes = false;
+ for (int i = 0; i < brakeSystemTypes.Length; i++)
+ {
+ switch (brakeSystemTypes[i])
+ {
+ case BrakeSystemType.Air_single_pipe:
+ case BrakeSystemType.Air_twin_pipe:
+ case BrakeSystemType.EP:
+ case BrakeSystemType.ECP:
+ hasAirBrakes = true;
+ break;
+ }
+ }
+
+ if (!hasAirBrakes)
+ {
+ brakeSystemDefaultUnits = UnitOfPressure.InchesOfMercury;
+ }
+ break;
+ case KujuTokenID.CabView:
+ // Loads cab view file
+ if (Plugin.PreviewOnly)
+ {
+ break;
+ }
+ string cabViewFile = OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(Path.GetDirectoryName(fileName), "CABVIEW"), block.ReadString());
+ if (!File.Exists(cabViewFile))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Cab view file " + cabViewFile + " was not found");
+ return true;
+ }
+
+ CabviewFileParser.ParseCabViewFile(cabViewFile, ref car);
+ car.HasInteriorView = true;
+ break;
+ case KujuTokenID.Description:
+ /*
+ * Only I believe valid in ENG files
+ * NOTE: For some reason, the array appears to be as lines, however it also contains the newline character
+ * Binary format??
+ */
+ string[] strings = block.ReadStringArray();
+ car.Description = string.Join("", strings).Replace(@"\n", Environment.NewLine);
+ break;
+ case KujuTokenID.Comment:
+ if(car.Description == string.Empty)
+ {
+ // WAG files often have a comment block with a basic description
+ strings = block.ReadStringArray();
+ car.Description = string.Join("", strings);
+ }
+ break;
+ case KujuTokenID.MaxPower:
+ // maximum continous power at the rails provided to the wheels
+ break;
+ case KujuTokenID.MaxForce:
+ // maximum force applied when starting
+ if (!isEngine)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: MaxForce is not expected to be present in a wagon block.");
+ break;
+ }
+ maxForce = block.ReadSingle(UnitOfForce.Newton);
+ break;
+ case KujuTokenID.MaxVelocity:
+ maxVelocity = block.ReadSingle(UnitOfVelocity.MetersPerSecond);
+ break;
+ case KujuTokenID.MaxBrakeForce:
+ maxBrakeForce = block.ReadSingle(UnitOfForce.Newton);
+ break;
+ case KujuTokenID.MaxContinuousForce:
+ // Maximum continuous force
+ if (!isEngine)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: MaxContinuousForce is not expected to be present in a wagon block.");
+ break;
+ }
+ maxContinuousForce = block.ReadSingle(UnitOfForce.Newton);
+ break;
+ case KujuTokenID.RunUpTimeToMaxForce:
+ //
+ break;
+ case KujuTokenID.WheelRadius:
+ wheelRadius = block.ReadSingle(UnitOfLength.Meter);
+ break;
+ case KujuTokenID.NumWheels:
+ int numWheels = block.ReadInt32();
+ if (numWheels < 2)
+ {
+ // NumWheels *should* be divisible by two (to get axles), but some content uses a single wheel, e.g. stock Class 50
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: Invalid number of wheels.");
+ numWheels = 1;
+ }
+ else
+ {
+ numWheels /= 2;
+ }
+
+ if (block.ParentBlock.Token == KujuTokenID.Engine)
+ {
+ car.DrivingWheels.Add(new Wheels(numWheels == 1 ? 2 : numWheels, wheelRadius));
+ }
+ else
+ {
+ car.TrailingWheels.Add(new Wheels(numWheels == 1 ? 2 : numWheels, wheelRadius));
+ }
+ break;
+ case KujuTokenID.Sound:
+ // parse the sounds *after* we've loaded the traction model though
+ string sF = block.ReadString();
+ string soundFile = OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(Path.GetDirectoryName(fileName), "SOUND"), sF);
+ if (!File.Exists(soundFile))
+ {
+ if (Directory.Exists(Plugin.FileSystem.MSTSDirectory))
+ {
+ // If sound file is not relative to the ENG / WAG, try in the MSTS common sound directory (most generic wagons + coaches)
+ soundFile = OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(Plugin.FileSystem.MSTSDirectory, "SOUND"), sF);
+ }
+ if (!File.Exists(soundFile))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: SMS file " + soundFile + " was not found.");
+ }
+ break;
+ }
+ soundFiles.Add(soundFile);
+ break;
+ case KujuTokenID.EngineControllers:
+ if (!isEngine)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: An EngineControllers block is not valid in a wagon block.");
+ break;
+ }
+
+ while (block.Position() < block.Length() - 2)
+ {
+ // large number of potential controls when including diesel + steam, so allow *any* block here
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, true, ref car, ref train);
+ }
+ break;
+ case KujuTokenID.Throttle:
+ if (EngineAlreadyParsed)
+ {
+ // NOTE: Per-car handles not yet supported, so take the handles from the first engine in the train
+ // otherwise, if we've got a VariableHandle (0-100) followed by notched, we'll be stuck at basically zero power
+ break;
+ }
+ if (currentEngineType == EngineType.Steam)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: A throttle is not valid for a Steam Locomotive.");
+ break;
+ }
+ train.Handles.Power = ParseHandle(block, train, true);
+ break;
+ case KujuTokenID.Brake_Train:
+ if (EngineAlreadyParsed)
+ {
+ break;
+ }
+ train.Handles.Brake = ParseHandle(block, train, false);
+ break;
+ case KujuTokenID.Brake_Engine:
+ if (EngineAlreadyParsed)
+ {
+ break;
+ }
+ train.Handles.HasLocoBrake = true;
+ train.Handles.LocoBrake = ParseHandle(block, train, false);
+ break;
+ case KujuTokenID.Combined_Control:
+ if (EngineAlreadyParsed)
+ {
+ break;
+ }
+ block.ReadSingle();
+ block.ReadSingle();
+ block.ReadSingle();
+ block.ReadSingle();
+
+ CombinedControlType firstCombinedControl = block.ReadEnumValue(default(CombinedControlType));
+ CombinedControlType secondCombinedControl = block.ReadEnumValue(default(CombinedControlType));
+
+ if (firstCombinedControl == CombinedControlType.Throttle && secondCombinedControl == CombinedControlType.Dynamic)
+ {
+ train.Handles.HandleType = HandleType.SingleHandle;
+ }
+ break;
+ case KujuTokenID.Sanding:
+ switch (block.ParentBlock.Token)
+ {
+ case KujuTokenID.Engine:
+ maxSandingSpeed = block.ReadSingle(UnitOfVelocity.MetersPerSecond, UnitOfVelocity.MilesPerHour);
+ break;
+ case KujuTokenID.EngineControllers:
+ int p1 = block.ReadInt16();
+ int p2 = block.ReadInt16();
+ int p3 = block.ReadInt16();
+ if (p1 == 0 && p2 == 1 && p3 == 0)
+ {
+ car.ReAdhesionDevice = new Sanders(car, SandersType.PressAndHold, maxSandingSpeed);
+ }
+ break;
+ }
+ break;
+ case KujuTokenID.DieselEngineSpeedOfMaxTractiveEffort:
+ dieselMaxTractiveEffortSpeed = block.ReadSingle(UnitOfVelocity.MetersPerSecond);
+ break;
+ case KujuTokenID.DieselEngineIdleRPM:
+ dieselIdleRPM = block.ReadSingle();
+ break;
+ case KujuTokenID.DieselEngineMaxRPM:
+ dieselMaxRPM = block.ReadSingle();
+ break;
+ case KujuTokenID.DieselEngineMaxRPMChangeRate:
+ dieselRPMChangeRate = block.ReadSingle();
+ break;
+ case KujuTokenID.DieselUsedPerHourAtIdle:
+ dieselIdleUse = block.ReadSingle(UnitOfVolume.Litres);
+ dieselIdleUse /= 3600;
+ break;
+ case KujuTokenID.DieselUsedPerHourAtMaxPower:
+ dieselMaxUse = block.ReadSingle(UnitOfVolume.Litres);
+ dieselMaxUse /= 3600;
+ break;
+ case KujuTokenID.MaxDieselLevel:
+ dieselCapacity = block.ReadSingle(UnitOfVolume.Litres);
+ break;
+ case KujuTokenID.MaxCurrent:
+ maxEngineAmps = block.ReadSingle(UnitOfCurrent.Amps);
+ break;
+ case KujuTokenID.DynamicBrakesResistorCurrentLimit:
+ maxBrakeAmps = block.ReadSingle(UnitOfCurrent.Amps);
+ break;
+ case KujuTokenID.AirBrakesMainMinResAirPressure:
+ mainReservoirMinimumPressure = block.ReadSingle(UnitOfPressure.Pascal, UnitOfPressure.PoundsPerSquareInch);
+ break;
+ case KujuTokenID.AirBrakesMainMaxAirPressure:
+ mainReservoirMaximumPressure = block.ReadSingle(UnitOfPressure.Pascal, UnitOfPressure.PoundsPerSquareInch);
+ break;
+ case KujuTokenID.BrakeCylinderPressureForMaxBrakeBrakeForce:
+ brakeCylinderMaximumPressure = block.ReadSingle(UnitOfPressure.Pascal, brakeSystemDefaultUnits);
+ break;
+ case KujuTokenID.TrainBrakesControllerEmergencyApplicationRate:
+ emergencyRate = block.ReadSingle(UnitOfPressure.Pascal, brakeSystemDefaultUnits);
+ break;
+ case KujuTokenID.AirBrakesAirCompressorPowerRating:
+ compressionRate = block.ReadSingle(UnitOfPressure.Pascal, UnitOfPressure.PoundsPerSquareInch);
+ if (compressionRate < 3500 || compressionRate > 34475) // assume valid range to be 0.5psi/s to 5psi/s
+ {
+ compressionRate = 3500;
+ }
+ break;
+ case KujuTokenID.TrainBrakesControllerMaxReleaseRate:
+ releaseRate = block.ReadSingle(UnitOfPressure.Pascal, brakeSystemDefaultUnits);
+ break;
+ case KujuTokenID.AntiSlip:
+ // if any value in this block, car has wheelslip detection control
+ hasAntiSlipDevice = true;
+ break;
+ case KujuTokenID.AWSMonitor:
+ case KujuTokenID.EmergencyStopMonitor:
+ case KujuTokenID.OverspeedMonitor:
+ case KujuTokenID.VigilanceMonitor:
+ // MSTS safety systems
+ VigilanceDevice device = VigilanceDevice.CreateVigilanceDevice(block.Token);
+ while (block.Position() < block.Length() - 2)
+ {
+ newBlock = block.ReadSubBlock(true);
+ device.ParseBlock(newBlock);
+ }
+ device.Create(car);
+ vigilanceDevices.Add(device);
+ break;
+ case KujuTokenID.FreightAnim:
+ if (Plugin.PreviewOnly)
+ {
+ break;
+ }
+ objectFile = OpenBveApi.Path.CombineFile(Path.GetDirectoryName(fileName), block.ReadString());
+
+ if (!File.Exists(objectFile))
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "MSTS Vehicle Parser: FreightAnim object file " + objectFile + " was not found");
+ break;
+ }
+
+ /*
+ *
+ * https://tsforum.forumotion.net/t655-freight-animation
+ * FreightAnim are a total mess...
+ * Whilst it appears they were intended to work with all cars, the positioning logic only works correctly
+ * with tenders.
+ *
+ * TENDERS:
+ * --------
+ * First value: Starting Y position (full)
+ * Second value: Ending Y position (empty)
+ * Third value: Must be positive or omitted for animation to work. If negative, animation stays at full.
+ *
+ * OTHER CARS:
+ * ----------
+ * First value: Ignored
+ * Second value: Must be any positive number.
+ *
+ * However, this is actually done by directly replacing the Y translation component of Matrix[0] within the shape
+ * This means that if our shape actually has a value here, things can get really messy.
+ *
+ * The UKTS RCH wagon loads contain a Y value of approx 2.53, which when loaded in this way actually gets discarded
+ *
+ */
+
+ double loadPosition = 0;
+ double emptyPosition = 0;
+ try
+ {
+ loadPosition = block.ReadSingle();
+ emptyPosition = block.ReadSingle();
+ // may also be one more number, but this appears unused
+ }
+ catch
+ {
+ // ignore
+ }
+
+ if (isEngine == false && currentWagonType != WagonType.Tender)
+ {
+ if (emptyPosition == 0)
+ {
+ break;
+ }
+ loadPosition = 0;
+ }
+
+ for (int i = 0; i < Plugin.CurrentHost.Plugins.Length; i++)
+ {
+ if (Plugin.CurrentHost.Plugins[i].Object == null || !Plugin.CurrentHost.Plugins[i].Object.CanLoadObject(objectFile))
+ {
+ continue;
+ }
+ Plugin.CurrentHost.Plugins[i].Object.LoadObject(objectFile, Path.GetDirectoryName(fileName), Encoding.Default, out UnifiedObject freightObject);
+ if (exteriorLoaded)
+ {
+
+ CarSection exteriorCarSection = car.CarSections[CarSectionType.Exterior];
+ exteriorCarSection.AppendObject(Plugin.CurrentHost, new Vector3(0, loadPosition, 0), car, freightObject);
+ car.CarSections[CarSectionType.Exterior] = exteriorCarSection;
+ }
+ else
+ {
+ car.CarSections.Add(CarSectionType.Exterior, new CarSection(Plugin.CurrentHost, ObjectType.Dynamic, false, car, freightObject));
+ }
+ break;
+ }
+ break;
+ case KujuTokenID.Effects:
+ while (block.Position() < block.Length() - 2)
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, isEngine, ref car, ref train);
+ }
+ break;
+ case KujuTokenID.DieselSpecialEffects:
+ while (block.Position() < block.Length() - 2)
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, isEngine, ref car, ref train);
+ }
+ break;
+ case KujuTokenID.Exhaust1:
+ Exhaust.Offset = new Vector3(block.ReadSingle(), block.ReadSingle(), block.ReadSingle());
+ Exhaust.Direction = new Vector3(block.ReadSingle(), block.ReadSingle(), block.ReadSingle());
+ Exhaust.Size = block.ReadSingle();
+ break;
+ case KujuTokenID.DieselSmokeEffectMaxMagnitude:
+ Exhaust.SmokeMaxMagnitude = block.ReadSingle();
+ break;
+ case KujuTokenID.DieselSmokeEffectInitialSmokeRate:
+ Exhaust.SmokeInitialRate = block.ReadSingle();
+ break;
+ case KujuTokenID.DieselSmokeEffectMaxSmokeRate:
+ Exhaust.SmokeMaxRate = block.ReadSingle();
+ break;
+ case KujuTokenID.GearBoxNumberOfGears:
+ int numGears = block.ReadInt16();
+ Gears = new Gear[numGears];
+ break;
+ case KujuTokenID.GearBoxMaxSpeedForGears:
+ if (Gears == null)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS Vehicle Parser: Gears must be specified when using GearBoxMaxSpeedForGears.");
+ break;
+ }
+
+ for (int i = 0; i < Gears.Length; i++)
+ {
+ Gears[i].MaximumSpeed = block.ReadSingle(UnitOfVelocity.MetersPerSecond, UnitOfVelocity.MilesPerHour);
+ }
+ break;
+ case KujuTokenID.GearBoxMaxTractiveForceForGears:
+ if (Gears == null)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS Vehicle Parser: Gears must be specified when using GearBoxMaxTractiveForceForGears.");
+ break;
+ }
+
+ for (int i = 0; i < Gears.Length; i++)
+ {
+ Gears[i].MaxTractiveForce = block.ReadSingle(UnitOfForce.Newton);
+ }
+ break;
+ case KujuTokenID.GearBoxOverspeedPercentageForFailure:
+ if (Gears == null)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MSTS Vehicle Parser: Gears must be specified when using GearBoxOVerspeedPercentageForFailure.");
+ break;
+ }
+
+ double perc = block.ReadSingle() / 100;
+ for (int i = 0; i < Gears.Length; i++)
+ {
+ Gears[i].OverspeedFailure = Gears[i].MaximumSpeed * perc;
+ }
+ break;
+ case KujuTokenID.GearBoxOperation:
+ gearboxOperationMode = block.ReadEnumValue(default(GearboxOperation));
+ break;
+ case KujuTokenID.Friction:
+ friction = new Friction(block);
+ break;
+ case KujuTokenID.Adheasion:
+ adhesion = new Adhesion(block, car, currentEngineType == EngineType.Steam);
+ break;
+ case KujuTokenID.Coupling:
+ while (block.Position() < block.Length() - 2)
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, isEngine, ref car, ref train);
+ }
+ break;
+ case KujuTokenID.Spring:
+ while (block.Position() < block.Length() - 2)
+ {
+ newBlock = block.ReadSubBlock(true);
+ ParseBlock(newBlock, fileName, ref wagonName, isEngine, ref car, ref train);
+ }
+ break;
+ case KujuTokenID.r0:
+ try
+ {
+ car.Coupler.MinimumDistanceBetweenCars = block.ReadSingle(UnitOfLength.Meter);
+ car.Coupler.MaximumDistanceBetweenCars = couplingType != CouplingType.Bar ? block.ReadSingle(UnitOfLength.Meter) : car.Coupler.MinimumDistanceBetweenCars;
+ }
+ catch
+ {
+ // ignored
+ }
+
+ if (car.Coupler.MaximumDistanceBetweenCars > 2)
+ {
+ // some automatic / bar couplers seem to have absurd maximum distances
+ // so let's assume they're no good
+ car.Coupler.MaximumDistanceBetweenCars = car.Coupler.MinimumDistanceBetweenCars;
+ }
+ break;
+ case KujuTokenID.IsTenderRequired:
+ RequiresTender = block.ReadBool();
+ break;
+ case KujuTokenID.EngineVariables:
+ switch (currentEngineType)
+ {
+ case EngineType.DieselHydraulic:
+ case EngineType.Diesel:
+ // Fuel capacity (L)
+ // NOTE: Max fuel is set by MaxDieselLevel
+ MaxFuelLevel = block.ReadSingle(UnitOfVolume.Litres);
+ break;
+ case EngineType.Steam:
+ // https://tsforum.forumotion.net/t120-msts-helpful-facts-and-links-part-14-enginevariables-for-steam-locomotives-by-slipperman12
+ // Fire temp (deg c)
+ // Fire mass (lbs)
+ // Water mass in boiler (lbs)
+ // Boiler pressure (psi)
+ // Tender water mass (If switched to in ACT mode, so ignore)
+ // Tender coal mass (If switched to in ACT mode, so ignore)
+ // Smoke quantity multiplier
+ // Fire condition
+ // Coal quality
+ // NOTE: Max fuel / water levels are set by MaxTenderCoalMass and MaxTenderWaterMass
+ break;
+ }
+ break;
+ case KujuTokenID.MaxTenderCoalMass:
+ MaxFuelLevel = block.ReadSingle(UnitOfWeight.Kilograms, UnitOfWeight.Pounds);
+ break;
+ case KujuTokenID.MaxTenderWaterMass:
+ // at atmospheric pressure, 1kg of water = 1L
+ MaxWaterLevel = block.ReadSingle(UnitOfWeight.Kilograms, UnitOfWeight.Pounds);
+ break;
+ }
+ return true;
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Vigilance/AWSMonitor.cs b/source/Plugins/Train.MsTs/Vigilance/AWSMonitor.cs
new file mode 100644
index 0000000000..a8cd6dc6a5
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Vigilance/AWSMonitor.cs
@@ -0,0 +1,17 @@
+namespace Train.MsTs
+{
+ internal class AWSMonitor : VigilanceDevice
+ {
+ /*
+ * NOT IMPLEMENTED
+ *
+ * NOTE: OpenRails does not implement the AWSMonitor
+ *
+ * Need to look further into whether it ever actually worked,
+ * or was implemented in any real-world content.
+ *
+ * No use of it in a relatively large UK content collection
+ * (some AWS displays appear to be simulated via CAB_SIGNAL_DISPLAY)
+ */
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Vigilance/AbstractVigilanceDevice.cs b/source/Plugins/Train.MsTs/Vigilance/AbstractVigilanceDevice.cs
new file mode 100644
index 0000000000..c0231fea81
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Vigilance/AbstractVigilanceDevice.cs
@@ -0,0 +1,182 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System.IO;
+using OpenBve.Formats.MsTs;
+using OpenBveApi.World;
+using TrainManager.Car;
+
+namespace Train.MsTs
+{
+ internal abstract class VigilanceDevice
+ {
+ /// The time limit before this device alarms
+ /// Set to -1 for triggered devices
+ internal double TimeLimit;
+ /// The time limit before the device intervenes in alarm state
+ internal double AlarmTimeLimit;
+ /// The time limit before the device applies a penalty
+ internal double PenaltyTimeLimit;
+ /// The critical level of the trigger
+ internal double CriticalLevel;
+ /// The reset level of the trigger
+ internal double ResetLevel;
+ /// Whether full brake is applied on intervention
+ internal bool AppliesFullBrake;
+ /// Whether emergency brake is applied on intervention
+ internal bool AppliesEmergencyBrake;
+ /// Whether power is cut on invervention
+ internal bool CutsPower;
+ /// Whether the engine is shut down on intervention
+ internal bool ShutsDownEngine;
+ /// The reset conditions
+ internal ResetCondition ResetConditions;
+
+ internal static VigilanceDevice CreateVigilanceDevice(KujuTokenID token)
+ {
+ switch (token)
+ {
+ case KujuTokenID.AWSMonitor:
+ return new AWSMonitor();
+ case KujuTokenID.EmergencyStopMonitor:
+ return new EmergencyStopMonitor();
+ case KujuTokenID.OverspeedMonitor:
+ return new OverspeedMonitor();
+ case KujuTokenID.VigilanceMonitor:
+ return new VigilanceMonitor();
+ default:
+ throw new InvalidDataException("Not a valid vigilance device");
+ }
+ }
+
+ internal virtual void Create(CarBase car)
+ {
+
+ }
+
+ internal void ParseBlock(Block block)
+ {
+ switch (block.Token)
+ {
+ case KujuTokenID.MonitoringDeviceMonitorTimeLimit:
+ TimeLimit = block.ReadSingle();
+ break;
+ case KujuTokenID.MonitoringDeviceAlarmTimeLimit:
+ AlarmTimeLimit = block.ReadSingle();
+ break;
+ case KujuTokenID.MonitoringDevicePenaltyTimeLimit:
+ PenaltyTimeLimit = block.ReadSingle();
+ break;
+ case KujuTokenID.MonitoringDeviceCriticalLevel:
+ if (block.ParentBlock.Token == KujuTokenID.OverspeedMonitor)
+ {
+ // Check exact behaviour
+ CriticalLevel = block.ReadSingle(UnitOfVelocity.MetersPerSecond, UnitOfVelocity.MilesPerHour);
+ }
+ else
+ {
+ CriticalLevel = block.ReadSingle();
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetLevel:
+ if (block.ParentBlock.Token == KujuTokenID.OverspeedMonitor)
+ {
+ // Check exact behaviour
+ ResetLevel = block.ReadSingle(UnitOfVelocity.MetersPerSecond, UnitOfVelocity.MilesPerHour);
+ }
+ else
+ {
+ ResetLevel = block.ReadSingle();
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceAppliesFullBrake:
+ AppliesFullBrake = block.ReadInt32() == 1;
+ break;
+ case KujuTokenID.MonitoringDeviceAppliesEmergencyBrake:
+ AppliesEmergencyBrake = block.ReadInt32() == 1;
+ break;
+ case KujuTokenID.MonitoringDeviceAppliesCutsPower:
+ CutsPower = block.ReadInt32() == 1;
+ break;
+ case KujuTokenID.MonitoringDeviceAppliesShutsDownEngine:
+ ShutsDownEngine = block.ReadInt32() == 1;
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnZeroSpeed:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.ZeroSpeed;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnZeroThrottle:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.ZeroThrottle;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnDirectionNeutral:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.DirectionNeutral;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnEngineAtIdle:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.EngineAtIdle;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnBrakeOff:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.BrakeOff;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnBrakeFullyOn:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.BrakeFullyOn;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnDynamicBrakeOff:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.DynamicBrakeOff;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnDynamicBrakeOn:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.DynamicBrakeOn;
+ }
+ break;
+ case KujuTokenID.MonitoringDeviceResetOnResetButton:
+ if (block.ReadInt32() == 1)
+ {
+ ResetConditions |= ResetCondition.ResetButton;
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Vigilance/EmergencyStopMonitor.cs b/source/Plugins/Train.MsTs/Vigilance/EmergencyStopMonitor.cs
new file mode 100644
index 0000000000..81229e7dcc
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Vigilance/EmergencyStopMonitor.cs
@@ -0,0 +1,7 @@
+namespace Train.MsTs
+{
+ internal class EmergencyStopMonitor : VigilanceDevice
+ {
+ // NOT YET IMPLEMENTED
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Vigilance/OverspeedMonitor.cs b/source/Plugins/Train.MsTs/Vigilance/OverspeedMonitor.cs
new file mode 100644
index 0000000000..a26391d746
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Vigilance/OverspeedMonitor.cs
@@ -0,0 +1,52 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using TrainManager.Car;
+using TrainManager.SafetySystems;
+
+namespace Train.MsTs
+{
+ internal class OverspeedMonitor : VigilanceDevice
+ {
+ internal override void Create(CarBase car)
+ {
+ SafetySystemType deviceType = SafetySystemType.None;
+
+ if (CutsPower)
+ {
+ deviceType = SafetySystemType.CutsPower;
+ }
+ if (AppliesFullBrake)
+ {
+ deviceType = SafetySystemType.ApplyBrake;
+ }
+ if (AppliesEmergencyBrake)
+ {
+ deviceType = SafetySystemType.ApplyEmergencyBrake;
+ }
+
+ car.SafetySystems.Add(SafetySystem.OverspeedDevice, new OverspeedDevice(car, deviceType, CriticalLevel, ResetLevel, TimeLimit, PenaltyTimeLimit, 0));
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Vigilance/ResetCondition.cs b/source/Plugins/Train.MsTs/Vigilance/ResetCondition.cs
new file mode 100644
index 0000000000..578aa040cf
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Vigilance/ResetCondition.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Train.MsTs
+{
+ [Flags]
+ public enum ResetCondition
+ {
+ None = 0,
+ ZeroSpeed = 1,
+ ZeroThrottle= 2,
+ DirectionNeutral = 4,
+ EngineAtIdle = 8,
+ BrakeOff = 16,
+ BrakeFullyOn = 32,
+ DynamicBrakeOff = 64,
+ DynamicBrakeOn = 128,
+ ResetButton = 256,
+ }
+}
diff --git a/source/Plugins/Train.MsTs/Vigilance/VigilanceMonitor.cs b/source/Plugins/Train.MsTs/Vigilance/VigilanceMonitor.cs
new file mode 100644
index 0000000000..486facdd69
--- /dev/null
+++ b/source/Plugins/Train.MsTs/Vigilance/VigilanceMonitor.cs
@@ -0,0 +1,52 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using TrainManager.Car;
+using TrainManager.SafetySystems;
+
+namespace Train.MsTs
+{
+ internal class VigilanceMonitor : VigilanceDevice
+ {
+ internal override void Create(CarBase car)
+ {
+ SafetySystemType deviceType = SafetySystemType.None;
+
+ if (CutsPower)
+ {
+ deviceType = SafetySystemType.CutsPower;
+ }
+ if (AppliesFullBrake)
+ {
+ deviceType = SafetySystemType.ApplyBrake;
+ }
+ if (AppliesEmergencyBrake)
+ {
+ deviceType = SafetySystemType.ApplyEmergencyBrake;
+ }
+
+ car.SafetySystems.Add(SafetySystem.DriverSupervisionDevice, new DriverSupervisionDevice(car, deviceType, DriverSupervisionDeviceMode.AnyHandle, SafetySystemTriggerMode.TrainMoving, AlarmTimeLimit, TimeLimit, PenaltyTimeLimit));
+ }
+ }
+}
diff --git a/source/Plugins/Train.MsTs/app.config b/source/Plugins/Train.MsTs/app.config
new file mode 100644
index 0000000000..a1e2bff25d
--- /dev/null
+++ b/source/Plugins/Train.MsTs/app.config
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/Plugins/Train.MsTs/packages.config b/source/Plugins/Train.MsTs/packages.config
new file mode 100644
index 0000000000..5d2acb5f31
--- /dev/null
+++ b/source/Plugins/Train.MsTs/packages.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/SoundManager/SoundManager.csproj b/source/SoundManager/SoundManager.csproj
index 86e28e3270..857bdfaad0 100644
--- a/source/SoundManager/SoundManager.csproj
+++ b/source/SoundManager/SoundManager.csproj
@@ -47,6 +47,7 @@
prompt
+
..\..\packages\OpenTK-OpenBVE.1.0.4\lib\net20\OpenTK.dll
@@ -78,5 +79,6 @@
+
\ No newline at end of file
diff --git a/source/SoundManager/Sounds.CarSound.cs b/source/SoundManager/Sounds.CarSound.cs
index c28c2c2bc9..f6f9e63b51 100644
--- a/source/SoundManager/Sounds.CarSound.cs
+++ b/source/SoundManager/Sounds.CarSound.cs
@@ -3,8 +3,9 @@
using OpenBveApi.Hosts;
using OpenBveApi.Interface;
using OpenBveApi.Math;
-using OpenBveApi.Sounds;
+using OpenBveApi.Runtime;
using OpenBveApi.Trains;
+using SoundHandle = OpenBveApi.Sounds.SoundHandle;
namespace SoundManager
{
@@ -21,6 +22,8 @@ public class CarSound
/// Used when crossfading between multiple sounds of the same type
public double TargetVolume;
+ public CameraViewMode ViewModes;
+
public CarSound(HostInterface currentHost, string trainFolder, string soundFile, double radius, Vector3 position) : this(currentHost, trainFolder, string.Empty, -1, soundFile, radius, position)
{
}
diff --git a/source/TrainManager/Brake/AirBrake/ThroughPiped.cs b/source/TrainManager/Brake/AirBrake/ThroughPiped.cs
index e728eae1b7..ecbf67d7ad 100644
--- a/source/TrainManager/Brake/AirBrake/ThroughPiped.cs
+++ b/source/TrainManager/Brake/AirBrake/ThroughPiped.cs
@@ -33,7 +33,6 @@ public class ThroughPiped : CarBrake
{
public ThroughPiped(CarBase car) : base(car, new AccelerationCurve[] {})
{
- DecelerationCurves = new AccelerationCurve[] { };
BrakeType = BrakeType.None;
BrakePipe = new BrakePipe(0);
}
diff --git a/source/TrainManager/Brake/CarBrake.cs b/source/TrainManager/Brake/CarBrake.cs
index 78d2ba7056..78409ebbd5 100644
--- a/source/TrainManager/Brake/CarBrake.cs
+++ b/source/TrainManager/Brake/CarBrake.cs
@@ -101,6 +101,11 @@ public double DecelerationAtServiceMaximumPressure(int Notch, double currentSpee
{
return 0;
}
+
+ if (DecelerationCurves[0] is MSTSDecelerationCurve dec)
+ {
+ return dec.MaximumAcceleration;
+ }
if (Notch == 0)
{
return this.DecelerationCurves[0].GetAccelerationOutput(currentSpeed);
diff --git a/source/TrainManager/Car/CarSounds.cs b/source/TrainManager/Car/CarSounds.cs
index a36b226a59..e14b1464f5 100644
--- a/source/TrainManager/Car/CarSounds.cs
+++ b/source/TrainManager/Car/CarSounds.cs
@@ -1,5 +1,7 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using SoundManager;
+using TrainManager.Motor;
+using TrainManager.MsTsSounds;
namespace TrainManager.Car
{
@@ -8,6 +10,8 @@ public class CarSounds
{
/// The loop sound
public CarSound Loop;
+
+ public List ControlledSounds = new List();
/// The sounds triggered by the train's plugin
public Dictionary Plugin = new Dictionary();
/// The sounds triggered by a request stop
diff --git a/source/TrainManager/Motor/DieselEngine/Gearbox.cs b/source/TrainManager/Motor/DieselEngine/Gearbox.cs
index 85059c54b6..6fcb3eeb3a 100644
--- a/source/TrainManager/Motor/DieselEngine/Gearbox.cs
+++ b/source/TrainManager/Motor/DieselEngine/Gearbox.cs
@@ -11,9 +11,9 @@ public class Gearbox : AbstractComponent
/// The current gear
public int CurrentGear;
/// The sound played when the gear is increased
- internal CarSound GearUpSound;
+ public CarSound GearUpSound;
/// The sound played when the gear is decreased
- internal CarSound GearDownSound;
+ public CarSound GearDownSound;
/// The sound played when the gearbox returns to neutral
internal CarSound NeutralSound;
/// The maximum speed attainable in the current gear
diff --git a/source/TrainManager/Motor/ElectricEngine/ElectricEngine.cs b/source/TrainManager/Motor/ElectricEngine/ElectricEngine.cs
index 0353b04617..48805a9e55 100644
--- a/source/TrainManager/Motor/ElectricEngine/ElectricEngine.cs
+++ b/source/TrainManager/Motor/ElectricEngine/ElectricEngine.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
//
@@ -32,10 +32,6 @@ namespace TrainManager.Motor
{
public class ElectricEngine : TractionModel
{
- public ElectricEngine(CarBase car) : base(car)
- {
- }
-
public ElectricEngine(CarBase car, AccelerationCurve[] accelerationCurves) : base(car, accelerationCurves, true)
{
}
diff --git a/source/TrainManager/Motor/Fuel/FuelTank.cs b/source/TrainManager/Motor/Fuel/FuelTank.cs
index 8f08364928..0c4d6e7dce 100644
--- a/source/TrainManager/Motor/Fuel/FuelTank.cs
+++ b/source/TrainManager/Motor/Fuel/FuelTank.cs
@@ -25,5 +25,12 @@ public FuelTank(double maxLevel, double minLevel, double currentLevel)
MinLevel = minLevel;
CurrentLevel = currentLevel;
}
+
+ public FuelTank(double currentLevel)
+ {
+ MaxLevel = currentLevel;
+ MinLevel = 0;
+ CurrentLevel = currentLevel;
+ }
}
}
diff --git a/source/TrainManager/Motor/SteamEngine/TankEngine.cs b/source/TrainManager/Motor/SteamEngine/TankEngine.cs
new file mode 100644
index 0000000000..a2d1275c04
--- /dev/null
+++ b/source/TrainManager/Motor/SteamEngine/TankEngine.cs
@@ -0,0 +1,61 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using TrainManager.Car;
+using TrainManager.Power;
+
+namespace TrainManager.Motor
+{
+ public class TankEngine : TractionModel
+ {
+ /// The maximum water level
+ public readonly double TankMaxWaterLevel;
+ /// The current water level
+ public double TankWaterLevel;
+
+ public TankEngine(CarBase baseCar, AccelerationCurve[] accelerationCurves, double maxFuelLevel, double maxWaterLevel) : base(baseCar, accelerationCurves, true)
+ {
+ FuelTank = new FuelTank(maxFuelLevel, 0, maxFuelLevel);
+ TankMaxWaterLevel = maxWaterLevel;
+ TankWaterLevel = maxWaterLevel;
+ }
+
+ public TankEngine(CarBase baseCar, AccelerationCurve[] accelerationCurves, double maxFuelLevel, double fuelLevel, double maxWaterLevel, double waterLevel) : base(baseCar, accelerationCurves, true)
+ {
+ FuelTank = new FuelTank(maxFuelLevel, 0, fuelLevel);
+ TankMaxWaterLevel = maxWaterLevel;
+ TankWaterLevel = waterLevel;
+ }
+
+ public override void Update(double timeElapsed)
+ {
+ }
+
+ // TODO: PLACEHOLDER VALUES
+
+ public override double CurrentPower => 1.0;
+
+ public override double TargetAcceleration => AccelerationCurves[0].GetAccelerationOutput(BaseCar.CurrentSpeed);
+ }
+}
diff --git a/source/TrainManager/Motor/SteamEngine/Tender.cs b/source/TrainManager/Motor/SteamEngine/Tender.cs
new file mode 100644
index 0000000000..be2f1a37f1
--- /dev/null
+++ b/source/TrainManager/Motor/SteamEngine/Tender.cs
@@ -0,0 +1,55 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using TrainManager.Car;
+
+namespace TrainManager.Motor
+{
+ public class Tender : TractionModel
+ {
+ /// The maximum water level
+ public readonly double MaxWaterLevel;
+ /// The current water level
+ public double WaterLevel;
+
+ public Tender(CarBase car, double maxFuelLevel, double maxWaterLevel) : base(car, null, false)
+ {
+ FuelTank = new FuelTank(maxFuelLevel, 0, maxFuelLevel);
+ MaxWaterLevel = maxWaterLevel;
+ WaterLevel = maxWaterLevel;
+ }
+
+ public Tender(CarBase car, double maxFuelLevel, double fuelLevel, double maxWaterLevel, double waterLevel) : base(car, null, false)
+ {
+ FuelTank = new FuelTank(maxFuelLevel, 0, fuelLevel);
+ MaxWaterLevel = maxWaterLevel;
+ WaterLevel = waterLevel;
+ }
+
+ public override void Update(double timeElapsed)
+ {
+
+ }
+ }
+}
diff --git a/source/TrainManager/Motor/SteamEngine/TenderEngine.cs b/source/TrainManager/Motor/SteamEngine/TenderEngine.cs
new file mode 100644
index 0000000000..ee158b85ae
--- /dev/null
+++ b/source/TrainManager/Motor/SteamEngine/TenderEngine.cs
@@ -0,0 +1,49 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using TrainManager.Car;
+using TrainManager.Power;
+
+namespace TrainManager.Motor
+{
+ public class TenderEngine : TractionModel
+ {
+ /// Holds a reference to the connected tender, or null if no tender connected
+ public Tender Tender;
+
+ public TenderEngine(CarBase baseCar, AccelerationCurve[] accelerationCurves) : base(baseCar, accelerationCurves, true)
+ {
+ }
+
+ public override void Update(double timeElapsed)
+ {
+ }
+
+ // TODO: PLACEHOLDER VALUES
+
+ public override double CurrentPower => 1.0;
+
+ public override double TargetAcceleration => AccelerationCurves[0].GetAccelerationOutput(BaseCar.CurrentSpeed);
+ }
+}
diff --git a/source/TrainManager/Power/AccelerationCurve.cs b/source/TrainManager/Power/AccelerationCurve.cs
index 3545fa5f9f..838fd02ac6 100644
--- a/source/TrainManager/Power/AccelerationCurve.cs
+++ b/source/TrainManager/Power/AccelerationCurve.cs
@@ -5,7 +5,7 @@ public abstract class AccelerationCurve
{
/// Gets the acceleration output for this curve
/// The current speed
- /// The acceleration output
+ /// The acceleration output in km/h/s
public abstract double GetAccelerationOutput(double Speed);
/// Gets the maximum possible acceleration output for this curve
diff --git a/source/TrainManager/Power/MSTS/MSTSAccelerationCurve.cs b/source/TrainManager/Power/MSTS/MSTSAccelerationCurve.cs
new file mode 100644
index 0000000000..4f776bf61e
--- /dev/null
+++ b/source/TrainManager/Power/MSTS/MSTSAccelerationCurve.cs
@@ -0,0 +1,184 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ReSharper disable InconsistentNaming
+
+using TrainManager.Car;
+using TrainManager.Handles;
+using TrainManager.Motor;
+using TrainManager.Trains;
+
+namespace TrainManager.Power
+{
+ /// Represents a MSTS acceleration curve
+ public class MSTSAccelerationCurve : AccelerationCurve
+ {
+ /// Holds a reference to the car
+ /// Can't store the train reference directly as we may couple to another
+ private readonly CarBase baseCar;
+ /// The maximum force supplied by the engine
+ private readonly double MaxForce;
+ /// The maximum velocity attainable
+ private readonly double MaxVelocity;
+ /// The maximum continuous force supplied by the engine
+ /// Used by electric model
+ private readonly double MaxContinuousForce;
+
+ public MSTSAccelerationCurve(CarBase car, double maxForce, double maxContinuousForce, double maxVelocity)
+ {
+ baseCar = car;
+ MaxForce = maxForce;
+ MaxContinuousForce = maxContinuousForce;
+ MaxVelocity = maxVelocity;
+ }
+
+ public override double GetAccelerationOutput(double Speed)
+ {
+ if (baseCar.Specs.PerceivedSpeed > MaxVelocity)
+ {
+ return 0;
+ }
+
+ /*
+ * According to Newton's second law, Acceleration = Force / Mass
+ * For the minute at least, we'll assume that the Force value specified in an
+ * ENG file is proportionate across power notches, and remains constant throughout
+ * the speed range. In practice, MSTS will actually have internally simulated this
+ * via engine RPM, boiler pressure etc. etc. but at present we obviously don't
+ * have these available.
+ *
+ * We don't in this case need to take the speed or loading values into account, but
+ * retain them as legacy
+ */
+ double totalMass = 0;
+
+ TrainBase baseTrain = baseCar.baseTrain;
+ for (int i = 0; i < baseTrain.Cars.Length; i++)
+ {
+ totalMass += baseTrain.Cars[i].CurrentMass;
+ }
+
+ if (baseTrain.Handles.EmergencyBrake.Actual)
+ {
+ return totalMass / MaxForce / 3.6;
+ }
+
+ if (baseTrain.Handles.Brake.Actual > 0)
+ {
+ return ((baseTrain.Handles.Brake.Actual / (double)baseTrain.Handles.Brake.MaximumNotch) * (totalMass / MaxForce));
+ }
+
+ if (baseCar.TractionModel is DieselEngine dieselEngine)
+ {
+ // diesel engine uses simulated power level of MaxForce
+ return dieselEngine.CurrentPower * (totalMass / MaxForce);
+ }
+
+ if (baseCar.TractionModel is ElectricEngine electricEngine)
+ {
+ if (baseCar.Specs.PerceivedSpeed < 3.61111 || baseCar.Specs.PerceivedSpeed > 7.22222)
+ {
+ // for electrics, MaxContinuousForce is used between 13km/h and 26km/h as per original Kuju physics model
+ return electricEngine.CurrentPower * (totalMass / MaxContinuousForce);
+ }
+ else
+ {
+ return electricEngine.CurrentPower * (totalMass / MaxForce);
+ }
+ }
+
+ return ((baseTrain.Handles.Power.Actual / (double)baseTrain.Handles.Power.MaximumNotch) * (totalMass / MaxForce));
+ }
+
+ public override double MaximumAcceleration
+ {
+ get
+ {
+ double totalMass = 0;
+ TrainBase baseTrain = baseCar.baseTrain;
+ for (int i = 0; i < baseTrain.Cars.Length; i++)
+ {
+ totalMass += baseTrain.Cars[i].CurrentMass;
+ }
+
+ return totalMass / MaxForce;
+ }
+ }
+
+ }
+
+ public class MSTSDecelerationCurve : AccelerationCurve
+ {
+ private readonly TrainBase Train;
+ /// The maximum force supplied by the engine
+ private readonly double MaxForce;
+
+ public MSTSDecelerationCurve(TrainBase train, double maxForce)
+ {
+ Train = train;
+ MaxForce = maxForce;
+ }
+ public override double GetAccelerationOutput(double Speed)
+ {
+ /*
+ * According to Newton's second law, Acceleration = Force / Mass
+ * For the minute at least, we'll assume that the Force value specified in an
+ * ENG file is proportionate across power notches, and remains constant throughout
+ * the speed range. In practice, MSTS will actually have internally simulated this
+ * via engine RPM, boiler pressure etc. etc. but at present we obviously don't
+ * have these available.
+ *
+ * We don't in this case need to take the speed or loading values into account, but
+ * retain them as legacy
+ * REFACTOR: Store the train reference in BVE acceleration curves???
+ */
+ double totalMass = 0;
+ for (int i = 0; i < Train.Cars.Length; i++)
+ {
+ totalMass += Train.Cars[i].CurrentMass;
+ }
+
+ double maxBrakeForce = totalMass / MaxForce / 3.6;
+ if (Train.Handles.Brake is VariableHandle variableHandle)
+ {
+ maxBrakeForce *= variableHandle.GetPowerModifier;
+ }
+ return maxBrakeForce;
+ }
+
+ public override double MaximumAcceleration
+ {
+ get
+ {
+ double totalMass = 0;
+ for (int i = 0; i < Train.Cars.Length; i++)
+ {
+ totalMass += Train.Cars[i].CurrentMass;
+ }
+
+ return totalMass / MaxForce / 3.6;
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/FrequencyCurve.cs b/source/TrainManager/Sounds/MSTS/FrequencyCurve.cs
new file mode 100644
index 0000000000..eeca176bfc
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/FrequencyCurve.cs
@@ -0,0 +1,79 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using OpenBve.Formats.MsTs;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ public class MsTsFrequencyCurve
+ {
+ private readonly CarBase car;
+ private readonly Tuple[] frequencyPoints;
+
+ private readonly KujuTokenID controller;
+
+ public MsTsFrequencyCurve(CarBase car, KujuTokenID controller, Tuple[] points)
+ {
+ this.car = car;
+ this.controller = controller;
+ frequencyPoints = new Tuple[points.Length];
+ for (int i = 0; i < frequencyPoints.Length; i++)
+ {
+ frequencyPoints[i] = new Tuple(points[i].Item1, points[i].Item2 / 11025); // MSTS base sound frequency is 11025hz, convert to percentage
+ }
+ }
+
+ public double Pitch
+ {
+ get
+ {
+ switch (controller)
+ {
+ case KujuTokenID.SpeedControlled:
+ for (int i = frequencyPoints.Length - 1; i >= 0; i--)
+ {
+ if (Math.Abs(car.CurrentSpeed) >= frequencyPoints[i].Item1)
+ {
+ return frequencyPoints[i].Item2;
+ }
+ }
+ break;
+ case KujuTokenID.Variable2Controlled:
+ for (int i = frequencyPoints.Length - 1; i >= 0; i--)
+ {
+ if (car.TractionModel.CurrentPower >= frequencyPoints[i].Item1)
+ {
+ return frequencyPoints[i].Item2;
+ }
+ }
+ break;
+
+ }
+ return 0;
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/SoundStream.cs b/source/TrainManager/Sounds/MSTS/SoundStream.cs
new file mode 100644
index 0000000000..99d5640f4a
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/SoundStream.cs
@@ -0,0 +1,130 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBveApi.Runtime;
+using System.Collections.Generic;
+using OpenBveApi.Math;
+using SoundManager;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ public class SoundStream
+ {
+ /// The list of sound triggers within the sound stream
+ public List Triggers;
+ /// The volume curve for the sound stream
+ public MsTsVolumeCurve VolumeCurve;
+ /// The frequency curve for the sound stream
+ public MsTsFrequencyCurve FrequencyCurve;
+ /// The camera modes in which this sound stream is active
+ public readonly CameraViewMode ActivationCameraModes;
+ /// The modes in which this sound stream is not active
+ public readonly CameraViewMode DeactivationCameraModes;
+
+ private SoundSource soundSource;
+
+ private CarBase car;
+
+ public SoundStream(CarBase baseCar, CameraViewMode activationCameraModes, CameraViewMode deactivationCameraModes)
+ {
+ Triggers = new List();
+ ActivationCameraModes = activationCameraModes;
+ DeactivationCameraModes = deactivationCameraModes;
+ car = baseCar;
+ }
+
+ public void Update(double timeElapsed)
+ {
+ double volume = 1.0, pitch = 1.0;
+ if (VolumeCurve != null)
+ {
+ volume = VolumeCurve.Volume;
+ }
+
+ if (FrequencyCurve != null)
+ {
+ pitch = FrequencyCurve.Pitch;
+ }
+
+ bool canActivate = true;
+ if (ActivationCameraModes != CameraViewMode.NotDefined)
+ {
+ canActivate = (ActivationCameraModes & TrainManagerBase.Renderer.Camera.CurrentMode) != 0;
+ }
+
+ if (DeactivationCameraModes != CameraViewMode.NotDefined)
+ {
+ if (canActivate)
+ {
+ canActivate = (DeactivationCameraModes & TrainManagerBase.Renderer.Camera.CurrentMode) == 0;
+ }
+ }
+
+ /*
+ * To get the playing buffer and loop state, we itinerate through all sound triggers in a stream
+ * in order. If the conditions for a trigger are met, the buffer ref and loop status are updated
+ *
+ * At the end of our loop, if the buffer is not null, either adjust the pitch / gain (if currently
+ * playing) or replace the playing buffer with it
+ * Otherwise, stop the playing buffer.
+ */
+ SoundBuffer soundBuffer = null;
+ if (soundSource != null)
+ {
+ soundBuffer = soundSource.Buffer;
+ }
+ bool loops = false;
+
+ for (int i = 0; i < Triggers.Count; i++)
+ {
+ if (canActivate)
+ {
+ Triggers[i].Update(timeElapsed, car, ref soundBuffer, ref loops);
+ }
+ }
+
+ if (soundBuffer != null)
+ {
+ if (soundSource != null && soundSource.Buffer == soundBuffer)
+ {
+ soundSource.Volume = volume;
+ soundSource.Pitch = pitch;
+ }
+ else
+ {
+ soundSource?.Stop();
+ soundSource = (SoundSource)TrainManagerBase.currentHost.PlaySound(soundBuffer, pitch, volume, Vector3.Zero, car, loops);
+ }
+ }
+ else
+ {
+ if (soundSource != null && soundSource.IsPlaying())
+ {
+ soundSource.Stop();
+ }
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/SoundTrigger.Initial.cs b/source/TrainManager/Sounds/MSTS/SoundTrigger.Initial.cs
new file mode 100644
index 0000000000..bddc012cfc
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/SoundTrigger.Initial.cs
@@ -0,0 +1,53 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBve.Formats.MsTs;
+using SoundManager;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ /// A trigger which is activated when the car is introduced
+ public class InitialTrigger: SoundTrigger
+ {
+ public InitialTrigger(SoundBuffer buffer, bool soundLoops) : base(buffer, soundLoops)
+ {
+ }
+
+ public InitialTrigger(SoundBuffer[] buffers, KujuTokenID selectionMethod, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ }
+
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ if (Triggered == false)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/SoundTrigger.Speed.cs b/source/TrainManager/Sounds/MSTS/SoundTrigger.Speed.cs
new file mode 100644
index 0000000000..28b60addc4
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/SoundTrigger.Speed.cs
@@ -0,0 +1,96 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using OpenBve.Formats.MsTs;
+using SoundManager;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ /// A sound trigger that activates when the train's speed increases past the set value
+ public class SpeedIncPast : SoundTrigger
+ {
+ private readonly double speedValue;
+
+
+ public SpeedIncPast(SoundBuffer[] buffers, KujuTokenID selectionMethod, double speedValue, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ this.speedValue = speedValue;
+ }
+
+ public SpeedIncPast(CarBase car, SoundBuffer buffer, double speedValue, bool soundLoops) : base(buffer, soundLoops)
+ {
+ this.speedValue = speedValue;
+ }
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ double speed = Math.Abs(car.CurrentSpeed);
+ if (speed >= speedValue)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+
+ if (speed < speedValue)
+ {
+ Triggered = false;
+ }
+ }
+ }
+
+ /// A sound trigger that activates when the train's speed decreases past the set value
+ public class SpeedDecPast : SoundTrigger
+ {
+ private readonly double speedValue;
+
+ public SpeedDecPast(SoundBuffer[] buffers, KujuTokenID selectionMethod, double speedValue, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ this.speedValue = speedValue;
+ }
+
+ public SpeedDecPast(SoundBuffer buffer, double speedValue, bool soundLoops) : base(buffer, soundLoops)
+ {
+ this.speedValue = speedValue;
+ }
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ double speed = Math.Abs(car.CurrentSpeed);
+ if (speed <= speedValue && Triggered == false)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+
+ if (speed > speedValue)
+ {
+ Triggered = false;
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/SoundTrigger.VariableControlled.cs b/source/TrainManager/Sounds/MSTS/SoundTrigger.VariableControlled.cs
new file mode 100644
index 0000000000..c90072a984
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/SoundTrigger.VariableControlled.cs
@@ -0,0 +1,169 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBve.Formats.MsTs;
+using SoundManager;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ /// A sound trigger controlled by Variable1 increasing past the setpoint
+ /// Variable1 represents the current wheel rotation speed
+ /// Diesel- EngineRPM
+ /// Electric- TractiveForce
+ /// Steam- CylinderPressure
+ public class Variable1IncPast : SoundTrigger
+ {
+ private readonly double variableValue;
+
+ public Variable1IncPast(SoundBuffer[] buffers, KujuTokenID selectionMethod, double variableValue, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public Variable1IncPast(SoundBuffer buffer, double variableValue, bool soundLoops) : base(buffer, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ if (car.baseTrain.Handles.Power.Actual > 0 && car.CurrentSpeed / 1000 / car.DrivingWheels[0].Radius / System.Math.PI * 5 > variableValue)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+
+ if (car.baseTrain.Handles.Power.Actual == 0 || car.TractionModel.CurrentPower < variableValue)
+ {
+ Triggered = false;
+ }
+ }
+ }
+
+ /// A sound trigger controlled by Variable1 increasing past the setpoint
+ /// Variable1 represents the current wheel rotation speed
+ /// Diesel- EngineRPM
+ /// Electric- TractiveForce
+ /// Steam- CylinderPressure
+ public class Variable1DecPast : SoundTrigger
+ {
+ private readonly double variableValue;
+
+ public Variable1DecPast(SoundBuffer[] buffers, KujuTokenID selectionMethod, double variableValue, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public Variable1DecPast(SoundBuffer buffer, double variableValue, bool soundLoops) : base(buffer, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ if (car.baseTrain.Handles.Power.Actual > 0 && car.CurrentSpeed / 1000 / car.DrivingWheels[0].Radius / System.Math.PI * 5 < variableValue)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+
+ if (car.baseTrain.Handles.Power.Actual == 0 || car.TractionModel.CurrentPower > variableValue)
+ {
+ Triggered = false;
+ }
+ }
+ }
+
+ /// A sound trigger controlled by Variable2 increasing past the setpoint
+ /// Variable2 represents the proportion of power the car's TractionModel is currently generating
+ /// Diesel- EngineRPM
+ /// Electric- TractiveForce
+ /// Steam- CylinderPressure
+ public class Variable2IncPast : SoundTrigger
+ {
+ private readonly double variableValue;
+
+ public Variable2IncPast(SoundBuffer[] buffers, KujuTokenID selectionMethod, double variableValue, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public Variable2IncPast(SoundBuffer buffer, double variableValue, bool soundLoops) : base(buffer, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ if (car.TractionModel.CurrentPower >= variableValue && Triggered == false)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+
+ if (car.TractionModel.CurrentPower < variableValue)
+ {
+ Triggered = false;
+ }
+ }
+ }
+
+ /// A sound trigger controlled by Variable2 decreasing past the setpoint
+ /// Variable2 represents the proportion of power the car's TractionModel is currently generating
+ /// Diesel- EngineRPM
+ /// Electric- TractiveForce
+ /// Steam- CylinderPressure
+ public class Variable2DecPast : SoundTrigger
+ {
+ private readonly double variableValue;
+
+ public Variable2DecPast(SoundBuffer[] buffers, KujuTokenID selectionMethod, double variableValue, bool soundLoops) : base(buffers, selectionMethod, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+ public Variable2DecPast(SoundBuffer buffer, double variableValue, bool soundLoops) : base(buffer, soundLoops)
+ {
+ this.variableValue = variableValue;
+ }
+
+ public override void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+ if (car.TractionModel.CurrentPower <= variableValue && Triggered == false)
+ {
+ soundBuffer = Buffer;
+ soundLoops = SoundLoops;
+ Triggered = true;
+ }
+
+ if (car.TractionModel.CurrentPower > variableValue)
+ {
+ Triggered = false;
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/SoundTrigger.cs b/source/TrainManager/Sounds/MSTS/SoundTrigger.cs
new file mode 100644
index 0000000000..df15f82caf
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/SoundTrigger.cs
@@ -0,0 +1,85 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBve.Formats.MsTs;
+using SoundManager;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ public abstract class SoundTrigger
+ {
+ /// Holds the list of possible sound buffers to be selected from
+ internal readonly SoundBuffer[] Buffers;
+ /// The selection method used to determine the buffer to play
+ private readonly KujuTokenID bufferSelectionMethod;
+ /// Whether the sound loops
+ internal readonly bool SoundLoops;
+ /// Timer used in derived updates
+ internal double Timer;
+ /// The previously selected buffer index
+ internal int BufferIndex;
+ /// Stores whether the trigger is currently active
+ internal bool Triggered;
+ /// Gets the actual sound buffer to be played
+ internal SoundBuffer Buffer
+ {
+ get
+ {
+ switch (bufferSelectionMethod)
+ {
+ case KujuTokenID.SequentialSelection:
+ BufferIndex++;
+ if (BufferIndex > Buffers.Length - 1)
+ {
+ BufferIndex = 0;
+ }
+ break;
+ case KujuTokenID.RandomSelection:
+ BufferIndex = TrainManagerBase.RandomNumberGenerator.Next(0, Buffers.Length - 1);
+ break;
+ }
+ return Buffers[BufferIndex];
+ }
+ }
+
+ internal SoundTrigger(SoundBuffer buffer, bool soundLoops)
+ {
+ Buffers = new[] { buffer };
+ SoundLoops = soundLoops;
+ }
+
+ internal SoundTrigger(SoundBuffer[] buffers, KujuTokenID selectionMethod, bool soundLoops)
+ {
+ Buffers = buffers;
+ bufferSelectionMethod = selectionMethod;
+ SoundLoops = soundLoops;
+ }
+
+ public virtual void Update(double timeElapsed, CarBase car, ref SoundBuffer soundBuffer, ref bool soundLoops)
+ {
+
+ }
+ }
+}
diff --git a/source/TrainManager/Sounds/MSTS/VolumeCurve.cs b/source/TrainManager/Sounds/MSTS/VolumeCurve.cs
new file mode 100644
index 0000000000..ca881a5a1e
--- /dev/null
+++ b/source/TrainManager/Sounds/MSTS/VolumeCurve.cs
@@ -0,0 +1,74 @@
+//Simplified BSD License (BSD-2-Clause)
+//
+//Copyright (c) 2025, Christopher Lees, The OpenBVE Project
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are met:
+//
+//1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using OpenBve.Formats.MsTs;
+using System;
+using TrainManager.Car;
+
+namespace TrainManager.MsTsSounds
+{
+ public class MsTsVolumeCurve
+ {
+ private readonly CarBase car;
+ private readonly Tuple[] volumePoints;
+
+ private readonly KujuTokenID controller;
+
+ public MsTsVolumeCurve(CarBase car, KujuTokenID controller, Tuple[] points)
+ {
+ this.car = car;
+ this.controller = controller;
+ volumePoints = points;
+ }
+
+ public double Volume
+ {
+ get
+ {
+ switch (controller)
+ {
+ case KujuTokenID.SpeedControlled:
+ for (int i = volumePoints.Length - 1; i >= 0; i--)
+ {
+ if (Math.Abs(car.CurrentSpeed) >= volumePoints[i].Item1)
+ {
+ return volumePoints[i].Item2;
+ }
+ }
+ break;
+ case KujuTokenID.Variable2Controlled:
+ for (int i = volumePoints.Length - 1; i >= 0; i--)
+ {
+ if (car.TractionModel.CurrentPower >= volumePoints[i].Item1)
+ {
+ return volumePoints[i].Item2;
+ }
+ }
+ break;
+ }
+ return 0;
+ }
+ }
+ }
+}
diff --git a/source/TrainManager/Train/Station.cs b/source/TrainManager/Train/Station.cs
index 3cad38dcba..625141ce68 100644
--- a/source/TrainManager/Train/Station.cs
+++ b/source/TrainManager/Train/Station.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using OpenBveApi;
using OpenBveApi.Colors;
using OpenBveApi.Hosts;
diff --git a/source/TrainManager/Train/TrainBase.cs b/source/TrainManager/Train/TrainBase.cs
index 6e6a99bdff..296a58236d 100644
--- a/source/TrainManager/Train/TrainBase.cs
+++ b/source/TrainManager/Train/TrainBase.cs
@@ -523,6 +523,10 @@ private void UpdatePhysicsAndControls(double timeElapsed)
for (int i = 0; i < Cars.Length; i++)
{
Cars[i].Run.Update(timeElapsed);
+ for (int j = 0; j < Cars[i].Sounds.ControlledSounds.Count; j++)
+ {
+ Cars[i].Sounds.ControlledSounds[j].Update(timeElapsed);
+ }
}
// safety system
@@ -601,7 +605,7 @@ private void UpdateSpeeds(double timeElapsed)
CenterOfCarPositions[i] = 0.5 * (pr + pf);
CenterOfMassPosition += CenterOfCarPositions[i] * Cars[i].CurrentMass;
TrainMass += Cars[i].CurrentMass;
- // update engine
+ // update engine etc.
if (Cars[i].TractionModel.ProvidesPower && Cars[i].TractionModel != null)
{
Cars[i].TractionModel.Update(timeElapsed);
diff --git a/source/TrainManager/TrainManager.csproj b/source/TrainManager/TrainManager.csproj
index 256b2791de..d23302adb6 100644
--- a/source/TrainManager/TrainManager.csproj
+++ b/source/TrainManager/TrainManager.csproj
@@ -136,9 +136,13 @@
+
+
+
+
@@ -168,6 +172,13 @@
+
+
+
+
+
+
+
@@ -194,6 +205,10 @@
{27134980-4415-4375-a564-40a9014dfa5f}
OpenBveApi
+
+ {e81b7bd8-a326-47d3-b7ee-e9c7d4d119fa}
+ Formats.Msts
+
{4ef680d7-df17-4978-9872-133edc169b4b}
RouteManager2