/// <summary>Parses a base track following object node</summary> /// <param name="ObjectPath">Absolute path to the object folder of route data</param> /// <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 ParseTrackFollowingObjectNode(string ObjectPath, string FileName, XElement SectionElement, TrackFollowingObject Train) { string Section = SectionElement.Name.LocalName; string TrainDirectory = string.Empty; bool ConsistReversed = false; List <TravelData> Data = new List <TravelData>(); foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "definition": ParseDefinitionNode(FileName, KeyNode, Train); break; case "train": ParseTrainNode(ObjectPath, FileName, KeyNode, ref TrainDirectory, ref ConsistReversed); break; case "points": case "stops": ParseTravelDataNodes(FileName, KeyNode, Data); break; default: Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); break; } } if (Data.Count < 2) { Interface.AddMessage(MessageType.Error, false, $"There must be at least two points to go through in {FileName}"); return; } if (!(Data.First() is TravelStopData) || !(Data.Last() is TravelStopData)) { Interface.AddMessage(MessageType.Error, false, $"The first and the last point to go through must be the \"Stop\" node in {FileName}"); return; } if (string.IsNullOrEmpty(TrainDirectory)) { Interface.AddMessage(MessageType.Error, false, $"No train has been specified in {FileName}"); return; } /* * First check for a train.ai file- Functionally identical, but allows for differently configured AI * trains not to show up as drivable */ string TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.ai"); if (!File.Exists(TrainData)) { // Check for the standard drivable train.dat TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.dat"); } string ExteriorFile = OpenBveApi.Path.CombineFile(TrainDirectory, "extensions.cfg"); if (!File.Exists(TrainData) || !File.Exists(ExteriorFile)) { Interface.AddMessage(MessageType.Error, true, $"The supplied train folder in TrackFollowingObject {FileName} did not contain a complete set of data."); return; } AbstractTrain currentTrain = Train; for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Train != null && Program.CurrentHost.Plugins[i].Train.CanLoadTrain(TrainData)) { Program.CurrentHost.Plugins[i].Train.LoadTrain(Encoding.UTF8, TrainDirectory, ref currentTrain, ref Interface.CurrentControls); } } if (!Train.Cars.Any()) { Interface.AddMessage(MessageType.Error, false, $"Failed to load the specified train in {FileName}"); return; } Train.AI = new TrackFollowingObjectAI(Train, Data.ToArray()); 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].Position); }
/// <summary> Updates the position and state of the animated object</summary> /// <param name="IsPartOfTrain">Whether this object forms part of a train</param> /// <param name="Train">The train, or a null reference otherwise</param> /// <param name="CarIndex">If this object forms part of a train, the car index it refers to</param> /// <param name="SectionIndex">If this object has been placed via Track.Sig, the index of the section it is attached to</param> /// <param name="TrackPosition"></param> /// <param name="Position"></param> /// <param name="Direction"></param> /// <param name="Up"></param> /// <param name="Side"></param> /// <param name="UpdateFunctions">Whether the functions associated with this object should be re-evaluated</param> /// <param name="Show"></param> /// <param name="TimeElapsed">The time elapsed since this object was last updated</param> /// <param name="EnableDamping">Whether damping is to be applied for this call</param> /// <param name="IsTouch">Whether Animated Object belonging to TouchElement class.</param> /// <param name="Camera"></param> public void Update(bool IsPartOfTrain, AbstractTrain Train, int CarIndex, int SectionIndex, double TrackPosition, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, bool UpdateFunctions, bool Show, double TimeElapsed, bool EnableDamping, bool IsTouch = false, dynamic Camera = null) { // state change if (StateFunction != null & UpdateFunctions) { double sd = StateFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); int si = (int)System.Math.Round(sd); if (si < 0 | si >= States.Length) { si = -1; } if (CurrentState != si) { ObjectType type = ObjectType.Dynamic; if (Camera != null) { type = ObjectType.Overlay; } Initialize(si, type, Show); CurrentState = si; } } if (CurrentState == -1) { return; //not visible state, so don't bother updating } // translation if (TranslateXFunction != null) { double x = TranslateXFunction.LastResult; if (UpdateFunctions) { x = TranslateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } Vector3 translationVector = new Vector3(TranslateXDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= x; Position += translationVector; } else if (TranslateXScriptFile != null) { //Translate X Script if (TranslateXAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateXAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateXScriptFile)) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { currentHost.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateXScriptFile); TranslateXScriptFile = null; return; } } double x = TranslateXAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateXDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= x; Position += translationVector; } if (TranslateYFunction != null) { double y = TranslateYFunction.LastResult; if (UpdateFunctions) { y = TranslateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } Vector3 translationVector = new Vector3(TranslateYDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= y; Position += translationVector; } else if (TranslateYScriptFile != null) { //Translate X Script if (TranslateYAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateYAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateYScriptFile)) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { currentHost.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateYScriptFile); TranslateYScriptFile = null; return; } } double y = TranslateYAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateYDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= y; Position += translationVector; } if (TranslateZFunction != null) { double z = TranslateZFunction.LastResult; if (UpdateFunctions) { z = TranslateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } Vector3 translationVector = new Vector3(TranslateZDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= z; Position += translationVector; } else if (TranslateZScriptFile != null) { //Translate X Script if (TranslateZAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateZAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateZScriptFile)) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { currentHost.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateZScriptFile); TranslateZScriptFile = null; return; } } double z = TranslateZAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateZDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= z; Position += translationVector; } // rotation bool rotateX = RotateXFunction != null; bool rotateY = RotateYFunction != null; bool rotateZ = RotateZFunction != null; double radianX = 0.0; if (rotateX) { radianX = RotateXFunction.LastResult; if (UpdateFunctions) { radianX = RotateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } if (RotateXDamping != null) { RotateXDamping.Update(TimeElapsed, ref radianX, EnableDamping); } } double radianY = 0.0; if (rotateY) { radianY = RotateYFunction.LastResult; if (UpdateFunctions) { radianY = RotateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } if (RotateYDamping != null) { RotateYDamping.Update(TimeElapsed, ref radianY, EnableDamping); } } double radianZ = 0.0; if (rotateZ) { radianZ = RotateZFunction.LastResult; if (UpdateFunctions) { radianZ = RotateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } if (RotateZDamping != null) { RotateZDamping.Update(TimeElapsed, ref radianZ, EnableDamping); } } // texture shift bool shiftx = TextureShiftXFunction != null; bool shifty = TextureShiftYFunction != null; internalObject.TextureTranslation = Matrix4D.Identity; if (shiftx | shifty) { if (shiftx) { double x = TextureShiftXFunction.LastResult; if (UpdateFunctions) { x = TextureShiftXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } x -= System.Math.Floor(x); internalObject.TextureTranslation *= Matrix4D.CreateTranslation(x * TextureShiftXDirection.X, x * TextureShiftXDirection.Y, 1.0); } if (shifty) { double y = TextureShiftYFunction.LastResult; if (UpdateFunctions) { y = TextureShiftYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } y -= System.Math.Floor(y); internalObject.TextureTranslation *= Matrix4D.CreateTranslation(y * TextureShiftYDirection.X, y * TextureShiftYDirection.Y, 1.0); } } // led bool led = LEDFunction != null; double ledangle = 0.0; if (led) { ledangle = LEDFunction.LastResult; if (UpdateFunctions) { ledangle = LEDFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } } // null object if (States[CurrentState].Prototype == null) { return; } // led if (led) { /* * Edges: Vertices: * 0 - bottom 0 - bottom-left * 1 - left 1 - top-left * 2 - top 2 - top-right * 3 - right 3 - bottom-right * 4 - center * */ int v = 1; if (LEDClockwiseWinding) { /* winding is clockwise*/ if (ledangle < LEDInitialAngle) { ledangle = LEDInitialAngle; } if (ledangle < LEDLastAngle) { double currentEdgeFloat = System.Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = System.Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (lastEdge < currentEdge | lastEdge == currentEdge & System.Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { lastEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz); v++; } { double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = new Vector3(cx, cy, cz); States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[currentEdge]; v += 2; } for (int j = currentEdge + 1; j < lastEdge; j++) { /* square-vertex to square-vertex */ States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge % 4].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge % 4].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge % 4].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(lastEdge + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = new Vector3(lx, ly, lz); v += 2; } } } } else { /* winding is counter-clockwise*/ if (ledangle > LEDInitialAngle) { ledangle = LEDInitialAngle; } if (ledangle > LEDLastAngle) { double currentEdgeFloat = System.Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = System.Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (currentEdge < lastEdge | lastEdge == currentEdge & System.Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { currentEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz); v++; } { double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = t - System.Math.Floor(t); t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge % 4].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge % 4].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge % 4].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(currentEdge + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = new Vector3(cx, cy, cz); v += 2; } for (int j = currentEdge - 1; j > lastEdge; j--) { /* square-vertex to square-vertex */ States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = new Vector3(lx, ly, lz); States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[lastEdge % 4]; v += 2; } } } } for (int j = v; v < 11; v++) { States[CurrentState].Prototype.Mesh.Vertices[j].Coordinates = LEDVectors[4]; } } // update prototype internalObject.Prototype = States[CurrentState].Prototype; // update VAO for led if required UpdateVAO = led; // update state // rotate internalObject.Rotate = Matrix4D.Identity; if (rotateX) { internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateXDirection.X, RotateXDirection.Y, -RotateXDirection.Z), 2.0 * System.Math.PI - radianX); } if (rotateY) { internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateYDirection.X, RotateYDirection.Y, -RotateYDirection.Z), 2.0 * System.Math.PI - radianY); } if (rotateZ) { internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateZDirection.X, RotateZDirection.Y, -RotateZDirection.Z), 2.0 * System.Math.PI - radianZ); } if (Camera != null && Camera.CurrentRestriction != CameraRestrictionMode.NotAvailable && Camera.CurrentRestriction != CameraRestrictionMode.Restricted3D) { internalObject.Rotate *= States[CurrentState].Translation * Matrix4D.CreateTranslation(-Position.X, -Position.Y, Position.Z); internalObject.Rotate *= (Matrix4D) new Transformation((Vector3)Camera.AbsoluteDirection, (Vector3)Camera.AbsoluteUp, (Vector3)Camera.AbsoluteSide); // translate double dx = -System.Math.Tan(Camera.Alignment.Yaw) - Camera.Alignment.Position.X; double dy = -System.Math.Tan(Camera.Alignment.Pitch) - Camera.Alignment.Position.Y; double dz = -Camera.Alignment.Position.Z; Vector3 add = Camera.AbsolutePosition + dx * Camera.AbsoluteSide + dy * Camera.AbsoluteUp + dz * Camera.AbsoluteDirection; internalObject.Translation = Matrix4D.CreateTranslation(add.X, add.Y, -add.Z); } else { internalObject.Rotate *= States[CurrentState].Translation; internalObject.Rotate *= (Matrix4D) new Transformation(Direction, Up, Side); // translate internalObject.Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z); } // visibility changed // TouchElement is handled by another function. if (!IsTouch) { if (Show) { if (Camera != null) { currentHost.ShowObject(internalObject, ObjectType.Overlay); } else { currentHost.ShowObject(internalObject, ObjectType.Dynamic); } } else { currentHost.HideObject(internalObject); } } }
internal static void RefreshObjects() { LightingRelative = -1.0; Game.Reset(); for (int i = 0; i < Files.Length; i++) { try { if (String.Compare(System.IO.Path.GetFileName(Files[i]), "extensions.cfg", StringComparison.OrdinalIgnoreCase) == 0) { string currentTrainFolder = System.IO.Path.GetDirectoryName(Files[i]); for (int j = 0; j < Program.CurrentHost.Plugins.Length; j++) { if (Program.CurrentHost.Plugins[j].Train != null && Program.CurrentHost.Plugins[j].Train.CanLoadTrain(currentTrainFolder)) { TrainManager.Trains = new TrainBase[1]; Control[] dummyControls = new Control[0]; TrainManager.Trains[0] = new TrainManager.Train(); AbstractTrain playerTrain = TrainManager.Trains[0] as AbstractTrain; Program.CurrentHost.Plugins[j].Train.LoadTrain(Encoding.UTF8, currentTrainFolder, ref playerTrain, ref dummyControls); TrainManager.PlayerTrain = TrainManager.Trains[0]; break; } } TrainManager.PlayerTrain.Initialize(); foreach (var Car in TrainManager.PlayerTrain.Cars) { double length = TrainManager.PlayerTrain.Cars[0].Length; Car.Move(-length); Car.Move(length); } TrainManager.PlayerTrain.PlaceCars(0); for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].UpdateTrackFollowers(0, true, false); TrainManager.PlayerTrain.Cars[j].ChangeCarSection(CarSectionType.Exterior); TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0); } } else { UnifiedObject o; Program.CurrentHost.LoadObject(Files[i], System.Text.Encoding.UTF8, out o); o.CreateObject(Vector3.Zero, 0.0, 0.0, 0.0); } } catch (Exception ex) { Interface.AddMessage(MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + "."); } } Renderer.InitializeVisibility(); Renderer.UpdateViewingDistances(600); Renderer.UpdateVisibility(0.0, true); ObjectManager.UpdateAnimatedWorldObjects(0.01, true); Program.TrainManager.UpdateTrainObjects(0.0, true); Renderer.ApplyBackgroundColor(); }
/// <summary>Updates the specified signal section</summary> /// <param name="secondsSinceMidnight">The in-game time in seconds since midnight</param> public void Update(double secondsSinceMidnight) { // preparations int zeroaspect; bool settored = false; if (Type == SectionType.ValueBased) { // value-based zeroaspect = 0; for (int i = 1; i < Aspects.Length; i++) { if (Aspects[i].Number < Aspects[zeroaspect].Number) { zeroaspect = i; } } } else { // index-based zeroaspect = 0; } // hold station departure signal at red int d = StationIndex; if (d >= 0) { // look for train in previous blocks int l = PreviousSection; AbstractTrain train = null; while (true) { if (l >= 0) { train = CurrentRoute.Sections[l].GetFirstTrain(false); if (train != null) { break; } l = CurrentRoute.Sections[l].PreviousSection; } else { break; } } if (train == null) { double b = -double.MaxValue; for (int i = 0; i < CurrentRoute.Trains.Length; i++) { if (CurrentRoute.Trains[i].State == TrainState.Available) { if (CurrentRoute.Trains[i].TimetableDelta > b) { b = CurrentRoute.Trains[i].TimetableDelta; train = CurrentRoute.Trains[i]; } } } } // set to red where applicable if (train != null) { if (!TrainReachedStopPoint) { if (train.Station == d) { int c = CurrentRoute.Stations[d].GetStopIndex(train.NumberOfCars); if (c >= 0) { double p0 = train.FrontCarTrackPosition(); double p1 = CurrentRoute.Stations[d].Stops[c].TrackPosition - CurrentRoute.Stations[d].Stops[c].BackwardTolerance; if (p0 >= p1) { TrainReachedStopPoint = true; } } else { TrainReachedStopPoint = true; } } } double t = -15.0; if (CurrentRoute.Stations[d].DepartureTime >= 0.0) { t = CurrentRoute.Stations[d].DepartureTime - 15.0; } else if (CurrentRoute.Stations[d].ArrivalTime >= 0.0) { t = CurrentRoute.Stations[d].ArrivalTime; } if (train.IsPlayerTrain & CurrentRoute.Stations[d].Type != StationType.Normal & CurrentRoute.Stations[d].DepartureTime < 0.0) { settored = true; } else if (t >= 0.0 & secondsSinceMidnight < t - train.TimetableDelta) { settored = true; } else if (!TrainReachedStopPoint) { settored = true; } } else if (CurrentRoute.Stations[d].Type != StationType.Normal) { settored = true; } } // train in block if (!IsFree()) { settored = true; } // free sections int newaspect = -1; if (settored) { FreeSections = 0; newaspect = zeroaspect; } else { int n = NextSection; if (n >= 0) { if (CurrentRoute.Sections[n].FreeSections == -1) { FreeSections = -1; } else { FreeSections = CurrentRoute.Sections[n].FreeSections + 1; } } else { FreeSections = -1; } } // change aspect if (newaspect == -1) { if (Type == SectionType.ValueBased) { // value-based int n = NextSection; int a = Aspects[Aspects.Length - 1].Number; if (n >= 0 && CurrentRoute.Sections[n].CurrentAspect >= 0) { a = CurrentRoute.Sections[n].Aspects[CurrentRoute.Sections[n].CurrentAspect].Number; } for (int i = Aspects.Length - 1; i >= 0; i--) { if (Aspects[i].Number > a) { newaspect = i; } } if (newaspect == -1) { newaspect = Aspects.Length - 1; } } else { // index-based if (FreeSections >= 0 & FreeSections < Aspects.Length) { newaspect = FreeSections; } else { newaspect = Aspects.Length - 1; } } } // apply new aspect CurrentAspect = newaspect; // update previous section if (PreviousSection >= 0 && PreviousSection < CurrentRoute.Sections.Length) { CurrentRoute.Sections[PreviousSection].Update(secondsSinceMidnight); } }
/// <summary>Checks whether the section is free, disregarding the specified train.</summary> /// <param name="train">The train to disregard.</param> /// <returns>Whether the section is free, disregarding the specified train.</returns> public bool IsFree(AbstractTrain train) { return(Trains.All(t => !(t != train & (t.State == TrainState.Available | t.State == TrainState.Bogus)))); }
/// <summary>Checks whether a train is currently within the section</summary> /// <param name="Train">The train</param> /// <returns>True if the train is within the section, false otherwise</returns> public bool Exists(AbstractTrain Train) { return(Trains.Any(t => t == Train)); }
public override void Trigger(int Direction, EventTriggerType TriggerType, AbstractTrain Train, AbstractCar Car) { if (Train == null) { return; } if (Train.RouteLimits == null) { Train.RouteLimits = new double[] { }; } if (Direction < 0) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { int n = Train.RouteLimits.Length; if (n > 0) { Array.Resize(ref Train.RouteLimits, n - 1); Train.CurrentRouteLimit = double.PositiveInfinity; for (int i = 0; i < n - 1; i++) { if (Train.RouteLimits[i] < Train.CurrentRouteLimit) { Train.CurrentRouteLimit = Train.RouteLimits[i]; } } } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { int n = Train.RouteLimits.Length; Array.Resize(ref Train.RouteLimits, n + 1); for (int i = n; i > 0; i--) { Train.RouteLimits[i] = Train.RouteLimits[i - 1]; } Train.RouteLimits[0] = PreviousSpeedLimit; } } else if (Direction > 0) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { int n = Train.RouteLimits.Length; Array.Resize(ref Train.RouteLimits, n + 1); Train.RouteLimits[n] = NextSpeedLimit; if (NextSpeedLimit < Train.CurrentRouteLimit) { Train.CurrentRouteLimit = NextSpeedLimit; } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { int n = Train.RouteLimits.Length; if (n > 0) { Train.CurrentRouteLimit = double.PositiveInfinity; for (int i = 0; i < n - 1; i++) { Train.RouteLimits[i] = Train.RouteLimits[i + 1]; if (Train.RouteLimits[i] < Train.CurrentRouteLimit) { Train.CurrentRouteLimit = Train.RouteLimits[i]; } } Array.Resize(ref Train.RouteLimits, n - 1); } } } }
internal static void RefreshObjects() { LightingRelative = -1.0; Game.Reset(); formTrain.Instance?.DisableUI(); for (int i = 0; i < Files.Count; i++) { try { if (Files[i].EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase)) { string currentTrainFolder = System.IO.Path.GetDirectoryName(Files[i]); 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)) { Control[] dummyControls = new Control[0]; TrainManager.Trains = new[] { new TrainBase(TrainState.Available) }; AbstractTrain playerTrain = TrainManager.Trains[0]; Program.CurrentHost.Plugins[j].Train.LoadTrain(Encoding.UTF8, currentTrainFolder, ref playerTrain, ref dummyControls); TrainManager.PlayerTrain = TrainManager.Trains[0]; canLoad = true; break; } } if (canLoad) { TrainManager.PlayerTrain.Initialize(); foreach (var Car in TrainManager.PlayerTrain.Cars) { double length = TrainManager.PlayerTrain.Cars[0].Length; Car.Move(-length); Car.Move(length); } TrainManager.PlayerTrain.PlaceCars(0); for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].UpdateTrackFollowers(0, true, false); TrainManager.PlayerTrain.Cars[j].UpdateTopplingCantAndSpring(0.0); TrainManager.PlayerTrain.Cars[j].ChangeCarSection(CarSectionType.Exterior); TrainManager.PlayerTrain.Cars[j].FrontBogie.UpdateTopplingCantAndSpring(); TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].RearBogie.UpdateTopplingCantAndSpring(); TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].Coupler.ChangeSection(0); } } else { //As we now attempt to load the train as a whole, the most likely outcome is that the train.dat file is MIA Interface.AddMessage(MessageType.Critical, false, "No plugin found capable of loading file " + Files[i] + "."); } } else { UnifiedObject o; if (CurrentHost.LoadObject(Files[i], System.Text.Encoding.UTF8, out o)) { o.CreateObject(Vector3.Zero, 0.0, 0.0, 0.0); } } } catch (Exception ex) { Interface.AddMessage(MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + "."); } } NearestTrain.UpdateSpecs(); NearestTrain.Apply(); formTrain.Instance?.EnableUI(); Renderer.InitializeVisibility(); Renderer.UpdateViewingDistances(600); Renderer.UpdateVisibility(0.0, true); ObjectManager.UpdateAnimatedWorldObjects(0.01, true); Program.TrainManager.UpdateTrainObjects(0.0, true); Renderer.ApplyBackgroundColor(); }
/// <summary>Updates the specified signal section</summary> /// <param name="Section"></param> /// <param name="PreviousSection"></param> public void UpdateSection(Section Section, out Section PreviousSection) { if (Section == null) { PreviousSection = null; return; } // preparations int zeroAspect; bool setToRed = false; if (Section.Type == SectionType.ValueBased) { // value-based zeroAspect = 0; for (int i = 1; i < Section.Aspects.Length; i++) { if (Section.Aspects[i].Number < Section.Aspects[zeroAspect].Number) { zeroAspect = i; } } } else { // index-based zeroAspect = 0; } // hold station departure signal at red int d = Section.StationIndex; if (d >= 0) { // look for train in previous blocks Section l = Section.PreviousSection; AbstractTrain train = null; while (true) { if (l != null) { train = l.GetFirstTrain(false); if (train != null) { break; } l = l.PreviousSection; } else { break; } } if (train == null) { double b = -Double.MaxValue; foreach (AbstractTrain t in currentHost.Trains) { if (t.State == TrainState.Available) { if (t.TimetableDelta > b) { b = t.TimetableDelta; train = t; } } } } // set to red where applicable if (train != null) { if (!Section.TrainReachedStopPoint) { if (train.Station == d) { int c = Stations[d].GetStopIndex(train.NumberOfCars); if (c >= 0) { double p0 = train.FrontCarTrackPosition(); double p1 = Stations[d].Stops[c].TrackPosition - Stations[d].Stops[c].BackwardTolerance; if (p0 >= p1) { Section.TrainReachedStopPoint = true; } } else { Section.TrainReachedStopPoint = true; } } } double t = -15.0; if (Stations[d].DepartureTime >= 0.0) { t = Stations[d].DepartureTime - 15.0; } else if (Stations[d].ArrivalTime >= 0.0) { t = Stations[d].ArrivalTime; } if (train.IsPlayerTrain & Stations[d].Type != StationType.Normal & Stations[d].DepartureTime < 0.0) { setToRed = true; } else if (t >= 0.0 & SecondsSinceMidnight < t - train.TimetableDelta) { setToRed = true; } else if (!Section.TrainReachedStopPoint) { setToRed = true; } } else if (Stations[d].Type != StationType.Normal) { setToRed = true; } } // train in block if (!Section.IsFree()) { setToRed = true; } // free sections int newAspect = -1; if (setToRed) { Section.FreeSections = 0; newAspect = zeroAspect; } else { Section n = Section.NextSection; if (n != null) { if (n.FreeSections == -1) { Section.FreeSections = -1; } else { Section.FreeSections = n.FreeSections + 1; } } else { Section.FreeSections = -1; } } // change aspect if (newAspect == -1) { if (Section.Type == SectionType.ValueBased) { // value-based Section n = Section.NextSection; int a = Section.Aspects.Last().Number; if (n != null && n.CurrentAspect >= 0) { a = n.Aspects[n.CurrentAspect].Number; } for (int i = Section.Aspects.Length - 1; i >= 0; i--) { if (Section.Aspects[i].Number > a) { newAspect = i; } } if (newAspect == -1) { newAspect = Section.Aspects.Length - 1; } } else { // index-based if (Section.FreeSections >= 0 & Section.FreeSections < Section.Aspects.Length) { newAspect = Section.FreeSections; } else { newAspect = Section.Aspects.Length - 1; } } } // apply new aspect Section.CurrentAspect = newAspect; // update previous section PreviousSection = Section.PreviousSection; }
/// <summary>Updates the object</summary> /// <param name="NearestTrain">The nearest train to this object</param> /// <param name="TimeElapsed">The time elapsed in milliseconds</param> /// <param name="ForceUpdate">Whether this is a forced update (e.g. Change of viewpoint) or periodic</param> /// <param name="CurrentlyVisible">Whether the object is currently visble to the player</param> public abstract void Update(AbstractTrain NearestTrain, double TimeElapsed, bool ForceUpdate, bool CurrentlyVisible);
/// <summary>Plays a car sound.</summary> /// <param name="sound">The car sound.</param> /// <param name="pitch">The pitch change factor.</param> /// <param name="volume">The volume change factor.</param> /// <param name="train">The train the sound is attached to.</param> /// <param name="car">The car in the train the sound is attached to.</param> /// <param name="looped">Whether to play the sound in a loop.</param> /// <returns>The sound source.</returns> internal static void PlayCarSound(TrainManager.CarSound sound, double pitch, double volume, AbstractTrain train, int car, bool looped) { if (sound.Buffer == null) { return; } if (train == null) { throw new InvalidDataException("A train and car must be specified"); } sound.Source = PlaySound(sound.Buffer, pitch, volume, sound.Position, train, car, looped); }
/// <summary>The unconditional event trigger function</summary> /// <param name="Direction">The direction: /// 1 - Forwards /// -1 - Reverse</param> /// <param name="TriggerType">The trigger type (Car axle, camera follower etc.)</param> /// <param name="Train">The train, or a null reference</param> /// <param name="Car">The car, or a null reference</param> public abstract void Trigger(int Direction, EventTriggerType TriggerType, AbstractTrain Train, AbstractCar Car);
/// <summary>Called every frame to update the plugin.</summary> public void UpdatePlugin() { if (Train.Cars == null || Train.Cars.Length == 0) { return; } /* * Prepare the vehicle state. * */ double location = this.Train.Cars[0].FrontAxle.Follower.TrackPosition - this.Train.Cars[0].FrontAxle.Position + 0.5 * this.Train.Cars[0].Length; //If the list of stations has not been loaded, do so if (!StationsLoaded) { currentRouteStations = new List <Station>(); int s = 0; foreach (RouteStation selectedStation in TrainManagerBase.CurrentRoute.Stations) { double stopPosition = -1; int stopIdx = TrainManagerBase.CurrentRoute.Stations[s].GetStopIndex(Train.NumberOfCars); if (selectedStation.Stops.Length != 0) { stopPosition = selectedStation.Stops[stopIdx].TrackPosition; } Station i = new Station(selectedStation, stopPosition); currentRouteStations.Add(i); s++; } StationsLoaded = true; } //End of additions double speed = this.Train.Cars[this.Train.DriverCar].Specs.PerceivedSpeed; double bcPressure = this.Train.Cars[this.Train.DriverCar].CarBrake.brakeCylinder.CurrentPressure; double mrPressure = this.Train.Cars[this.Train.DriverCar].CarBrake.mainReservoir.CurrentPressure; double erPressure = this.Train.Cars[this.Train.DriverCar].CarBrake.equalizingReservoir.CurrentPressure; double bpPressure = this.Train.Cars[this.Train.DriverCar].CarBrake.brakePipe.CurrentPressure; double sapPressure = this.Train.Cars[this.Train.DriverCar].CarBrake.straightAirPipe.CurrentPressure; VehicleState vehicle = new VehicleState(location, new Speed(speed), bcPressure, mrPressure, erPressure, bpPressure, sapPressure, this.Train.Cars[0].FrontAxle.Follower); /* * Prepare the preceding vehicle state. * */ PrecedingVehicleState precedingVehicle; try { AbstractTrain closestTrain = TrainManagerBase.currentHost.ClosestTrain(this.Train); precedingVehicle = closestTrain != null ? new PrecedingVehicleState(closestTrain.RearCarTrackPosition(), closestTrain.RearCarTrackPosition() - location, new Speed(closestTrain.CurrentSpeed)) : new PrecedingVehicleState(Double.MaxValue, Double.MaxValue - location, new Speed(0.0)); } catch { precedingVehicle = null; } /* * Get the driver handles. * */ OpenBveApi.Runtime.Handles handles = GetHandles(); /* * Update the plugin. * */ double totalTime = TrainManagerBase.currentHost.InGameTime; double elapsedTime = TrainManagerBase.currentHost.InGameTime - LastTime; ElapseData data = new ElapseData(vehicle, precedingVehicle, handles, this.Train.SafetySystems.DoorInterlockState, new Time(totalTime), new Time(elapsedTime), currentRouteStations, TrainManagerBase.Renderer.Camera.CurrentMode, Translations.CurrentLanguageCode, this.Train.Destination); ElapseData inputDevicePluginData = data; LastTime = TrainManagerBase.currentHost.InGameTime; Elapse(ref data); this.PluginMessage = data.DebugMessage; this.Train.SafetySystems.DoorInterlockState = data.DoorInterlockState; DisableTimeAcceleration = data.DisableTimeAcceleration; for (int i = 0; i < InputDevicePlugin.AvailablePluginInfos.Count; i++) { if (InputDevicePlugin.AvailablePluginInfos[i].Status == InputDevicePlugin.PluginInfo.PluginStatus.Enable) { InputDevicePlugin.AvailablePlugins[i].SetElapseData(inputDevicePluginData); } } /* * Set the virtual handles. * */ this.PluginValid = true; SetHandles(data.Handles, true); this.Train.Destination = data.Destination; }
public override bool LoadTrain(Encoding Encoding, string trainPath, ref AbstractTrain train, ref Control[] currentControls) { CurrentProgress = 0.0; LastProgress = 0.0; IsLoading = true; CurrentControls = currentControls; TrainBase currentTrain = train as TrainBase; if (currentTrain == null) { currentHost.ReportProblem(ProblemType.InvalidData, "Train was not valid"); IsLoading = false; return(false); } if (currentTrain.State == TrainState.Bogus) { // bogus train string TrainData = Path.CombineFile(FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat"); TrainDatParser.Parse(TrainData, Encoding.UTF8, currentTrain); Thread.Sleep(1); if (Cancel) { IsLoading = false; return(false); } } else { currentTrain.TrainFolder = trainPath; // real train if (currentTrain.IsPlayerTrain) { FileSystem.AppendToLogFile("Loading player train: " + currentTrain.TrainFolder); } else { FileSystem.AppendToLogFile("Loading AI train: " + currentTrain.TrainFolder); } string TrainData = null; if (!currentTrain.IsPlayerTrain) { TrainData = Path.CombineFile(currentTrain.TrainFolder, "train.ai"); } if (currentTrain.IsPlayerTrain || !File.Exists(TrainData)) { TrainData = Path.CombineFile(currentTrain.TrainFolder, "train.dat"); } TrainDatParser.Parse(TrainData, Encoding, currentTrain); LastProgress = 0.1; Thread.Sleep(1); if (Cancel) { return(false); } SoundCfgParser.ParseSoundConfig(currentTrain); LastProgress = 0.2; Thread.Sleep(1); if (Cancel) { IsLoading = false; return(false); } // door open/close speed for (int i = 0; i < currentTrain.Cars.Length; i++) { currentTrain.Cars[i].DetermineDoorClosingSpeed(); } } // add panel section if (currentTrain.IsPlayerTrain) { ParsePanelConfig(currentTrain, Encoding); LastProgress = 0.6; Thread.Sleep(1); if (Cancel) { IsLoading = false; return(false); } FileSystem.AppendToLogFile("Train panel loaded sucessfully."); } // add exterior section if (currentTrain.State != TrainState.Bogus) { bool[] VisibleFromInterior; UnifiedObject[] CarObjects = new UnifiedObject[currentTrain.Cars.Length]; UnifiedObject[] BogieObjects = new UnifiedObject[currentTrain.Cars.Length * 2]; UnifiedObject[] CouplerObjects = new UnifiedObject[currentTrain.Cars.Length]; string tXml = Path.CombineFile(currentTrain.TrainFolder, "train.xml"); if (File.Exists(tXml)) { TrainXmlParser.Parse(tXml, currentTrain, ref CarObjects, ref BogieObjects, ref CouplerObjects, out VisibleFromInterior); } else { ExtensionsCfgParser.ParseExtensionsConfig(currentTrain.TrainFolder, Encoding, ref CarObjects, ref BogieObjects, ref CouplerObjects, out VisibleFromInterior, currentTrain); } currentTrain.CameraCar = currentTrain.DriverCar; Thread.Sleep(1); if (Cancel) { IsLoading = false; return(false); } //Stores the current array index of the bogie object to add //Required as there are two bogies per car, and we're using a simple linear array.... int currentBogieObject = 0; for (int i = 0; i < currentTrain.Cars.Length; i++) { if (CarObjects[i] == null) { // load default exterior object string file = Path.CombineFile(FileSystem.GetDataFolder("Compatibility"), "exterior.csv"); currentHost.LoadStaticObject(file, Encoding.UTF8, false, out var so); if (so == null) { CarObjects[i] = null; } else { StaticObject c = (StaticObject)so.Clone(); //Clone as otherwise the cached object doesn't scale right c.ApplyScale(currentTrain.Cars[i].Width, currentTrain.Cars[i].Height, currentTrain.Cars[i].Length); CarObjects[i] = c; } } if (CarObjects[i] != null) { // add object currentTrain.Cars[i].LoadCarSections(CarObjects[i], VisibleFromInterior[i]); } if (CouplerObjects[i] != null) { currentTrain.Cars[i].Coupler.LoadCarSections(CouplerObjects[i], VisibleFromInterior[i]); } //Load bogie objects if (BogieObjects[currentBogieObject] != null) { currentTrain.Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject], VisibleFromInterior[i]); } currentBogieObject++; if (BogieObjects[currentBogieObject] != null) { currentTrain.Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject], VisibleFromInterior[i]); } currentBogieObject++; } } // place cars currentTrain.PlaceCars(0.0); currentControls = CurrentControls; IsLoading = false; return(true); }
/// <summary>Executes a function script in the host application</summary> /// <param name="functionScript">The function script to execute</param> /// <param name="train">The train or a null reference</param> /// <param name="CarIndex">The car index</param> /// <param name="Position">The world position</param> /// <param name="TrackPosition">The linear track position</param> /// <param name="SectionIndex">The index to the signalling section</param> /// <param name="IsPartOfTrain">Whether this is part of a train</param> /// <param name="TimeElapsed">The frame time elapsed</param> /// <param name="CurrentState">The current state of the attached object</param> public virtual void ExecuteFunctionScript(FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) { }
/// <summary> Updates the position and state of the animated object</summary> /// <param name="IsPartOfTrain">Whether this object forms part of a train</param> /// <param name="Train">The train, or a null reference otherwise</param> /// <param name="CarIndex">If this object forms part of a train, the car index it refers to</param> /// <param name="SectionIndex">If this object has been placed via Track.Sig, the index of the section it is attached to</param> /// <param name="TrackPosition"></param> /// <param name="Position"></param> /// <param name="Direction"></param> /// <param name="Up"></param> /// <param name="Side"></param> /// <param name="Overlay">Whether this object should be overlaid over the other objects on-screen (Forms part of the cab etc.)</param> /// <param name="UpdateFunctions">Whether the functions associated with this object should be re-evaluated</param> /// <param name="Show"></param> /// <param name="TimeElapsed">The time elapsed since this object was last updated</param> /// <param name="EnableDamping">Whether damping is to be applied for this call</param> /// <param name="IsTouch">Whether Animated Object belonging to TouchElement class.</param> internal void Update(bool IsPartOfTrain, AbstractTrain Train, int CarIndex, int SectionIndex, double TrackPosition, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, bool Overlay, bool UpdateFunctions, bool Show, double TimeElapsed, bool EnableDamping, bool IsTouch = false) { int s = CurrentState; int i = ObjectIndex; // state change if (StateFunction != null & UpdateFunctions) { double sd = StateFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); int si = (int)Math.Round(sd); int sn = States.Length; if (si < 0 | si >= sn) { si = -1; } if (s != si) { Initialize(si, Overlay, Show); s = si; } } if (s == -1) { return; } // translation if (TranslateXFunction != null) { double x; if (UpdateFunctions) { x = TranslateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { x = TranslateXFunction.LastResult; } Vector3 translationVector = new Vector3(TranslateXDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= x; Position += translationVector; } else if (TranslateXScriptFile != null) { //Translate X Script if (TranslateXAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateXAnimationScript = CSScript.LoadCodeFrom(TranslateXScriptFile) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { Interface.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateXScriptFile); TranslateXScriptFile = null; return; } } double x = TranslateXAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateXDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= x; Position += translationVector; } if (TranslateYFunction != null) { double y; if (UpdateFunctions) { y = TranslateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { y = TranslateYFunction.LastResult; } Vector3 translationVector = new Vector3(TranslateYDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= y; Position += translationVector; } else if (TranslateYScriptFile != null) { //Translate X Script if (TranslateYAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateYAnimationScript = CSScript.LoadCodeFrom(TranslateYScriptFile) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { Interface.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateYScriptFile); TranslateYScriptFile = null; return; } } double y = TranslateYAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateYDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= y; Position += translationVector; } if (TranslateZFunction != null) { double z; if (UpdateFunctions) { z = TranslateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { z = TranslateZFunction.LastResult; } Vector3 translationVector = new Vector3(TranslateZDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= z; Position += translationVector; } else if (TranslateZScriptFile != null) { //Translate X Script if (TranslateZAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateZAnimationScript = CSScript.LoadCodeFrom(TranslateZScriptFile) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { Interface.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateZScriptFile); TranslateZScriptFile = null; return; } } double z = TranslateZAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateZDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= z; Position += translationVector; } // rotation bool rotateX = RotateXFunction != null; bool rotateY = RotateYFunction != null; bool rotateZ = RotateZFunction != null; double cosX, sinX; if (rotateX) { double a; if (UpdateFunctions) { a = RotateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { a = RotateXFunction.LastResult; } if (RotateXDamping != null) { RotateXDamping.Update(TimeElapsed, ref a, EnableDamping); } cosX = Math.Cos(a); sinX = Math.Sin(a); } else { cosX = 0.0; sinX = 0.0; } double cosY, sinY; if (rotateY) { double a; if (UpdateFunctions) { a = RotateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { a = RotateYFunction.LastResult; } if (RotateYDamping != null) { RotateYDamping.Update(TimeElapsed, ref a, EnableDamping); } cosY = Math.Cos(a); sinY = Math.Sin(a); } else { cosY = 0.0; sinY = 0.0; } double cosZ, sinZ; if (rotateZ) { double a; if (UpdateFunctions) { a = RotateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { a = RotateZFunction.LastResult; } if (RotateZDamping != null) { RotateZDamping.Update(TimeElapsed, ref a, EnableDamping); } cosZ = Math.Cos(a); sinZ = Math.Sin(a); } else { cosZ = 0.0; sinZ = 0.0; } // texture shift bool shiftx = TextureShiftXFunction != null; bool shifty = TextureShiftYFunction != null; if ((shiftx | shifty) & UpdateFunctions) { for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates = States[s].Object.Mesh.Vertices[k].TextureCoordinates; } if (shiftx) { double x = TextureShiftXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); x -= Math.Floor(x); for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(x * TextureShiftXDirection.X); ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(x * TextureShiftXDirection.Y); } } if (shifty) { double y = TextureShiftYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); y -= Math.Floor(y); for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(y * TextureShiftYDirection.X); ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(y * TextureShiftYDirection.Y); } } } // led bool led = LEDFunction != null; double ledangle; if (led) { if (UpdateFunctions) { ledangle = LEDFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } else { ledangle = LEDFunction.LastResult; } } else { ledangle = 0.0; } // null object if (States[s].Object == null) { return; } // initialize vertices for (int k = 0; k < States[s].Object.Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates = States[s].Object.Mesh.Vertices[k].Coordinates; } // led if (led) { /* * Edges: Vertices: * 0 - bottom 0 - bottom-left * 1 - left 1 - top-left * 2 - top 2 - top-right * 3 - right 3 - bottom-right * 4 - center * */ int v = 1; if (LEDClockwiseWinding) { /* winding is clockwise*/ if (ledangle < LEDInitialAngle) { ledangle = LEDInitialAngle; } if (ledangle < LEDLastAngle) { double currentEdgeFloat = Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (lastEdge < currentEdge | lastEdge == currentEdge & Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { lastEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz); v++; } { double t = 0.5 + (0.636619772367582 * LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[s].Object.Mesh.Vertices[v + 0].Coordinates = new Vector3(cx, cy, cz); States[s].Object.Mesh.Vertices[v + 1].Coordinates = LEDVectors[currentEdge]; v += 2; } for (int j = currentEdge + 1; j < lastEdge; j++) { /* square-vertex to square-vertex */ States[s].Object.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4]; States[s].Object.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + (0.636619772367582 * LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge % 4].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge % 4].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge % 4].Z; States[s].Object.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(lastEdge + 3) % 4]; States[s].Object.Mesh.Vertices[v + 1].Coordinates = new Vector3(lx, ly, lz); v += 2; } } } } else { /* winding is counter-clockwise*/ if (ledangle > LEDInitialAngle) { ledangle = LEDInitialAngle; } if (ledangle > LEDLastAngle) { double currentEdgeFloat = Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (currentEdge < lastEdge | lastEdge == currentEdge & Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { currentEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + (0.636619772367582 * LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz); v++; } { double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = t - Math.Floor(t); t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge % 4].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge % 4].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge % 4].Z; States[s].Object.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(currentEdge + 3) % 4]; States[s].Object.Mesh.Vertices[v + 1].Coordinates = new Vector3(cx, cy, cz); v += 2; } for (int j = currentEdge - 1; j > lastEdge; j--) { /* square-vertex to square-vertex */ States[s].Object.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4]; States[s].Object.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + (0.636619772367582 * LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[s].Object.Mesh.Vertices[v + 0].Coordinates = new Vector3(lx, ly, lz); States[s].Object.Mesh.Vertices[v + 1].Coordinates = LEDVectors[lastEdge % 4]; v += 2; } } } } for (int j = v; v < 11; v++) { States[s].Object.Mesh.Vertices[j].Coordinates = LEDVectors[4]; } } // update vertices for (int k = 0; k < States[s].Object.Mesh.Vertices.Length; k++) { // rotate if (rotateX) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Rotate(RotateXDirection, cosX, sinX); } if (rotateY) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Rotate(RotateYDirection, cosY, sinY); } if (rotateZ) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Rotate(RotateZDirection, cosZ, sinZ); } // translate if (Overlay & Camera.CurrentRestriction != CameraRestrictionMode.NotAvailable) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates += States[s].Position - Position; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Rotate(Camera.AbsoluteDirection, Camera.AbsoluteUp, Camera.AbsoluteSide); double dx = -Math.Tan(Camera.CurrentAlignment.Yaw) - Camera.CurrentAlignment.Position.X; double dy = -Math.Tan(Camera.CurrentAlignment.Pitch) - Camera.CurrentAlignment.Position.Y; double dz = -Camera.CurrentAlignment.Position.Z; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Camera.AbsolutePosition.X + dx * Camera.AbsoluteSide.X + dy * Camera.AbsoluteUp.X + dz * Camera.AbsoluteDirection.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Camera.AbsolutePosition.Y + dx * Camera.AbsoluteSide.Y + dy * Camera.AbsoluteUp.Y + dz * Camera.AbsoluteDirection.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Camera.AbsolutePosition.Z + dx * Camera.AbsoluteSide.Z + dy * Camera.AbsoluteUp.Z + dz * Camera.AbsoluteDirection.Z; } else { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates += States[s].Position; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Rotate(Direction, Up, Side); ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates += Position; } } // update normals for (int k = 0; k < States[s].Object.Mesh.Faces.Length; k++) { for (int h = 0; h < States[s].Object.Mesh.Faces[k].Vertices.Length; h++) { ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal = States[s].Object.Mesh.Faces[k].Vertices[h].Normal; if (!Vector3.IsZero(States[s].Object.Mesh.Faces[k].Vertices[h].Normal)) { if (rotateX) { ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Rotate(RotateXDirection, cosX, sinX); } if (rotateY) { ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Rotate(RotateYDirection, cosY, sinY); } if (rotateZ) { ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Rotate(RotateZDirection, cosZ, sinZ); } ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Rotate(Direction, Up, Side); } } // visibility changed // TouchElement is handled by another function. if (!IsTouch) { if (Show) { if (Overlay) { Renderer.ShowObject(i, ObjectType.Overlay); } else { Renderer.ShowObject(i, ObjectType.Dynamic); } } else { Renderer.HideObject(i); } } } }
/// <summary>Processes a jump</summary> /// <param name="Train">The train to be jumped</param> /// <param name="StationIndex">The station to jump to</param> public virtual void ProcessJump(AbstractTrain Train, int StationIndex) { }
public Coupler(double minimumDistance, double maximumDistance, CarBase frontCar, CarBase rearCar, AbstractTrain train) { MinimumDistanceBetweenCars = minimumDistance; MaximumDistanceBetweenCars = maximumDistance; baseCar = frontCar; if (rearCar != null) { connectedCar = rearCar; } else { connectedCar = frontCar; } CarSections = new CarSection[] { }; baseTrain = train; }
/// <summary>Gets the closest train to the specified train</summary> /// <param name="Train">The specified train</param> /// <returns>The closest train, or null if no other trains</returns> public virtual AbstractTrain ClosestTrain(AbstractTrain Train) { return(null); }
/// <summary>Gets the signal data for a plugin.</summary> /// <param name="train">The train.</param> /// <returns>The signal data.</returns> public SignalData GetPluginSignal(AbstractTrain train) { if (Exists(train)) { int aspect; if (IsFree(train)) { if (Type == SectionType.IndexBased) { if (NextSection != null) { int value = NextSection.FreeSections; if (value == -1) { value = Aspects.Length - 1; } else { value++; if (value >= Aspects.Length) { value = Aspects.Length - 1; } if (value < 0) { value = 0; } } aspect = Aspects[value].Number; } else { aspect = Aspects[Aspects.Length - 1].Number; } } else { aspect = Aspects[Aspects.Length - 1].Number; if (NextSection != null) { int value = NextSection.Aspects[NextSection.CurrentAspect].Number; for (int i = 0; i < Aspects.Length; i++) { if (Aspects[i].Number > value) { aspect = Aspects[i].Number; break; } } } } } else { aspect = Aspects[CurrentAspect].Number; } double position = train.FrontCarTrackPosition(); double distance = TrackPosition - position; return(new SignalData(aspect, distance)); } else { int aspect = Aspects[CurrentAspect].Number; double position = train.FrontCarTrackPosition(); double distance = TrackPosition - position; return(new SignalData(aspect, distance)); } }
/// <inheritdoc/> public override void Update(AbstractTrain NearestTrain, double TimeElapsed, bool ForceUpdate, bool CurrentlyVisible) { if (CurrentlyVisible | ForceUpdate) { if (Object.SecondsSinceLastUpdate >= Object.RefreshRate | ForceUpdate) { double timeDelta = Object.SecondsSinceLastUpdate + TimeElapsed; Object.SecondsSinceLastUpdate = 0.0; Object.Update(false, NearestTrain, NearestTrain == null ? 0 : NearestTrain.DriverCar, SectionIndex, TrackPosition, Position, Direction, Up, Side, true, true, timeDelta, true); if (this.Object.CurrentState != this.lastState && currentHost.SimulationSetup) { if (this.SingleBuffer && this.Buffers[0] != null) { switch (this.Object.CurrentState) { case -1: if (this.PlayOnHide) { Source = currentHost.PlaySound(Buffers[0], currentPitch, currentVolume, Position, null, false); } break; case 0: if (this.PlayOnShow || this.lastState != -1) { Source = currentHost.PlaySound(Buffers[0], currentPitch, currentVolume, Position, null, false); } break; default: Source = currentHost.PlaySound(Buffers[0], currentPitch, currentVolume, Position, null, false); break; } } else { int bufferIndex = this.Object.CurrentState + 1; if (bufferIndex < this.Buffers.Length && this.Buffers[bufferIndex] != null) { switch (bufferIndex) { case 0: if (this.PlayOnHide) { Source = currentHost.PlaySound(Buffers[bufferIndex], currentPitch, currentVolume, Position, null, false); } break; case 1: if (this.PlayOnShow || this.lastState != -1) { Source = currentHost.PlaySound(Buffers[bufferIndex], currentPitch, currentVolume, Position, null, false); } break; default: Source = currentHost.PlaySound(Buffers[bufferIndex], currentPitch, currentVolume, Position, null, false); break; } } } } } else { Object.SecondsSinceLastUpdate += TimeElapsed; } if (!base.Visible) { currentHost.ShowObject(Object.internalObject, ObjectType.Dynamic); base.Visible = true; } } else { Object.SecondsSinceLastUpdate += TimeElapsed; if (base.Visible) { currentHost.HideObject(Object.internalObject); base.Visible = false; } } this.lastState = this.Object.CurrentState; }
public override void ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) { FunctionScripts.ExecuteFunctionScript(functionScript, (TrainManager.Train)train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); }
/// <summary>Creates a new sound source.</summary> /// <param name="buffer">The sound buffer.</param> /// <param name="radius">The effective sound radius.</param> /// <param name="pitch">The pitch change factor.</param> /// <param name="volume">The volume change factor.</param> /// <param name="position">The position. If a train and car are specified, the position is relative to the car, otherwise absolute.</param> /// <param name="train">The train this sound source is attached to, or a null reference.</param> /// <param name="type">The type of sound</param> /// <param name="looped">Whether this sound source plays in a loop.</param> internal SoundSource(SoundBuffer buffer, double radius, double pitch, double volume, Vector3 position, AbstractTrain train, SoundType type, bool looped) { Buffer = buffer; Radius = radius; Pitch = pitch; Volume = volume; Position = position; Parent = train; Looped = looped; State = SoundSourceState.PlayPending; OpenAlSourceName = 0; //Set sound type manually Type = type; }