/// <summary>Parses any command-line arguments passed to the main program</summary> /// <param name="Arguments">A string array of arguments</param> /// <param name="Result">The main dialog result (Used to launch)</param> internal static void ParseArguments(string[] Arguments, ref formMain.MainDialogResult Result) { if (Arguments.Length == 0) { return; } for (int i = 0; i < Arguments.Length; i++) { int equals = Arguments[i].IndexOf('='); if (equals >= 0) { string key = Arguments[i].Substring(0, equals).Trim(new char[] { }).ToLowerInvariant(); string value = Arguments[i].Substring(equals + 1).Trim(new char[] { }); switch (key) { case "/route": Result.RouteFile = value; Result.RouteEncoding = TextEncoding.GetSystemEncodingFromFile(Result.RouteFile); break; case "/train": Result.TrainFolder = value; Result.TrainEncoding = TextEncoding.GetSystemEncodingFromFile(Result.TrainFolder, "train.txt"); break; case "/station": Result.InitialStation = value; break; case "/time": Interface.TryParseTime(value, out Result.StartTime); break; case "/ai": if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1") { Result.AIDriver = true; } break; case "/fullscreen": if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1") { Result.FullScreen = true; } break; case "/width": NumberFormats.TryParseIntVb6(value, out Result.Width); break; case "/height": NumberFormats.TryParseIntVb6(value, out Result.Height); break; } } } }
/// <summary> /// Function to parse TFO definition /// </summary> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="SectionElement">The XElement to parse</param> /// <param name="Train">The track following object to parse this node into</param> private static void ParseDefinitionNode(string FileName, XElement SectionElement, TrackFollowingObject Train) { string Section = SectionElement.Name.LocalName; foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "appearancetime": if (Value.Any() && !Interface.TryParseTime(Value, out Train.AppearanceTime)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "appearancestartposition": if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceStartPosition)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "appearanceendposition": if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceEndPosition)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "leavetime": if (Value.Any() && !Interface.TryParseTime(Value, out Train.LeaveTime)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; default: Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); break; } } }
/// <summary> /// Function to parse the contents of TravelStopData class /// </summary> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="SectionElement">The XElement to parse</param> /// <returns>An instance of the new TravelStopData class with the parse result applied</returns> private static TravelStopData ParseTravelStopNode(string FileName, XElement SectionElement) { string Section = SectionElement.Name.LocalName; TravelStopData Data = new TravelStopData(); ParseTravelDataNode(FileName, SectionElement, Data); foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "stoptime": if (Value.Any() && !Interface.TryParseTime(Value, out Data.StopTime)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "doors": { int Door = 0; bool DoorBoth = false; switch (Value.ToLowerInvariant()) { case "l": case "left": Door = -1; break; case "r": case "right": Door = 1; break; case "n": case "none": case "neither": Door = 0; break; case "b": case "both": DoorBoth = true; break; default: if (Value.Any() && !NumberFormats.TryParseIntVb6(Value, out Door)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; } Data.OpenLeftDoors = Door < 0.0 | DoorBoth; Data.OpenRightDoors = Door > 0.0 | DoorBoth; } break; case "direction": { int d = 0; switch (Value.ToLowerInvariant()) { case "f": d = 1; break; case "r": d = -1; break; default: if (Value.Any() && (!NumberFormats.TryParseIntVb6(Value, out d) || !Enum.IsDefined(typeof(TravelDirection), d))) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); d = 1; } break; } Data.Direction = (TravelDirection)d; } break; case "decelerate": case "position": case "stopposition": case "accelerate": case "targetspeed": case "rail": // Already parsed break; default: Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); break; } } return(Data); }
public static bool ReadMarkerXML(string fileName, ref CsvRwRouteParser.Marker marker) { //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the marker's XML file currentXML.Load(fileName); string Path = System.IO.Path.GetDirectoryName(fileName); if (currentXML.DocumentElement != null) { bool iM = false; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/TextMarker"); if (DocumentNodes == null || DocumentNodes.Count == 0) { DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/ImageMarker"); iM = true; } if (DocumentNodes == null || DocumentNodes.Count == 0) { Interface.AddMessage(MessageType.Error, false, "No marker nodes defined in XML file " + fileName); return(false); } //marker = new CsvRwRouteParser.Marker(); foreach (XmlNode n in DocumentNodes) { if (n.ChildNodes.OfType <XmlElement>().Any()) { bool EarlyDefined = false, LateDefined = false; string EarlyText = null, Text = null, LateText = null; string[] Trains = null; Texture EarlyTexture = null, Texture = null, LateTexture = null; double EarlyTime = 0.0, LateTime = 0.0, TimeOut = Double.PositiveInfinity, EndingPosition = Double.PositiveInfinity; OpenBveApi.Colors.MessageColor EarlyColor = MessageColor.White, OnTimeColor = MessageColor.White, LateColor = MessageColor.White; foreach (XmlNode c in n.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "early": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "No paramaters defined for the early message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": EarlyText = cc.InnerText; break; case "texture": case "image": string f; try { f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(MessageType.Error, false, "MessageEarlyTexture path was malformed in file " + fileName); break; } if (System.IO.File.Exists(f)) { if (!Program.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out EarlyTexture)) { Interface.AddMessage(MessageType.Error, false, "Loading MessageEarlyTexture " + f + " failed."); } } else { Interface.AddMessage(MessageType.Error, false, "MessageEarlyTexture " + f + " does not exist."); } break; case "time": if (!Interface.TryParseTime(cc.InnerText, out EarlyTime)) { Interface.AddMessage(MessageType.Error, false, "Early message time invalid in " + fileName); } EarlyDefined = true; break; case "color": EarlyColor = ParseColor(cc.InnerText, fileName); break; } } break; case "ontime": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "No paramaters defined for the on-time message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": Text = cc.InnerText; break; case "texture": case "image": string f; try { f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(MessageType.Error, false, "MessageTexture path was malformed in file " + fileName); break; } if (System.IO.File.Exists(f)) { if (!Program.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out Texture)) { Interface.AddMessage(MessageType.Error, false, "Loading MessageTexture " + f + " failed."); } } else { Interface.AddMessage(MessageType.Error, false, "MessageTexture " + f + " does not exist."); } break; case "color": OnTimeColor = ParseColor(cc.InnerText, fileName); break; case "time": Interface.AddMessage(MessageType.Error, false, "OnTime should not contain a TIME declaration in " + fileName); break; } } break; case "late": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "No paramaters defined for the late message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": LateText = cc.InnerText; break; case "texture": case "image": string f; try { f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(MessageType.Error, false, "MessageLateTexture path was malformed in file " + fileName); break; } if (System.IO.File.Exists(f)) { if (!Program.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out LateTexture)) { Interface.AddMessage(MessageType.Error, false, "Loading MessageLateTexture " + f + " failed."); } } else { Interface.AddMessage(MessageType.Error, false, "MessageLateTexture " + f + " does not exist."); } break; case "time": if (!Interface.TryParseTime(cc.InnerText, out LateTime)) { Interface.AddMessage(MessageType.Error, false, "Early message time invalid in " + fileName); } LateDefined = true; break; case "color": LateColor = ParseColor(cc.InnerText, fileName); break; } } break; case "timeout": if (!NumberFormats.TryParseDouble(c.InnerText, new[] { 1.0 }, out TimeOut)) { Interface.AddMessage(MessageType.Error, false, "Marker timeout invalid in " + fileName); } break; case "distance": if (!NumberFormats.TryParseDouble(c.InnerText, new[] { 1.0 }, out EndingPosition)) { Interface.AddMessage(MessageType.Error, false, "Marker distance invalid in " + fileName); } break; case "trains": Trains = c.InnerText.Split(';'); break; } } //Check this marker is valid if (TimeOut == Double.PositiveInfinity && EndingPosition == Double.PositiveInfinity) { Interface.AddMessage(MessageType.Error, false, "No marker timeout or distance defined in marker XML " + fileName); return(false); } if (EndingPosition != Double.PositiveInfinity) { if (Math.Abs(EndingPosition) == EndingPosition) { //Positive marker.EndingPosition = marker.StartingPosition + EndingPosition; } else { //Negative marker.EndingPosition = marker.StartingPosition; marker.StartingPosition -= EndingPosition; } } TextureMessage t = new TextureMessage(); GeneralMessage m = new GeneralMessage(); //Add variants if (EarlyDefined) { if (iM) { if (EarlyTexture != null) { t.MessageEarlyTime = EarlyTime; t.MessageEarlyTexture = EarlyTexture; } else { Interface.AddMessage(MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } else { if (EarlyText != null) { m.MessageEarlyTime = EarlyTime; m.MessageEarlyText = EarlyText; m.MessageEarlyColor = EarlyColor; } else { Interface.AddMessage(MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } } if (LateDefined) { if (iM) { if (LateTexture != null) { t.MessageLateTime = LateTime; t.MessageLateTexture = LateTexture; } else { Interface.AddMessage(MessageType.Warning, false, "A late time was defined, but no message was specified in MarkerXML " + fileName); } } else { if (LateText != null) { m.MessageLateTime = LateTime; m.MessageLateText = LateText; m.MessageLateColor = LateColor; } else { Interface.AddMessage(MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } } //Final on-time message if (iM) { t.Trains = Trains; if (Texture != null) { t.MessageOnTimeTexture = Texture; } } else { m.Trains = Trains; if (Text != null) { m.MessageOnTimeText = Text; m.Color = OnTimeColor; } } if (iM) { marker.Message = t; } else { marker.Message = m; } } } } return(true); }
/// <summary>Parses any command-line arguments passed to the main program</summary> /// <param name="Arguments">A string array of arguments</param> /// <param name="Result">The main dialog result (Used to launch)</param> internal static void ParseArguments(string[] Arguments, ref formMain.MainDialogResult Result) { if (Arguments.Length == 0) { return; } for (int i = 0; i < Arguments.Length; i++) { int equals = Arguments[i].IndexOf('='); if (@equals >= 0) { string key = Arguments[i].Substring(0, @equals).Trim().ToLowerInvariant(); string value = Arguments[i].Substring(@equals + 1).Trim(); switch (key) { case "/route": Result.RouteFile = value; switch (TextEncoding.GetEncodingFromFile(Result.RouteFile)) { case TextEncoding.Encoding.Utf7: Result.RouteEncoding = System.Text.Encoding.UTF7; break; case TextEncoding.Encoding.Utf8: Result.RouteEncoding = System.Text.Encoding.UTF8; break; case TextEncoding.Encoding.Utf16Le: Result.RouteEncoding = System.Text.Encoding.Unicode; break; case TextEncoding.Encoding.Utf16Be: Result.RouteEncoding = System.Text.Encoding.BigEndianUnicode; break; case TextEncoding.Encoding.Utf32Le: Result.RouteEncoding = System.Text.Encoding.UTF32; break; case TextEncoding.Encoding.Utf32Be: Result.RouteEncoding = System.Text.Encoding.GetEncoding(12001); break; case TextEncoding.Encoding.Shift_JIS: Result.RouteEncoding = System.Text.Encoding.GetEncoding(932); break; case TextEncoding.Encoding.Windows1252: Result.RouteEncoding = System.Text.Encoding.GetEncoding(1252); break; case TextEncoding.Encoding.Big5: Result.RouteEncoding = System.Text.Encoding.GetEncoding(950); break; default: Result.RouteEncoding = Encoding.Default; break; } break; case "/train": Result.TrainFolder = value; switch (TextEncoding.GetEncodingFromFile(Result.TrainFolder, "train.txt")) { case TextEncoding.Encoding.Utf8: Result.TrainEncoding = System.Text.Encoding.UTF8; break; case TextEncoding.Encoding.Utf16Le: Result.TrainEncoding = System.Text.Encoding.Unicode; break; case TextEncoding.Encoding.Utf16Be: Result.TrainEncoding = System.Text.Encoding.BigEndianUnicode; break; case TextEncoding.Encoding.Utf32Le: Result.TrainEncoding = System.Text.Encoding.UTF32; break; case TextEncoding.Encoding.Utf32Be: Result.TrainEncoding = System.Text.Encoding.GetEncoding(12001); break; case TextEncoding.Encoding.Shift_JIS: Result.TrainEncoding = System.Text.Encoding.GetEncoding(932); break; case TextEncoding.Encoding.Windows1252: Result.TrainEncoding = System.Text.Encoding.GetEncoding(1252); break; case TextEncoding.Encoding.Big5: Result.TrainEncoding = System.Text.Encoding.GetEncoding(950); break; default: Result.TrainEncoding = Encoding.Default; break; } break; case "/station": Result.InitialStation = value; break; case "/time": Interface.TryParseTime(value, out Result.StartTime); break; case "/ai": if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1") { Result.AIDriver = true; } break; case "/fullscreen": if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1") { Result.FullScreen = true; } break; case "/width": NumberFormats.TryParseIntVb6(value, out Result.Width); break; case "/height": NumberFormats.TryParseIntVb6(value, out Result.Height); break; } } } }
//Parses an XML dynamic lighting definition public static bool ReadLightingXML(string fileName) { //Prep Renderer.LightDefinitions = new Renderer.LightDefinition[0]; //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the object's XML file try { currentXML.Load(fileName); } catch { return(false); } bool defined = false; //Check for null if (currentXML.DocumentElement != null) { XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/Brightness"); //Check this file actually contains OpenBVE light definition nodes if (DocumentNodes != null) { foreach (XmlNode n in DocumentNodes) { Renderer.LightDefinition currentLight = new Renderer.LightDefinition(); if (n.ChildNodes.OfType <XmlElement>().Any()) { bool tf = false, al = false, dl = false, ld = false, cb = false; string ts = null; foreach (XmlNode c in n.ChildNodes) { string[] Arguments = c.InnerText.Split(','); switch (c.Name.ToLowerInvariant()) { case "cablighting": double b; if (NumberFormats.TryParseDoubleVb6(Arguments[0].Trim(), out b)) { cb = true; } if (b > 255 || b < 0) { Interface.AddMessage(MessageType.Error, false, c.InnerText + " is not a valid brightness value in file " + fileName); currentLight.CabBrightness = 255; break; } currentLight.CabBrightness = b; break; case "time": double t; if (Interface.TryParseTime(Arguments[0].Trim(), out t)) { currentLight.Time = (int)t; tf = true; //Keep back for error report later ts = Arguments[0]; } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid time in file " + fileName); } break; case "ambientlight": if (Arguments.Length == 3) { double R, G, B; if (NumberFormats.TryParseDoubleVb6(Arguments[0].Trim(), out R) && NumberFormats.TryParseDoubleVb6(Arguments[1].Trim(), out G) && NumberFormats.TryParseDoubleVb6(Arguments[2].Trim(), out B)) { currentLight.AmbientColor = new Color24((byte)R, (byte)G, (byte)B); al = true; } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid color in file " + fileName); } } else { if (Arguments.Length == 1) { if (Color24.TryParseHexColor(Arguments[0], out currentLight.DiffuseColor)) { al = true; break; } } Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not contain three arguments in file " + fileName); } break; case "directionallight": if (Arguments.Length == 3) { double R, G, B; if (NumberFormats.TryParseDoubleVb6(Arguments[0].Trim(), out R) && NumberFormats.TryParseDoubleVb6(Arguments[1].Trim(), out G) && NumberFormats.TryParseDoubleVb6(Arguments[2].Trim(), out B)) { currentLight.DiffuseColor = new Color24((byte)R, (byte)G, (byte)B); dl = true; } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid color in file " + fileName); } } else { if (Arguments.Length == 1) { if (Color24.TryParseHexColor(Arguments[0], out currentLight.DiffuseColor)) { dl = true; break; } } Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not contain three arguments in file " + fileName); } break; case "cartesianlightdirection": case "lightdirection": if (Arguments.Length == 3) { double X, Y, Z; if (NumberFormats.TryParseDoubleVb6(Arguments[0].Trim(), out X) && NumberFormats.TryParseDoubleVb6(Arguments[1].Trim(), out Y) && NumberFormats.TryParseDoubleVb6(Arguments[2].Trim(), out Z)) { currentLight.LightPosition = new Vector3(X, Y, Z); ld = true; } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid direction in file " + fileName); } } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not contain three arguments in file " + fileName); } break; case "sphericallightdirection": if (Arguments.Length == 2) { double theta, phi; if (NumberFormats.TryParseDoubleVb6(Arguments[0].Trim(), out theta) && NumberFormats.TryParseDoubleVb6(Arguments[1].Trim(), out phi)) { currentLight.LightPosition = new Vector3(Math.Cos(theta) * Math.Sin(phi), -Math.Sin(theta), Math.Cos(theta) * Math.Cos(phi)); ld = true; } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid direction in file " + fileName); } } else { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not contain two arguments in file " + fileName); } break; } } //We want to be able to add a completely default light element, but not one that's not been defined in the XML properly if (tf || al || ld || dl || cb) { //HACK: No way to break out of the first loop and continue with the second, so we've got to use a variable bool Break = false; int l = Renderer.LightDefinitions.Length; for (int i = 0; i > l; i++) { if (Renderer.LightDefinitions[i].Time == currentLight.Time) { Break = true; if (ts == null) { Interface.AddMessage(MessageType.Error, false, "Multiple undefined times were encountered in file " + fileName); } else { Interface.AddMessage(MessageType.Error, false, "Duplicate time found: " + ts + " in file " + fileName); } break; } } if (Break) { continue; } //We've got there, so now figure out where to add the new light into our list of light definitions int t = 0; if (l == 1) { t = currentLight.Time > Renderer.LightDefinitions[0].Time ? 1 : 0; } else if (l > 1) { for (int i = 1; i < l; i++) { t = i + 1; if (currentLight.Time > Renderer.LightDefinitions[i - 1].Time && currentLight.Time < Renderer.LightDefinitions[i].Time) { break; } } } //Resize array defined = true; Array.Resize(ref Renderer.LightDefinitions, l + 1); if (t == l) { //Straight insert at the end of the array Renderer.LightDefinitions[l] = currentLight; } else { for (int u = t; u < l; u++) { //Otherwise, shift all elements to compensate Renderer.LightDefinitions[u + 1] = Renderer.LightDefinitions[u]; } Renderer.LightDefinitions[t] = currentLight; } } } } } } //We couldn't find any valid XML, so return false return(defined); }
/// <summary>Parses a base track following object node</summary> /// <param name="Element">The XElement to parse</param> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="Path">The path of the containing XML file</param> /// <param name="Train">The track following object to parse this node into</param> private static void ParseTrackFollowingObjectNode(XElement Element, string FileName, string Path, string ObjectPath, TrainManager.TrackFollowingObject Train) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; string TrainDirectory = string.Empty; bool consistReversed = false; List <Game.TravelData> Data = new List <Game.TravelData>(); foreach (XElement SectionElement in Element.Elements()) { string Section = SectionElement.Name.LocalName; switch (SectionElement.Name.LocalName.ToLowerInvariant()) { case "stops": ParseStopNode(SectionElement, FileName, Data); break; case "train": foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "directory": { string trainDirectory = OpenBveApi.Path.CombineDirectory(Path, Value); if (!System.IO.Directory.Exists(trainDirectory)) { trainDirectory = OpenBveApi.Path.CombineFile(Program.FileSystem.InitialTrainFolder, Value); } if (!System.IO.Directory.Exists(trainDirectory)) { trainDirectory = OpenBveApi.Path.CombineFile(Program.FileSystem.TrainInstallationDirectory, Value); } if (!System.IO.Directory.Exists(trainDirectory)) { trainDirectory = OpenBveApi.Path.CombineFile(ObjectPath, Value); } if (!System.IO.Directory.Exists(trainDirectory)) { Interface.AddMessage(MessageType.Error, false, "Directory was not found in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } else { TrainDirectory = trainDirectory; } } break; case "reversed": int n; NumberFormats.TryParseIntVb6(Value, out n); if (n == 1 || Value.ToLowerInvariant() == "true") { consistReversed = true; } break; } } break; case "definition": foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "appearancetime": if (Value.Length != 0 && !Interface.TryParseTime(Value, out Train.AppearanceTime)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "appearancestartposition": if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceStartPosition)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "appearanceendposition": if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceEndPosition)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "leavetime": if (Value.Length != 0 && !Interface.TryParseTime(Value, out Train.LeaveTime)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; } } break; } } if (!Data.Any() || string.IsNullOrEmpty(TrainDirectory)) { return; } /* * First check for a train.ai file- Functionally identical, but allows for differently configured AI * trains not to show up as driveable */ string TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.ai"); if (!System.IO.File.Exists(TrainData)) { // Check for the standard driveable train.dat TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.dat"); } string ExteriorFile = OpenBveApi.Path.CombineFile(TrainDirectory, "extensions.cfg"); if (!System.IO.File.Exists(TrainData) || !System.IO.File.Exists(ExteriorFile)) { Interface.AddMessage(MessageType.Error, true, "The supplied train folder in TrackFollowingObject " + FileName + " did not contain a complete set of data."); return; } TrainDatParser.ParseTrainData(TrainData, TextEncoding.GetSystemEncodingFromFile(TrainData), Train); SoundCfgParser.ParseSoundConfig(TrainDirectory, Train); Train.AI = new Game.TrackFollowingObjectAI(Train, Data); UnifiedObject[] CarObjects = new UnifiedObject[Train.Cars.Length]; UnifiedObject[] BogieObjects = new UnifiedObject[Train.Cars.Length * 2]; UnifiedObject[] CouplerObjects = new UnifiedObject[Train.Cars.Length - 1]; ExtensionsCfgParser.ParseExtensionsConfig(System.IO.Path.GetDirectoryName(ExteriorFile), TextEncoding.GetSystemEncodingFromFile(ExteriorFile), ref CarObjects, ref BogieObjects, ref CouplerObjects, Train, true); int currentBogieObject = 0; for (int i = 0; i < Train.Cars.Length; i++) { if (CarObjects[i] == null) { // load default exterior object string file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv"); StaticObject so = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, false); if (so == null) { CarObjects[i] = null; } else { double sx = Train.Cars[i].Width; double sy = Train.Cars[i].Height; double sz = Train.Cars[i].Length; so.ApplyScale(sx, sy, sz); CarObjects[i] = so; } } if (CarObjects[i] != null) { // add object Train.Cars[i].LoadCarSections(CarObjects[i]); } //Load bogie objects if (BogieObjects[currentBogieObject] != null) { Train.Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]); } currentBogieObject++; if (BogieObjects[currentBogieObject] != null) { Train.Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]); } currentBogieObject++; } // door open/close speed foreach (var Car in Train.Cars) { if (Car.Specs.DoorOpenFrequency <= 0.0) { if (Car.Doors[0].OpenSound.Buffer != null & Car.Doors[1].OpenSound.Buffer != null) { Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer); Program.Sounds.LoadBuffer(Car.Doors[1].OpenSound.Buffer); double a = Car.Doors[0].OpenSound.Buffer.Duration; double b = Car.Doors[1].OpenSound.Buffer.Duration; Car.Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8; } else if (Car.Doors[0].OpenSound.Buffer != null) { Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer); double a = Car.Doors[0].OpenSound.Buffer.Duration; Car.Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8; } else if (Car.Doors[1].OpenSound.Buffer != null) { Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer); double b = Car.Doors[1].OpenSound.Buffer.Duration; Car.Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8; } else { Car.Specs.DoorOpenFrequency = 0.8; } } if (Car.Specs.DoorCloseFrequency <= 0.0) { if (Car.Doors[0].CloseSound.Buffer != null & Car.Doors[1].CloseSound.Buffer != null) { Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer); Program.Sounds.LoadBuffer(Car.Doors[1].CloseSound.Buffer); double a = Car.Doors[0].CloseSound.Buffer.Duration; double b = Car.Doors[1].CloseSound.Buffer.Duration; Car.Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8; } else if (Car.Doors[0].CloseSound.Buffer != null) { Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer); double a = Car.Doors[0].CloseSound.Buffer.Duration; Car.Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8; } else if (Car.Doors[1].CloseSound.Buffer != null) { Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer); double b = Car.Doors[1].CloseSound.Buffer.Duration; Car.Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8; } else { Car.Specs.DoorCloseFrequency = 0.8; } } const double f = 0.015; const double g = 2.75; Car.Specs.DoorOpenPitch = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5))); Car.Specs.DoorClosePitch = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5))); Car.Specs.DoorOpenFrequency /= Car.Specs.DoorOpenPitch; Car.Specs.DoorCloseFrequency /= Car.Specs.DoorClosePitch; /* * Remove the following two lines, then the pitch at which doors play * takes their randomized opening and closing times into account. * */ Car.Specs.DoorOpenPitch = 1.0; Car.Specs.DoorClosePitch = 1.0; } foreach (var Car in Train.Cars) { Car.FrontAxle.Follower.TrackIndex = Data[0].RailIndex; Car.RearAxle.Follower.TrackIndex = Data[0].RailIndex; Car.FrontBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex; Car.FrontBogie.RearAxle.Follower.TrackIndex = Data[0].RailIndex; Car.RearBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex; Car.RearBogie.RearAxle.Follower.TrackIndex = Data[0].RailIndex; } if (consistReversed) { Train.Reverse(); } Train.PlaceCars(Data[0].StopPosition); }
/// <summary>Parses a train travel stop node</summary> /// <param name="Element">The XElement to parse</param> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="Data">The list of travel data to add this to</param> private static void ParseStopNode(XElement Element, string FileName, List <Game.TravelData> Data) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; foreach (XElement SectionElement in Element.Elements()) { string Section = SectionElement.Name.LocalName; switch (SectionElement.Name.LocalName.ToLowerInvariant()) { case "stop": { Game.TravelData NewData = new Game.TravelData(); double Decelerate = 0.0; double Accelerate = 0.0; double TargetSpeed = 0.0; foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "decelerate": if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Decelerate)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "stopposition": if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out NewData.StopPosition)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "stoptime": if (Value.Length != 0 && !Interface.TryParseTime(Value, out NewData.StopTime)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "doors": { int door = 0; bool doorboth = false; switch (Value.ToLowerInvariant()) { case "l": case "left": door = -1; break; case "r": case "right": door = 1; break; case "n": case "none": case "neither": door = 0; break; case "b": case "both": doorboth = true; break; default: if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out door)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); door = 0; } break; } NewData.OpenLeftDoors = door < 0.0 | doorboth; NewData.OpenRightDoors = door > 0.0 | doorboth; } break; case "accelerate": if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Accelerate)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "targetspeed": if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out TargetSpeed)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; case "direction": { int d = 0; switch (Value.ToLowerInvariant()) { case "f": d = 1; break; case "r": d = -1; break; default: if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out d)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; } if (d == 1 || d == -1) { NewData.Direction = (Game.TravelDirection)d; } } break; case "rail": if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out NewData.RailIndex)) { Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } break; } } NewData.Decelerate = Decelerate / 3.6; NewData.Accelerate = Accelerate / 3.6; NewData.TargetSpeed = TargetSpeed / 3.6; Data.Add(NewData); } break; } } }
//Parses an XML background definition public static BackgroundHandle ReadBackgroundXML(string fileName) { List <StaticBackground> Backgrounds = new List <StaticBackground>(); //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the object's XML file currentXML.Load(fileName); string Path = System.IO.Path.GetDirectoryName(fileName); double[] UnitOfLength = { 1.0 }; //Check for null if (currentXML.DocumentElement != null) { XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/Background"); //Check this file actually contains OpenBVE light definition nodes if (DocumentNodes != null) { foreach (XmlNode n in DocumentNodes) { if (n.ChildNodes.OfType <XmlElement>().Any()) { double DisplayTime = -1; //The time to transition between backgrounds in seconds double TransitionTime = 0.8; //The texture to use (if static) Texture t = null; //The object to use (if object based) StaticObject o = null; //The transition mode between backgrounds BackgroundTransitionMode mode = BackgroundTransitionMode.FadeIn; //The number of times the texture is repeated around the viewing frustrum (if appropriate) double repetitions = 6; foreach (XmlNode c in n.ChildNodes) { string[] Arguments = c.InnerText.Split(','); switch (c.Name.ToLowerInvariant()) { case "mode": switch (c.InnerText.ToLowerInvariant()) { case "fadein": mode = BackgroundTransitionMode.FadeIn; break; case "fadeout": mode = BackgroundTransitionMode.FadeOut; break; case "none": mode = BackgroundTransitionMode.None; break; default: Interface.AddMessage(MessageType.Error, true, c.InnerText + "is not a valid background fade mode in file " + fileName); break; } break; case "object": string f; try { f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), c.InnerText); } catch { Interface.AddMessage(MessageType.Error, true, "BackgroundObject FileName is malformed in file " + fileName); break; } if (!System.IO.File.Exists(f)) { Interface.AddMessage(MessageType.Error, true, "FileName " + f + " not found in file " + fileName); } else { UnifiedObject b = ObjectManager.LoadObject(f, System.Text.Encoding.Default, false); o = (StaticObject)b; } break; case "repetitions": if (!NumberFormats.TryParseDoubleVb6(Arguments[0], UnitOfLength, out repetitions)) { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid number of repetitions in " + fileName); } break; case "texture": string file; try { file = OpenBveApi.Path.CombineFile(Path, c.InnerText); } catch { Interface.AddMessage(MessageType.Error, true, "BackgroundTexture FileName is malformed in file " + fileName); break; } if (!System.IO.File.Exists(file)) { Interface.AddMessage(MessageType.Error, false, "The background texture file " + c.InnerText + " does not exist in " + fileName); } else { Program.CurrentHost.RegisterTexture(file, new TextureParameters(null, null), out t); } break; case "time": if (!Interface.TryParseTime(Arguments[0].Trim(), out DisplayTime)) { Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid time in file " + fileName); } break; case "transitiontime": if (!NumberFormats.TryParseDoubleVb6(Arguments[0], UnitOfLength, out TransitionTime)) { Interface.AddMessage(MessageType.Error, false, c.InnerText + " is not a valid background transition time in " + fileName); } break; } } //Create background if texture is not null if (t != null && o == null) { Backgrounds.Add(new StaticBackground(t, repetitions, false, TransitionTime, mode, DisplayTime)); } if (t == null && o != null) { //All other parameters are ignored if an object has been defined //TODO: Error message stating they have been ignored return(new BackgroundObject(o)); } } } if (Backgrounds.Count == 1) { return(Backgrounds[0]); } if (Backgrounds.Count > 1) { //Sort list- Not worried about when they start or end, so use simple LINQ Backgrounds = Backgrounds.OrderBy(o => o.Time).ToList(); //If more than 2 backgrounds, convert to array and return a new dynamic background return(new DynamicBackground(Backgrounds.ToArray())); } } } //We couldn't find any valid XML, so return false throw new InvalidDataException(); }
public static Game.Station ReadStationXML(string fileName, bool PreviewOnly, Textures.Texture[] daytimeTimetableTextures, Textures.Texture[] nighttimeTimetableTextures, int CurrentStation, ref bool passAlarm, ref CsvRwRouteParser.StopRequest stopRequest) { Game.Station station = new Game.Station { Stops = new Game.StationStop[] { } }; stopRequest.Early = new TrackManager.RequestStop(); stopRequest.OnTime = new TrackManager.RequestStop(); stopRequest.Late = new TrackManager.RequestStop(); stopRequest.OnTime.Probability = 75; //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the object's XML file currentXML.Load(fileName); string Path = System.IO.Path.GetDirectoryName(fileName); //Check for null if (currentXML.DocumentElement != null) { XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/Station"); //Check this file actually contains OpenBVE light definition nodes if (DocumentNodes != null) { foreach (XmlNode n in DocumentNodes) { if (n.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode c in n.ChildNodes) { //string[] Arguments = c.InnerText.Split(','); switch (c.Name.ToLowerInvariant()) { case "name": if (!string.IsNullOrEmpty(c.InnerText)) { station.Name = c.InnerText; } else { Interface.AddMessage(Interface.MessageType.Error, false, "Station name was empty in XML file " + fileName); } break; case "arrivaltime": if (!string.IsNullOrEmpty(c.InnerText)) { if (!Interface.TryParseTime(c.InnerText, out station.ArrivalTime)) { Interface.AddMessage(Interface.MessageType.Error, false, "Station arrival time was invalid in XML file " + fileName); } } break; case "departuretime": if (!string.IsNullOrEmpty(c.InnerText)) { if (!Interface.TryParseTime(c.InnerText, out station.DepartureTime)) { Interface.AddMessage(Interface.MessageType.Error, false, "Station arrival time was invalid in XML file " + fileName); } } break; case "type": switch (c.InnerText.ToLowerInvariant()) { case "c": case "changeends": station.Type = StationType.ChangeEnds; break; case "t": case "terminal": station.Type = StationType.Terminal; break; default: station.Type = StationType.Normal; break; } break; case "passalarm": if (!string.IsNullOrEmpty(c.InnerText)) { if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true") { passAlarm = true; } else { passAlarm = false; } } break; case "doors": int door = 0; bool doorboth = false; if (!string.IsNullOrEmpty(c.InnerText)) { switch (c.InnerText.ToLowerInvariant()) { case "l": case "left": door = -1; break; case "r": case "right": door = 1; break; case "n": case "none": case "neither": door = 0; break; case "b": case "both": doorboth = true; break; default: if (!NumberFormats.TryParseIntVb6(c.InnerText, out door)) { Interface.AddMessage(Interface.MessageType.Error, false, "Door side was invalid in XML file " + fileName); door = 0; } break; } } station.OpenLeftDoors = door < 0.0 | doorboth; station.OpenRightDoors = door > 0.0 | doorboth; break; case "forcedredsignal": if (!string.IsNullOrEmpty(c.InnerText)) { if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true") { station.ForceStopSignal = true; } else { station.ForceStopSignal = false; } } break; case "system": switch (c.InnerText.ToLowerInvariant()) { case "0": case "ATS": station.SafetySystem = Game.SafetySystem.Ats; break; case "1": case "ATC": station.SafetySystem = Game.SafetySystem.Atc; break; default: Interface.AddMessage(Interface.MessageType.Error, false, "An invalid station safety system was specified in XML file " + fileName); station.SafetySystem = Game.SafetySystem.Ats; break; } break; case "arrivalsound": string arrSound = string.Empty; double arrRadius = 30.0; if (!c.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cc in c.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "filename": try { arrSound = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound filename is invalid in XML file " + fileName); } break; case "radius": if (!double.TryParse(cc.InnerText, out arrRadius)) { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound radius was invalid in XML file " + fileName); } break; } } } else { try { arrSound = OpenBveApi.Path.CombineFile(Path, c.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound filename is invalid in XML file " + fileName); } } if (File.Exists(arrSound)) { station.ArrivalSoundBuffer = Sounds.RegisterBuffer(arrSound, arrRadius); } else { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound file does not exist in XML file " + fileName); } break; case "stopduration": double stopDuration; if (!double.TryParse(c.InnerText, out stopDuration)) { Interface.AddMessage(Interface.MessageType.Error, false, "Stop duration is invalid in XML file " + fileName); } else { if (stopDuration < 5.0) { stopDuration = 5.0; } station.StopTime = stopDuration; } break; case "passengerratio": double ratio; if (!double.TryParse(c.InnerText, out ratio)) { Interface.AddMessage(Interface.MessageType.Error, false, "Passenger ratio is invalid in XML file " + fileName); } else { if (ratio < 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "Passenger ratio must be non-negative in XML file " + fileName); ratio = 100.0; } station.PassengerRatio = ratio * 0.01; } break; case "departuresound": string depSound = string.Empty; double depRadius = 30.0; if (!c.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cc in c.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "filename": try { depSound = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound filename is invalid in XML file " + fileName); } break; case "radius": if (!double.TryParse(cc.InnerText, out depRadius)) { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound radius was invalid in XML file " + fileName); } break; } } } else { try { depSound = OpenBveApi.Path.CombineFile(Path, c.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound filename is invalid in XML file " + fileName); } } if (File.Exists(depSound)) { station.DepartureSoundBuffer = Sounds.RegisterBuffer(depSound, depRadius); } else { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound file does not exist in XML file " + fileName); } break; case "timetableindex": if (!PreviewOnly) { int ttidx = -1; if (!string.IsNullOrEmpty(c.InnerText)) { if (NumberFormats.TryParseIntVb6(c.InnerText, out ttidx)) { if (ttidx < 0) { Interface.AddMessage(Interface.MessageType.Error, false, "Timetable index must be non-negative in XML file " + fileName); ttidx = -1; } else if (ttidx >= daytimeTimetableTextures.Length & ttidx >= nighttimeTimetableTextures.Length) { Interface.AddMessage(Interface.MessageType.Error, false, "Timetable index references a non-loaded texture in XML file " + fileName); ttidx = -1; } station.TimetableDaytimeTexture = ttidx >= 0 & ttidx < daytimeTimetableTextures.Length ? daytimeTimetableTextures[ttidx] : null; station.TimetableNighttimeTexture = ttidx >= 0 & ttidx < nighttimeTimetableTextures.Length ? nighttimeTimetableTextures[ttidx] : null; break; } } if (ttidx == -1) { if (CurrentStation > 0) { station.TimetableDaytimeTexture = Game.Stations[CurrentStation - 1].TimetableDaytimeTexture; station.TimetableNighttimeTexture = Game.Stations[CurrentStation - 1].TimetableNighttimeTexture; } else if (daytimeTimetableTextures.Length > 0 & nighttimeTimetableTextures.Length > 0) { station.TimetableDaytimeTexture = daytimeTimetableTextures[0]; station.TimetableNighttimeTexture = nighttimeTimetableTextures[0]; } } } break; case "requeststop": station.Type = StationType.RequestStop; station.StopMode = StationStopMode.AllRequestStop; foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "aibehaviour": switch (cc.InnerText.ToLowerInvariant()) { case "fullspeed": case "0": //With this set, the AI driver will not attempt to brake, but pass through at linespeed stopRequest.FullSpeed = true; break; case "normalbrake": case "1": //With this set, the AI driver breaks to a near stop whilst passing through the station stopRequest.FullSpeed = false; break; } break; case "playeronly": station.StopMode = StationStopMode.PlayerRequestStop; break; case "distance": if (!string.IsNullOrEmpty(cc.InnerText)) { double d; if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out d)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop distance is invalid in XML file " + fileName); break; } stopRequest.TrackPosition -= Math.Abs(d); } break; case "earlytime": if (!string.IsNullOrEmpty(cc.InnerText)) { if (!Interface.TryParseTime(cc.InnerText, out stopRequest.Early.Time)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop early time was invalid in XML file " + fileName); } } break; case "latetime": if (!string.IsNullOrEmpty(cc.InnerText)) { if (!Interface.TryParseTime(cc.InnerText, out stopRequest.Late.Time)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop late time was invalid in XML file " + fileName); } } break; case "stopmessage": if (cc.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cd in cc.ChildNodes) { switch (cd.Name.ToLowerInvariant()) { case "early": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Early.StopMessage = cd.InnerText; } break; case "ontime": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.OnTime.StopMessage = cd.InnerText; } break; case "late": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Late.StopMessage = cd.InnerText; } break; case "#text": stopRequest.Early.StopMessage = cc.InnerText; stopRequest.OnTime.StopMessage = cc.InnerText; stopRequest.Late.StopMessage = cc.InnerText; break; } } } break; case "passmessage": if (cc.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cd in cc.ChildNodes) { switch (cd.Name.ToLowerInvariant()) { case "early": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Early.PassMessage = cd.InnerText; } break; case "ontime": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.OnTime.PassMessage = cd.InnerText; } break; case "late": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Late.PassMessage = cd.InnerText; } break; case "#text": stopRequest.Early.PassMessage = cc.InnerText; stopRequest.OnTime.PassMessage = cc.InnerText; stopRequest.Late.PassMessage = cc.InnerText; break; } } } break; case "probability": foreach (XmlNode cd in cc.ChildNodes) { switch (cd.Name.ToLowerInvariant()) { case "early": if (!string.IsNullOrEmpty(cd.InnerText)) { if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.Early.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop early probability was invalid in XML file " + fileName); } } break; case "ontime": if (!string.IsNullOrEmpty(cd.InnerText)) { if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop ontime probability was invalid in XML file " + fileName); } } break; case "late": if (!string.IsNullOrEmpty(cd.InnerText)) { if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop late probability was invalid in XML file " + fileName); } } break; case "#text": if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop probability was invalid in XML file " + fileName); } break; } } break; case "maxcars": if (!NumberFormats.TryParseIntVb6(cc.InnerText, out stopRequest.MaxNumberOfCars)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop maximum cars was invalid in XML file " + fileName); } break; } } break; } } } } return(station); } } //We couldn't find any valid XML, so return false throw new InvalidDataException(); }