예제 #1
0
        public void Update(WorldLocation playerLocation, int approachDist, int scaredDist)
        {
            if (state == State.Idle1)
            {
                if (Simulator.Random.Next(10) == 0)
                {
                    state = State.Idle2;
                }
            }
            else if (state == State.Idle2)
            {
                if (Simulator.Random.Next(5) == 0)
                {
                    state = State.Idle1;
                }
            }

            if (!WorldLocation.Within(Location, playerLocation, scaredDist) && state < State.LookLeft)
            {
                if (WorldLocation.Within(Location, playerLocation, approachDist) && state < State.LookLeft)
                {
                    state = State.LookRight;
                }
            }
            if (WorldLocation.Within(Location, playerLocation, scaredDist) && state == State.LookRight || state == State.LookLeft)
            {
                state = State.Scared;
            }
        }
예제 #2
0
        public void WorldLocationDistanceZeroTest()
        {
            WorldLocation location1 = new WorldLocation();
            WorldLocation location2 = new WorldLocation();

            Assert.IsTrue(WorldLocation.Within(location1, location2, 0));
            Assert.AreEqual(0, WorldLocation.GetDistanceSquared(location1, location2));
            Assert.AreEqual(Microsoft.Xna.Framework.Vector3.Zero, WorldLocation.GetDistance(location1, location2));
            Assert.AreEqual(Microsoft.Xna.Framework.Vector2.Zero, WorldLocation.GetDistance2D(location1, location2));
        }
예제 #3
0
        public void WorldLocationDistanceTest()
        {
            WorldLocation location1 = new WorldLocation();
            WorldLocation location2 = new WorldLocation(1, -1, Microsoft.Xna.Framework.Vector3.Zero);

            Assert.AreEqual(2048 * 2048 + 2048 * 2048, WorldLocation.GetDistanceSquared(location1, location2));
            Assert.IsTrue(WorldLocation.Within(location1, location2, (float)Math.Sqrt(2048 * 2048 * 2) + 1));

            Assert.AreEqual(new Microsoft.Xna.Framework.Vector3(2048, 0, -2048), WorldLocation.GetDistance(location1, location2));
            Assert.AreEqual(new Microsoft.Xna.Framework.Vector2(2048, -2048), WorldLocation.GetDistance2D(location1, location2));
        }
예제 #4
0
        public void Horn()
        {
            var playerLocation = Simulator.PlayerLocomotive.WorldPosition.WorldLocation;

            foreach (var haz in Hazards)
            {
                if (WorldLocation.Within(haz.Value.Location, playerLocation, hornDist))
                {
                    haz.Value.state = Hazard.State.LookLeft;
                }
            }
        }
예제 #5
0
        public void Horn()
        {
            WorldLocation playerLocation = Simulator.Instance.PlayerLocomotive.WorldPosition.WorldLocation;

            foreach (KeyValuePair <int, Hazard> item in hazards)
            {
                if (WorldLocation.Within(item.Value.Location, playerLocation, hornDist))
                {
                    item.Value.State = Hazard.HazardState.LookLeft;
                }
            }
        }
예제 #6
0
        /// <summary>
        /// CheckTrainOnTurntable: checks if actual player train is on turntable
        /// </summary>
        public bool CheckTrainOnMovingTable(Train train)
        {
            if (train == null)
            {
                return(false);
            }
            string tableType = this is TurnTable?Simulator.Catalog.GetString("turntable") : Simulator.Catalog.GetString("transfertable");

            int trainIndex = (TrainsOnMovingTable as List <TrainOnMovingTable>)?.FindIndex(x => x.Train.Number == train.Number) ?? -1;

            if (WorldLocation.Within(train.FrontTDBTraveller.WorldLocation, WorldPosition.WorldLocation, Length / 2))
            {
                if (trainIndex == -1 || !TrainsOnMovingTable[trainIndex].FrontOnBoard)
                {
                    if (trainIndex == -1)
                    {
                        TrainOnMovingTable trainOnTurntable = new TrainOnMovingTable(train);
                        trainIndex = TrainsOnMovingTable.Count;
                        TrainsOnMovingTable.Add(trainOnTurntable);
                    }
                    if (!TrainsOnMovingTable[trainIndex].BackOnBoard)
                    {
                        // check if turntable aligned with train
                        bool aligned = CheckMovingTableAligned(train, true);
                        if (!aligned)
                        {
                            TrainsOnMovingTable[trainIndex].SetFrontState(true);
                            Simulator.Instance.Confirmer.Warning(Simulator.Catalog.GetString("Train slipped into non aligned {0}", tableType));
                            train.SetTrainOutOfControl(OutOfControlReason.SlippedIntoTurnTable);
                            train.SpeedMpS = 0;
                            foreach (TrainCar car in train.Cars)
                            {
                                car.SpeedMpS = 0;
                            }
                            return(false);
                        }
                    }
                    if (SendNotifications)
                    {
                        Simulator.Instance.Confirmer.Information(Simulator.Catalog.GetString("Train front on {0}", tableType));
                    }
                }
                TrainsOnMovingTable[trainIndex].SetFrontState(true);
            }
            else
            if (trainIndex != -1 && TrainsOnMovingTable[trainIndex].FrontOnBoard)
            {
                if (SendNotifications)
                {
                    Simulator.Instance.Confirmer.Information(Simulator.Catalog.GetString("Train front outside {0}", tableType));
                }
                if (TrainsOnMovingTable[trainIndex].BackOnBoard)
                {
                    TrainsOnMovingTable[trainIndex].SetFrontState(false);
                }
                else
                {
                    TrainsOnMovingTable.RemoveAt(trainIndex);
                    trainIndex = -1;
                }
            }
            if (WorldLocation.Within(train.RearTDBTraveller.WorldLocation, WorldPosition.WorldLocation, Length / 2))
            {
                if (trainIndex == -1 || !TrainsOnMovingTable[trainIndex].BackOnBoard)
                {
                    if (trainIndex == -1)
                    {
                        TrainOnMovingTable trainOnTurntable = new TrainOnMovingTable(train);
                        trainIndex = TrainsOnMovingTable.Count;
                        TrainsOnMovingTable.Add(trainOnTurntable);
                    }
                    if (!TrainsOnMovingTable[trainIndex].FrontOnBoard)
                    {
                        // check if turntable aligned with train
                        bool aligned = CheckMovingTableAligned(train, false);
                        if (!aligned)
                        {
                            TrainsOnMovingTable[trainIndex].SetBackState(true);
                            Simulator.Instance.Confirmer.Warning(Simulator.Catalog.GetString("Train slipped into non aligned {0}", tableType));
                            train.SetTrainOutOfControl(OutOfControlReason.SlippedIntoTurnTable);
                            train.SpeedMpS = 0;
                            foreach (TrainCar car in train.Cars)
                            {
                                car.SpeedMpS = 0;
                            }
                            return(false);
                        }
                    }
                    Simulator.Instance.Confirmer.Information(Simulator.Catalog.GetString("Train rear on {0}", tableType));
                }
                TrainsOnMovingTable[trainIndex].SetBackState(true);
            }
            else
            if (trainIndex != -1 && TrainsOnMovingTable[trainIndex].BackOnBoard)
            {
                if (SendNotifications)
                {
                    Simulator.Instance.Confirmer.Information(Simulator.Catalog.GetString("Train rear outside {0}", tableType));
                }
                if (TrainsOnMovingTable[trainIndex].FrontOnBoard)
                {
                    TrainsOnMovingTable[trainIndex].SetBackState(false);
                }
                else
                {
                    TrainsOnMovingTable.RemoveAt(trainIndex);
                    trainIndex = -1;
                }
            }
            if (Simulator.Instance.ActivityRun != null && !train.IsPathless && train.TrainType != TrainType.Static && trainIndex != -1 &&
                TrainsOnMovingTable[trainIndex].FrontOnBoard && TrainsOnMovingTable[trainIndex].BackOnBoard && train.SpeedMpS <= 0.1f && train.ControlMode != TrainControlMode.Manual &&
                train.TCRoute.ActiveSubPath == train.TCRoute.TCRouteSubpaths.Count - 1 && train.TCRoute.TCRouteSubpaths[train.TCRoute.ActiveSubPath].Count > 1 &&
                (train.PresentPosition[Direction.Forward].RouteListIndex == train.TCRoute.TCRouteSubpaths[train.TCRoute.ActiveSubPath].Count - 2 ||
                 train.PresentPosition[Direction.Backward].RouteListIndex == train.TCRoute.TCRouteSubpaths[train.TCRoute.ActiveSubPath].Count - 2))
            {
                train.IsPathless = true;
            }
            return(false);
        }
예제 #7
0
        void UpdateCrossings(Train train, float elapsedTime)
        {
            var speedMpS    = train.SpeedMpS;
            var absSpeedMpS = Math.Abs(speedMpS);
            var maxSpeedMpS = train.AllowedMaxSpeedMpS;
            var minCrossingActivationSpeed = 5.0f;  //5.0MpS is equalivalent to 11.1mph.  This is the estimated min speed that MSTS uses to activate the gates when in range.


            bool validTrain         = false;
            bool validStaticConsist = false;

            //var stopTime = elapsedTime; // This has been set up, but it is not being used in the code.
            //stopTime = 0;


            // We only care about crossing items which are:
            //   a) Grouped properly.
            //   b) Within the maximum activation distance of front/rear of the train.
            // Separate tests are performed for present speed and for possible maximum speed to avoid anomolies if train accelerates.
            // Special test is also done to check on section availability to avoid closure beyond signal at danger.

            foreach (var crossing in TrackCrossingItems.Values.Where(ci => ci.CrossingGroup != null))
            {
                var predictedDist    = crossing.CrossingGroup.WarningTime * absSpeedMpS;
                var maxPredictedDist = crossing.CrossingGroup.WarningTime * (maxSpeedMpS - absSpeedMpS) / 2; // added distance if train accelerates to maxspeed
                var minimumDist      = crossing.CrossingGroup.MinimumDistance;
                var totalDist        = predictedDist + minimumDist + 1;
                var totalMaxDist     = predictedDist + maxPredictedDist + minimumDist + 1;

                var reqDist     = 0f; // actual used distance
                var hornReqDist = 0f; // used distance for horn blow
                var adjustDist  = 0f;


                //  The first 2 tests are critical for STATIC CONSISTS, but at the same time should be mandatory since there should always be checks for any null situation.
                //  The first 2 tests cover a situation where a STATIC consist is found on a crossing attached to a road where other crossings are attached to the same road.
                //  These tests will only allow the activation of the crossing that should be activated but prevent the actvation of the other crossings which was the issue.
                //  The source of the issue is not known yet since this only happens with STATIC consists.

                // The purpose of this test is to validate the static consist that is within vicinity of the crossing.
                if (train.TrainType == Train.TRAINTYPE.STATIC)
                {
                    // An issue was found where a road sharing more than one crossing would have all crossings activated instead of the one crossing when working with STATIC consists.
                    // The test below corrects this, but the source of the issue is not understood.
                    if (!WorldLocation.Within(crossing.Location, train.FrontTDBTraveller.WorldLocation, (minimumDist + (train.Length / 2))) && !WorldLocation.Within(crossing.Location, train.RearTDBTraveller.WorldLocation, (minimumDist + (train.Length / 2))))
                    {
                        continue;
                    }
                    if (WorldLocation.Within(crossing.Location, train.FrontTDBTraveller.WorldLocation, (minimumDist + (train.Length / 2))) || WorldLocation.Within(crossing.Location, train.RearTDBTraveller.WorldLocation, (minimumDist + (train.Length / 2))))
                    {
                        foreach (var scar in train.Cars)
                        {
                            if (WorldLocation.Within(crossing.Location, scar.WorldPosition.WorldLocation, minimumDist))
                            {
                                validStaticConsist = true;
                            }
                        }
                    }
                }

                if ((train.TrainType != Train.TRAINTYPE.STATIC) && WorldLocation.Within(crossing.Location, train.FrontTDBTraveller.WorldLocation, totalDist) || WorldLocation.Within(crossing.Location, train.RearTDBTraveller.WorldLocation, totalDist))
                {
                    validTrain  = true;
                    reqDist     = totalDist;
                    hornReqDist = Math.Min(totalDist, 80.0f);
                }

                else if ((train.TrainType != Train.TRAINTYPE.STATIC) && WorldLocation.Within(crossing.Location, train.FrontTDBTraveller.WorldLocation, totalMaxDist) || WorldLocation.Within(crossing.Location, train.RearTDBTraveller.WorldLocation, totalMaxDist))
                {
                    validTrain  = true;
                    reqDist     = totalMaxDist;
                    hornReqDist = Math.Min(totalMaxDist, 80.0f);
                }

                if ((train.TrainType == Train.TRAINTYPE.STATIC) && !validStaticConsist && !crossing.StaticConsists.Contains(train))
                {
                    continue;
                }

                if ((train.TrainType != Train.TRAINTYPE.STATIC) && !validTrain && !crossing.Trains.Contains(train))
                {
                    continue;
                }

                // Distances forward from the front and rearwards from the rear.
                var frontDist = crossing.DistanceTo(train.FrontTDBTraveller, reqDist);
                if (frontDist < 0 && train.TrainType != Train.TRAINTYPE.STATIC)
                {
                    frontDist = -crossing.DistanceTo(new Traveller(train.FrontTDBTraveller, Traveller.TravellerDirection.Backward), reqDist + train.Length);
                    if (frontDist > 0)
                    {
                        // Train cannot find crossing.
                        crossing.RemoveTrain(train);
                        continue;
                    }
                }

                var rearDist = -frontDist - train.Length;

                if (train is AITrain && frontDist <= hornReqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    //  Add generic actions if needed
                    ((AITrain)train).AuxActionsContain.CheckGenActions(this.GetType(), crossing.Location, rearDist, frontDist, crossing.TrackIndex);
                }

                // The tests below is to allow the crossings operate like the crossings under MSTS
                // Tests as follows
                // Train speed is 0.  This was the initial issue that was found under one the MSTS activities.  Activity should start without gates being activated.
                // There are 2 tests for train speed between 0 and 5.0MpS(11.1mph).  Covering forward movement and reverse movement.
                // The last 2 tests is for testing trains running at line speed, forward or reverse.

                // The crossing only becomes active if the train has been added to the list such as crossing.AddTrain(train).
                // Note: With the conditions below, OR's crossings operates like the crossings in MSTS, with exception to the simulation of the timout below.

                // MSTS did not simulate a timeout, I introduced a simple timout using speedMpS.

                // Depending upon future development in this area, it would probably be best to have the current operation in its own class followed by any new region specific operations.

                // Recognizing static consists at crossings.
                if ((train.TrainType == Train.TRAINTYPE.STATIC) && validStaticConsist)
                {
                    // This process is to raise the crossing gates if a loose consist rolls through the crossing.
                    if (speedMpS > 0)
                    {
                        frontDist = crossing.DistanceTo(train.FrontTDBTraveller, minimumDist);
                        rearDist  = crossing.DistanceTo(train.RearTDBTraveller, minimumDist);

                        if (frontDist < 0 && rearDist < 0)
                        {
                            crossing.RemoveTrain(train);
                        }
                    }
                    //adjustDist is used to allow static cars to be placed closer to the crossing without activation.
                    // One example would be industry sidings with a crossing nearby.  This was found in a custom route.
                    if (minimumDist >= 20)
                    {
                        adjustDist = minimumDist - 13.5f;
                    }
                    else if (minimumDist < 20)
                    {
                        adjustDist = minimumDist - 6.5f;
                    }
                    frontDist = crossing.DistanceTo(train.FrontTDBTraveller, adjustDist);
                    rearDist  = crossing.DistanceTo(train.RearTDBTraveller, adjustDist);
                    // Static consist passed the crossing.
                    if (frontDist < 0 && rearDist < 0)
                    {
                        rearDist = crossing.DistanceTo(new Traveller(train.RearTDBTraveller, Traveller.TravellerDirection.Backward), adjustDist);
                    }

                    // Testing distance before crossing
                    if (frontDist > 0 && frontDist <= adjustDist)
                    {
                        crossing.AddTrain(train);
                    }

                    // Testing to check if consist is straddling the crossing.
                    else if (frontDist < 0 && rearDist > 0)
                    {
                        crossing.AddTrain(train);
                    }

                    // This is an odd test because a custom route has a particular
                    // crossing object placement that is creating different results.
                    // Testing to check if consist is straddling the crossing.
                    else if (frontDist < 0 && rearDist < 0)
                    {
                        crossing.AddTrain(train);
                    }

                    // Testing distance when past crossing.
                    else if (rearDist <= adjustDist && rearDist > 0)
                    {
                        crossing.AddTrain(train);
                    }

                    else
                    {
                        crossing.RemoveTrain(train);
                    }
                }

                // Train is stopped.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER || train.TrainType == Train.TRAINTYPE.REMOTE) && Math.Abs(speedMpS) <= Simulator.MaxStoppedMpS && frontDist <= reqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    // First test is to simulate a timeout if a train comes to a stop before minimumDist
                    if (frontDist > minimumDist && Simulator.Trains.Contains(train))
                    {
                        crossing.RemoveTrain(train);
                    }
                    // This test is to factor in the train sitting on the crossing at the start of the activity.
                    else
                    {
                        crossing.AddTrain(train);
                    }
                }

                // Train is travelling toward crossing below 11.1mph.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER || train.TrainType == Train.TRAINTYPE.STATIC || train.TrainType == Train.TRAINTYPE.REMOTE) && speedMpS > 0 && speedMpS <= minCrossingActivationSpeed && frontDist <= reqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    // This will allow a slow train to approach to the crossing's minmum distance without activating the crossing.
                    if (frontDist <= minimumDist + 65f) // Not all crossing systems operate the same so adding an additional 65 meters is only an option to improve operation.
                    {
                        crossing.AddTrain(train);
                    }
                }

                // Checking for reverse movement when train is approaching crossing while travelling under 11.1mph.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER) && speedMpS < 0 && absSpeedMpS <= minCrossingActivationSpeed && rearDist <= reqDist && (train.ReservedTrackLengthM <= 0 || rearDist < train.ReservedTrackLengthM) && frontDist <= minimumDist)
                {
                    // This will allow a slow train to approach a crossing to a certain point without activating the system.
                    // First test covers front of train clearing crossing.
                    // Second test covers rear of train approaching crossing.
                    if (frontDist > 9.5) // The value of 9.5 which is within minimumDist is used to test against frontDist to give the best possible distance the gates should deactivate.
                    {
                        crossing.RemoveTrain(train);
                    }
                    else if (rearDist <= minimumDist + 65f) // Not all crossing systems operate the same so adding an additional 65 meters is only an option to improve operation.
                    {
                        crossing.AddTrain(train);
                    }
                }

                // Checking for reverse movement through crossing when train is travelling above 11.1mph.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER || train.TrainType == Train.TRAINTYPE.REMOTE) && speedMpS < 0 && absSpeedMpS > minCrossingActivationSpeed && rearDist <= reqDist && (train.ReservedTrackLengthM <= 0 || rearDist < train.ReservedTrackLengthM) && frontDist <= minimumDist)
                {
                    crossing.AddTrain(train);
                }

                // Player train travelling in forward direction above 11.1mph will activate the crossing.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER || train.TrainType == Train.TRAINTYPE.REMOTE) && speedMpS > 0 && speedMpS > minCrossingActivationSpeed && frontDist <= reqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    crossing.AddTrain(train);
                }

                else
                {
                    crossing.RemoveTrain(train);
                }
            }
        }
예제 #8
0
        /// <summary>
        /// CheckTrainOnTurntable: checks if actual player train is on turntable
        /// </summary>
        ///
        public bool CheckTrainOnMovingTable(Train train)
        {
            var thisTableType = this is Turntable?Simulator.Catalog.GetString("turntable") : Simulator.Catalog.GetString("transfertable");

            var trainIndex = TrainsOnMovingTable.FindIndex(x => x.Train.Number == train.Number);

            if (WorldLocation.Within(train.FrontTDBTraveller.WorldLocation, WorldPosition.WorldLocation, Length / 2))
            {
                if (trainIndex == -1 || !TrainsOnMovingTable[trainIndex].FrontOnBoard)
                {
                    if (trainIndex == -1)
                    {
                        var trainOnTurntable = new TrainOnMovingTable(train, Simulator);
                        trainIndex = TrainsOnMovingTable.Count;
                        TrainsOnMovingTable.Add(trainOnTurntable);
                    }
                    if (!TrainsOnMovingTable[trainIndex].BackOnBoard)
                    {
                        // check if turntable aligned with train
                        var isAligned = CheckMovingTableAligned(train, true);
                        if (!isAligned)
                        {
                            TrainsOnMovingTable[trainIndex].SetFrontState(true);
                            Simulator.Confirmer.Warning(Simulator.Catalog.GetStringFmt("Train slipped into non aligned {0}", thisTableType));
                            train.SetTrainOutOfControl(Train.OUTOFCONTROL.SLIPPED_INTO_TURNTABLE);
                            train.SpeedMpS = 0;
                            foreach (var car in train.Cars)
                            {
                                car.SpeedMpS = 0;
                            }
                            return(false);
                        }
                    }
                    if (SendNotifications)
                    {
                        Simulator.Confirmer.Information(Simulator.Catalog.GetStringFmt("Train front on {0}", thisTableType));
                    }
                }
                TrainsOnMovingTable[trainIndex].SetFrontState(true);
            }
            else
            {
                if (trainIndex != -1 && TrainsOnMovingTable[trainIndex].FrontOnBoard)
                {
                    if (SendNotifications)
                    {
                        Simulator.Confirmer.Information(Simulator.Catalog.GetStringFmt("Train front outside {0}", thisTableType));
                    }
                    if (TrainsOnMovingTable[trainIndex].BackOnBoard)
                    {
                        TrainsOnMovingTable[trainIndex].SetFrontState(false);
                    }
                    else
                    {
                        TrainsOnMovingTable.RemoveAt(trainIndex);
                        trainIndex = -1;
                    }
                }
            }
            if (WorldLocation.Within(train.RearTDBTraveller.WorldLocation, WorldPosition.WorldLocation, Length / 2))
            {
                if (trainIndex == -1 || !TrainsOnMovingTable[trainIndex].BackOnBoard)
                {
                    if (trainIndex == -1)
                    {
                        var trainOnTurntable = new TrainOnMovingTable(train, Simulator);
                        trainIndex = TrainsOnMovingTable.Count;
                        TrainsOnMovingTable.Add(trainOnTurntable);
                    }
                    if (!TrainsOnMovingTable[trainIndex].FrontOnBoard)
                    {
                        // check if turntable aligned with train
                        var isAligned = CheckMovingTableAligned(train, false);
                        if (!isAligned)
                        {
                            TrainsOnMovingTable[trainIndex].SetBackState(true);
                            Simulator.Confirmer.Warning(Simulator.Catalog.GetStringFmt("Train slipped into non aligned {0}", thisTableType));
                            train.SetTrainOutOfControl(Train.OUTOFCONTROL.SLIPPED_INTO_TURNTABLE);
                            train.SpeedMpS = 0;
                            foreach (var car in train.Cars)
                            {
                                car.SpeedMpS = 0;
                            }
                            return(false);
                        }
                    }
                    Simulator.Confirmer.Information(Simulator.Catalog.GetStringFmt("Train rear on {0}", thisTableType));
                }
                TrainsOnMovingTable[trainIndex].SetBackState(true);
            }
            else
            {
                if (trainIndex != -1 && TrainsOnMovingTable[trainIndex].BackOnBoard)
                {
                    if (SendNotifications)
                    {
                        Simulator.Confirmer.Information(Simulator.Catalog.GetStringFmt("Train rear outside {0}", thisTableType));
                    }
                    if (TrainsOnMovingTable[trainIndex].FrontOnBoard)
                    {
                        TrainsOnMovingTable[trainIndex].SetBackState(false);
                    }
                    else
                    {
                        TrainsOnMovingTable.RemoveAt(trainIndex);
                        trainIndex = -1;
                    }
                }
            }
            if (Simulator.ActivityRun != null && !train.IsPathless && train.TrainType != Train.TRAINTYPE.STATIC && trainIndex != -1 &&
                TrainsOnMovingTable[trainIndex].FrontOnBoard && TrainsOnMovingTable[trainIndex].BackOnBoard && train.SpeedMpS <= 0.1f && train.ControlMode != Train.TRAIN_CONTROL.MANUAL &&
                train.TCRoute.activeSubpath == train.TCRoute.TCRouteSubpaths.Count - 1 && train.TCRoute.TCRouteSubpaths[train.TCRoute.activeSubpath].Count > 1 &&
                (train.PresentPosition[0].RouteListIndex == train.TCRoute.TCRouteSubpaths[train.TCRoute.activeSubpath].Count - 2 ||
                 train.PresentPosition[1].RouteListIndex == train.TCRoute.TCRouteSubpaths[train.TCRoute.activeSubpath].Count - 2))
            // Activity mode, train with path is at end of it and is being rotated on the turntable
            {
                train.IsPathless = true;
            }
            return(false);
        }
예제 #9
0
        void UpdateCrossings(Train train, float elapsedTime)
        {
            var speedMpS    = train.SpeedMpS;
            var absSpeedMpS = Math.Abs(speedMpS);
            var maxSpeedMpS = train.AllowedMaxSpeedMpS;
            var minCrossingActivationSpeed = 5.0f;  //5.0MpS is equalivalent to 11.1mph.  This is the estimated min speed that MSTS uses to activate the gates when in range.


            bool validTrain = false;

            //var stopTime = elapsedTime; // This has been set up, but it is not being used in the code.
            //stopTime = 0;


            // We only care about crossing items which are:
            //   a) Grouped properly.
            //   b) Within the maximum activation distance of front/rear of the train.
            // Separate tests are performed for present speed and for possible maximum speed to avoid anomolies if train accelerates.
            // Special test is also done to check on section availability to avoid closure beyond signal at danger.

            foreach (var crossing in TrackCrossingItems.Values.Where(ci => ci.CrossingGroup != null))
            {
                var predictedDist    = crossing.CrossingGroup.WarningTime * absSpeedMpS;
                var maxPredictedDist = crossing.CrossingGroup.WarningTime * (maxSpeedMpS - absSpeedMpS) / 2; // added distance if train accelerates to maxspeed
                var minimumDist      = crossing.CrossingGroup.MinimumDistance;
                var totalDist        = predictedDist + minimumDist + 1;
                var totalMaxDist     = predictedDist + maxPredictedDist + minimumDist + 1;

                var reqDist     = 0f; // actual used distance
                var hornReqDist = 0f; // used distance for horn blow


                if (WorldLocation.Within(crossing.Location, train.FrontTDBTraveller.WorldLocation, totalDist) || WorldLocation.Within(crossing.Location, train.RearTDBTraveller.WorldLocation, totalDist))
                {
                    validTrain  = true;
                    reqDist     = totalDist;
                    hornReqDist = Math.Min(totalDist, 80.0f);
                }

                else if (WorldLocation.Within(crossing.Location, train.FrontTDBTraveller.WorldLocation, totalMaxDist) || WorldLocation.Within(crossing.Location, train.RearTDBTraveller.WorldLocation, totalMaxDist))
                {
                    validTrain  = true;
                    reqDist     = totalMaxDist;
                    hornReqDist = Math.Min(totalMaxDist, 80.0f);
                }

                if (!validTrain && !crossing.Trains.Contains(train))
                {
                    continue;
                }

                // Distances forward from the front and rearwards from the rear.
                var frontDist = crossing.DistanceTo(train.FrontTDBTraveller, reqDist);
                if (frontDist < 0)
                {
                    frontDist = -crossing.DistanceTo(new Traveller(train.FrontTDBTraveller, Traveller.TravellerDirection.Backward), reqDist + train.Length);
                    if (frontDist > 0)
                    {
                        // Train cannot find crossing.
                        crossing.RemoveTrain(train);
                        continue;
                    }
                }

                var rearDist = -frontDist - train.Length;

                if (train is AITrain && frontDist <= hornReqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    //  Add generic actions if needed
                    ((AITrain)train).AuxActionsContain.CheckGenActions(this.GetType(), crossing.Location, rearDist, frontDist, crossing.TrackIndex);
                }

                // The tests below is to allow the crossings operate like the crossings under MSTS
                // Tests as follows
                // Train speed is 0.  This was the initial issue that was found under one the MSTS activities.  Activity should start without gates being activated.
                // There are 2 tests for train speed between 0 and 5.0MpS(11.1mph).  Covering forward movement and reverse movement.
                // The last 2 tests is for testing trains running at line speed, forward or reverse.

                // The crossing only becomes active if the train has been added to the list such as crossing.AddTrain(train).
                // Note: With the conditions below, OR's crossings operates like the crossings in MSTS, with exception to the simulation of the timout below.

                // MSTS did not simulate a timeout, I introduced a simple timout using speedMpS.

                // Depending upon future development in this area, it would probably be best to have the current operation in its own class followed by any new region specific operations.


                // Train is stopped.
                if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER) && speedMpS == 0 && frontDist <= reqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    // First test is to simulate a timeout if a train comes to a stop before minimumDist
                    if (frontDist > minimumDist && Simulator.Trains.Contains(train))
                    {
                        crossing.RemoveTrain(train);
                    }
                }

                // Train is travelling toward crossing below 11.1mph.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER) && speedMpS > 0 && speedMpS <= minCrossingActivationSpeed && frontDist <= reqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    // This will allow a slow train to approach to the crossing's minmum distance without activating the crossing.
                    if (frontDist <= minimumDist + 60f) // Not all crossing systems operate the same so adding an additional 60 meters is only an option to improve operation.
                    {
                        crossing.AddTrain(train);
                    }
                }

                // Checking for reverse movement when train is approaching crossing while travelling under 11.1mph.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER) && speedMpS < 0 && absSpeedMpS <= minCrossingActivationSpeed && rearDist <= reqDist && (train.ReservedTrackLengthM <= 0 || rearDist < train.ReservedTrackLengthM) && frontDist <= minimumDist)
                {
                    // This will allow a slow train to approach a crossing to a certain point without activating the system.
                    // First test covers front of train clearing crossing.
                    // Second test covers rear of train approaching crossing.
                    if (frontDist > 2.5) // The value of 2.5 which is within minimumDist is used to test against frontDist to give the best possible distance the gates should deactivate.
                    {
                        crossing.RemoveTrain(train);
                    }
                    else if (rearDist <= minimumDist + 60f) // Not all crossing systems operate the same so adding an additional 60 meters is only an option to improve operation.
                    {
                        crossing.AddTrain(train);
                    }
                }

                // Checking for reverse movement through crossing when train is travelling above 11.1mph.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER) && speedMpS < 0 && absSpeedMpS > minCrossingActivationSpeed && rearDist <= reqDist && (train.ReservedTrackLengthM <= 0 || rearDist < train.ReservedTrackLengthM) && frontDist <= minimumDist)
                {
                    crossing.AddTrain(train);
                }

                // Player train travelling in forward direction above 11.1mph will activate the crossing.
                else if ((train is AITrain || train.TrainType == Train.TRAINTYPE.PLAYER) && speedMpS > 0 && speedMpS > minCrossingActivationSpeed && frontDist <= reqDist && (train.ReservedTrackLengthM <= 0 || frontDist < train.ReservedTrackLengthM) && rearDist <= minimumDist)
                {
                    crossing.AddTrain(train);
                }

                else
                {
                    crossing.RemoveTrain(train);
                }
            }
        }