Esempio n. 1
0
        private float CalcVelocity(float currentVelocity, RCT2TrackElements.RCT2TrackElement element, RCT2Qualifier qualifier, RCT2TrackElementProperty property)
        {
            //Check if it's a Chain lift or a station
            if (qualifier.IsChainLift)
            {
                return(Math.Max(currentVelocity, ChainLiftSpeed));
            }
            else if (element == RCT2TrackElements.RCT2TrackElement.BeginStation ||
                     element == RCT2TrackElements.RCT2TrackElement.MiddleStation ||
                     element == RCT2TrackElements.RCT2TrackElement.EndStation)
            {
                return(Math.Max(currentVelocity, StationSpeed));
            }

            float acceleration = 0;

            //Try to get current acceleration from the map
            try
            {
                acceleration = RCT2TrackElementProperty.TrackAccelerationMap[(int)-property.Displacement.Y];
            }
            catch
            {
                Console.WriteLine($"Unable to find acceleration value for track piece {element.ToString()}");
            }

            float newVelocity = currentVelocity + acceleration;

            if (newVelocity <= 0)
            {
                velocityGoesNegative = true;
            }

            return(newVelocity);
        }
Esempio n. 2
0
        private int CalculateFitness(RCT2RideData candidate)
        {
            int fitness = 0;

            //Get Displacement to End & Max Y Displacement
            Vector3 prevWorldPos         = new Vector3(0.0f, 0.0f, 0.0f);
            int     worldDirectionChange = 0;
            double  maxVarianceFromStart = 0;
            int     maxYVariance         = 0;

            for (int i = 0; i < candidate.TrackData.TrackData.Count; i++)
            {
                RCT2TrackElements.RCT2TrackElement currentElement = candidate.TrackData.TrackData[i].TrackElement;
                RCT2TrackElementProperty           property       = RCT2TrackElements.TrackElementPropertyMap[currentElement];

                Vector3 worldDisplacement = candidate.TrackData.LocalDisplacementToWorld(property.Displacement, worldDirectionChange);

                //Update World Position Changes
                prevWorldPos += worldDisplacement;

                if (prevWorldPos.Y >= maxYVariance)
                {
                    maxYVariance = (int)prevWorldPos.Y;
                }

                if (prevWorldPos.Length() >= maxVarianceFromStart)
                {
                    maxVarianceFromStart = prevWorldPos.Length();
                }

                //Update World Direction Changes
                worldDirectionChange = candidate.TrackData.UpdateRotation(worldDirectionChange, property.DirectionChange);
            }
            maxYVariance         -= (int)prevWorldPos.Y;
            maxVarianceFromStart -= prevWorldPos.Length();
            Vector3 displacementToEnd = new Vector3(0, 0, 0);

            displacementToEnd.X = Math.Abs(prevWorldPos.X);
            displacementToEnd.Y = Math.Abs(prevWorldPos.Y);
            displacementToEnd.Z = Math.Abs(prevWorldPos.Z);

            //Console.WriteLine(maxYDisplacement);

            double displacementToEndLength = displacementToEnd.Length();

            fitness = (int)(((candidate.ExcitementTimesTen / (1 + candidate.NauseaTimesTen)) + /*maxVarianceFromStart*/ +maxYVariance) * 1000);

            return(fitness);
        }
Esempio n. 3
0
        public Vector2 CalculateRequiredMapSpace()
        {
            Vector2 requiredMapSpace       = new Vector2(0.0f, 0.0f);
            Vector2 posDisplacementCounter = new Vector2(0.0f, 0.0f);

            int            currentDirectionOffset = 0;
            List <Vector3> usedCells             = new List <Vector3>();
            Vector3        prevWorldDisplacement = new Vector3(0.0f, 0.0f, 0.0f);

            for (int i = 0; i < TrackData.Count; i++)
            {
                RCT2TrackElements.RCT2TrackElement element  = TrackData[i].TrackElement;
                RCT2TrackElementProperty           property = RCT2TrackElements.TrackElementPropertyMap[element];

                Vector3 worldDisplacement = LocalDisplacementToWorld(property.Displacement, currentDirectionOffset);

                prevWorldDisplacement += worldDisplacement;
                usedCells.Add(prevWorldDisplacement);

                currentDirectionOffset = UpdateRotation(currentDirectionOffset, property.DirectionChange);
            }

            //Find max X and Y distance of cells in list
            List <float> xVals = new List <float>();
            List <float> yVals = new List <float>();

            usedCells.ForEach(v =>
            {
                xVals.Add(v.X);
                yVals.Add(v.Z);
            });
            xVals.Sort();
            yVals.Sort();

            requiredMapSpace.X = Math.Abs(xVals.Last() - xVals.First());
            requiredMapSpace.Y = Math.Abs(yVals.Last() - yVals.First());

            return(requiredMapSpace);
        }
Esempio n. 4
0
        public int CalculateRideLengthInMeters()
        {
            //Approximate
            int rideLength = 0;

            for (int i = 0; i < TrackData.Count; i++)
            {
                RCT2TrackElements.RCT2TrackElement element  = TrackData[i].TrackElement;
                RCT2TrackElementProperty           property = RCT2TrackElements.TrackElementPropertyMap[element];

                int curLength = 0;
                int counter   = 0;

                if (property.Displacement.X != 0)
                {
                    curLength += (int)Math.Abs(property.Displacement.X * HorizontalUnitsToMeters);
                    counter++;
                }

                if (property.Displacement.Y != 0)
                {
                    curLength += (int)Math.Abs(property.Displacement.Y * VerticalUnitsToMeters);
                    counter++;
                }

                if (property.Displacement.Z != 0)
                {
                    curLength += (int)Math.Abs(property.Displacement.Z * HorizontalUnitsToMeters);
                    counter++;
                }

                if (counter > 0)
                {
                    rideLength += (curLength / counter);
                }
            }

            return(rideLength);
        }
Esempio n. 5
0
        private RCT2TrackData GenerateWoodenRollerCoasterTrack()
        {
            RCT2TrackData trackData = new RCT2TrackData();

            trackData.TrackData = new List <RCT2TrackPiece>();
            Random random = new Random();

            //Begin Station
            trackData.TrackData.Add(new RideData.RCT2TrackPiece()
            {
                TrackElement = RideData.RCT2TrackElements.RCT2TrackElement.BeginStation,
                Qualifier    = new RideData.RCT2Qualifier()
                {
                    IsChainLift             = false,
                    TrackColourSchemeNumber = 0,
                    TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                    AtTerminalStation       = false,
                    StationNumber           = 0
                }
            });

            //End Station
            trackData.TrackData.Add(new RideData.RCT2TrackPiece()
            {
                TrackElement = RideData.RCT2TrackElements.RCT2TrackElement.EndStation,
                Qualifier    = new RideData.RCT2Qualifier()
                {
                    IsChainLift             = false,
                    TrackColourSchemeNumber = 0,
                    TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                    AtTerminalStation       = false,
                    StationNumber           = 0
                }
            });

            //TODO: Marking valid track pieces as invalid
            //      The prior connection check is failing

            for (int i = 2; i < length; i++)
            {
                List <RCT2TrackElements.RCT2TrackElement> candidates = RCT2TrackElements.FindValidSuccessors(whitelistedTracks, trackData.TrackData[i - 1].TrackElement);
                bool reselect = false;

                do
                {
                    //If we have no candidates left
                    if (candidates.Count <= 0)
                    {
                        return(null);
                        //if (steppedBack)
                        //{
                        //    return null;
                        //}

                        //if (i < 3)
                        //{
                        //    throw new Exception("ERROR: Unable to create Coaster - Index stepped back too far");
                        //}
                        ////Console.WriteLine("ERROR: No Valid Track Pieces Found, Stepping back and starting again");
                        //trackData.TrackData.Remove(trackData.TrackData.Last());
                        //i -= 2;
                        //steppedBack = true;


                        //TODO - Make this a better solution, right now it's a hack to make it work
                        //break;
                    }

                    //Select our successor and remove it from the potential pool
                    RCT2TrackElements.RCT2TrackElement successor = candidates[random.Next(candidates.Count)];
                    candidates.Remove(successor);
                    RCT2TrackElementProperty property = RCT2TrackElements.TrackElementPropertyMap[successor];

                    //Console.WriteLine($"\tAttempting Track Piece {successor.ToString()}");

                    RCT2Qualifier qualifier;

                    //Create our qualifier bit
                    if (property.Displacement.Y > 0)
                    {
                        //TODO: Check if it should be a chain
                        //      Perform a lookup to see if previous track was chain lift
                        //      Or if our current velocity would be negative/0
                        //      If not possible, do a lookup to see if previous X tracks contained a decline, if not we need one

                        bool chainLift = trackData.TrackData[i - 1].Qualifier.IsChainLift;

                        //If our current velocity would be negative or zero, we need a chain lift


                        qualifier = new RCT2Qualifier()
                        {
                            IsChainLift             = true,
                            TrackColourSchemeNumber = 0,
                            TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                            AtTerminalStation       = false,
                            StationNumber           = 0
                        };
                    }
                    else
                    {
                        qualifier = new RCT2Qualifier()
                        {
                            IsChainLift             = false,
                            TrackColourSchemeNumber = 0,
                            TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                            AtTerminalStation       = false,
                            StationNumber           = 0
                        };
                    }

                    //Add to track
                    trackData.TrackData.Add(new RCT2TrackPiece()
                    {
                        TrackElement = successor, Qualifier = qualifier
                    });

                    //If it's invalid
                    RCT2TrackData.InvalidityCode invalidityCode = trackData.CheckValidity();
                    if (invalidityCode != RCT2TrackData.InvalidityCode.Valid)
                    {
                        //Remove it and try again
                        reselect = true;
                        trackData.TrackData.Remove(trackData.TrackData.Last());
                        //Console.WriteLine($"\tInvalid Selection, Code: {invalidityCode.ToString()}");
                    }
                    else
                    {
                        reselect = false;
                    }
                } while (reselect);

                //Console.WriteLine($"{trackData.TrackData.Last().TrackElement.ToString()} Selected!");
            }

            //for (int i = 0; i < trackData.TrackData.Count(); i++)
            //{
            //    Console.WriteLine("\t" + trackData.TrackData[i].TrackElement.ToString());
            //}

            return(trackData);
        }
Esempio n. 6
0
        public InvalidityCode CheckValidity()
        {
            //Following Validity Checks:
            // - All Track Pieces connect to the one before it
            // - Track doesn't intersect with itself
            // - Track doesn't exceed max height
            // - Track doesn't go underground (Go lower than the station height)
            // - Track's velocity doesn't go negative
            // - Track has more than one OnRidePhoto
            bool hasRidePhoto = false;

            if (TrackData.Count <= 0)
            {
                return(InvalidityCode.NoTrack);
            }

            //Negative Velocity
            if (!velocityChecked)
            {
                PopulateRideStatistics();
            }

            if (velocityGoesNegative)
            {
                return(InvalidityCode.NegativeVelocity);
            }

            float currentYDisplacement = 0;
            RCT2TrackElementProperty prevElementProperty = RCT2TrackElements.TrackElementPropertyMap[TrackData[0].TrackElement];
            List <Vector3>           UsedCells           = new List <Vector3>();
            Vector3 prevWorldPos         = new Vector3(0.0f, 0.0f, 0.0f);
            int     worldDirectionChange = 0;

            for (int i = 0; i < TrackData.Count; i++)
            {
                RCT2TrackElements.RCT2TrackElement currentElement = TrackData[i].TrackElement;
                RCT2TrackElementProperty           property       = RCT2TrackElements.TrackElementPropertyMap[currentElement];

                // OnRidePhoto Checks
                if (currentElement == RCT2TrackElements.RCT2TrackElement.OnRidePhoto)
                {
                    if (hasRidePhoto)
                    {
                        return(InvalidityCode.TwoRidePhotos);
                    }
                    else
                    {
                        hasRidePhoto = true;
                    }
                }

                // Height Checks
                currentYDisplacement += property.Displacement.Y;
                if (currentYDisplacement >= MaxUnitsOfDisplacement)
                {
                    return(InvalidityCode.ExceedMaxHeight);
                }
                if (currentYDisplacement < 0)
                {
                    return(InvalidityCode.ExceedMinHeight);
                }

                //Prev Element Matching Test
                if (i > 0 &&
                    (prevElementProperty.OutputTrackBank != property.InputTrackBank ||
                     prevElementProperty.OutputTrackDegree != property.InputTrackDegree))
                {
                    return(InvalidityCode.DoesntConnectToPrior);
                }

                //Intersection Tests
                //Get the world version of our property displacement
                //ie, if the segment moves 1 forward, but is already rotated to the left
                //    by 90°, then it actually moves right by 1
                Vector3 worldDisplacement = LocalDisplacementToWorld(property.Displacement, worldDirectionChange);
                Vector3 testCell          = prevWorldPos;
                //Check every tile used in this segment
                //Code is so gross Im so sorry
                for (int x = 1; x <= Math.Abs(worldDisplacement.X); x++)
                {
                    testCell = prevWorldPos + new Vector3(Math.Sign(worldDisplacement.X) * (x), 0, 0);
                    if (!UsedCells.Contains(testCell))
                    {
                        UsedCells.Add(testCell);
                    }
                    else
                    {
                        return(InvalidityCode.Intersection);
                    }
                }
                prevWorldPos = testCell;
                for (int y = 1; y <= Math.Abs(worldDisplacement.Y); y++)
                {
                    testCell = prevWorldPos + new Vector3(0, Math.Sign(worldDisplacement.Y) * (y), 0);
                    if (!UsedCells.Contains(testCell))
                    {
                        UsedCells.Add(testCell);
                    }
                    else
                    {
                        return(InvalidityCode.Intersection);
                    }
                }
                prevWorldPos = testCell;
                for (int z = 1; z <= Math.Abs(worldDisplacement.Z); z++)
                {
                    testCell = prevWorldPos + new Vector3(0, 0, Math.Sign(worldDisplacement.Z) * (z));
                    if (!UsedCells.Contains(testCell))
                    {
                        UsedCells.Add(testCell);
                    }
                    else
                    {
                        return(InvalidityCode.Intersection);
                    }
                }
                prevWorldPos = testCell;

                //Update World Direction Changes
                worldDirectionChange = UpdateRotation(worldDirectionChange, property.DirectionChange);

                //Update variables
                prevElementProperty = property;
            }

            return(InvalidityCode.Valid);
        }
Esempio n. 7
0
        public void PopulateRideStatistics()
        {
            //Inversion Data
            int tempInvCount = 0;

            //Velocity Data
            float totalVelocity   = 0;
            float vehicleVelocity = 0;
            float tempMaxSpeed    = 0;

            //Drop Data
            int   dropCount            = 0;
            bool  inDrop               = false;
            float tempHighestDrop      = 0;
            float curDropHeight        = 0;
            int   tempAirTimeInSeconds = 0;

            //G Forces
            float maxLatG = 0;
            float maxPosG = 0;
            float maxNegG = 0;

            float previousLatG  = 0;
            float previousVertG = 0;

            for (int i = 0; i < TrackData.Count - 1; i++)
            {
                RCT2TrackElementProperty           property = RCT2TrackElements.TrackElementPropertyMap[TrackData[i].TrackElement];
                RCT2TrackElements.RCT2TrackElement element  = TrackData[i].TrackElement;

                //----Check for ride inversions----
                if (CheckInversion(property))
                {
                    tempInvCount++;
                }

                //----Velocity Calculations----
                float tempVel = CalcVelocity(vehicleVelocity, element, TrackData[i].Qualifier, property);
                vehicleVelocity = tempVel;
                totalVelocity  += tempVel;

                if (tempVel > tempMaxSpeed)
                {
                    tempMaxSpeed = tempVel;
                }

                //----Drop Calculations----
                //We've entered a drop
                if (property.Displacement.Y < 0 && !inDrop)
                {
                    //Increment our counters
                    inDrop = true;
                    dropCount++;
                    curDropHeight += property.Displacement.Y * VerticalUnitsToMeters;
                }
                //If we're still in a drop
                else if (property.Displacement.Y < 0)
                {
                    //Add to our measurement of this drop
                    curDropHeight += property.Displacement.Y * VerticalUnitsToMeters;
                }
                //If we end the drop
                else if (property.Displacement.Y >= 0 && inDrop)
                {
                    //Reset our values
                    inDrop = false;
                    if (Math.Abs(curDropHeight) > tempHighestDrop)
                    {
                        tempHighestDrop = Math.Abs(curDropHeight);
                    }
                    curDropHeight = 0;
                }

                //----G Forces----
                float latG  = 0;
                float vertG = 0;
                TrackData[i].GetGForces(vehicleVelocity, out latG, out vertG);

                //Calc air time
                if (vertG < 0)
                {
                    //TODO: Translate into seconds, not sure how to do that really!
                    tempAirTimeInSeconds++;
                }

                //Get current G forces by averaging with previous ones
                vertG        += previousVertG;
                vertG        /= 2;
                previousVertG = vertG;

                latG        += previousLatG;
                latG        /= 2;
                previousLatG = latG;

                latG = Math.Abs(latG);

                //See if it's more than our current maX
                if (latG > maxLatG)
                {
                    maxLatG = latG;
                }
                //Vertical Gs
                if (vertG < 0)
                {
                    //Keep track of Max
                    if (Math.Abs(vertG) > maxNegG)
                    {
                        maxNegG = Math.Abs(vertG);
                    }
                }
                else
                {
                    //Keep track of Max
                    if (vertG > maxPosG)
                    {
                        maxPosG = vertG;
                    }
                }
            }

            //Apply the new values to our global vars
            NumOfInversions = tempInvCount;

            NumOfDrops  = dropCount;
            HighestDrop = (int)tempHighestDrop;

            AverageSpeed    = (int)(totalVelocity / TrackData.Count);
            MaxSpeed        = (int)tempMaxSpeed;
            velocityChecked = true;

            MaxLateralG  = maxLatG;
            MaxPositiveG = maxPosG;
            MaxNegativeG = maxNegG;

            AirTimeInSeconds = tempAirTimeInSeconds;

            float localExcitement = CalculateExcitement();
            float localIntensity  = CalculateIntensity();
            float localNausea     = CalculateNausea();

            ApplyPenalties(ref localExcitement, ref localIntensity, ref localNausea);

            Excitement = localExcitement;
            Intensity  = localIntensity;
            Nausea     = localNausea;
        }
Esempio n. 8
0
        /// <summary>
        /// Encode the RCT2RideData Structure into a Run-Length Unencoded Byte Array
        /// </summary>
        /// <param name="td6Data">The RCT2RideData Structure</param>
        /// <returns>A Byte array containing a full TD6 file</returns>
        public byte[] Encode(RCT2RideData td6Data)
        {
            List <byte> td6Bytes = new List <byte>();

            // Go through the data structure described here and add the bytes in
            // http://freerct.github.io/RCTTechDepot-Archive/TD6.html
            byte dummyByte = 0;

            //00 Track Type
            td6Bytes.Add((byte)RCT2RideCode.RideNameCodeMap[td6Data.TrackType.RideType]);

            //01 ?
            td6Bytes.Add(dummyByte);

            td6Data.RideFeatures.Populate(td6Data.TrackData);

            //02 - Ride Features Byte 0
            byte rideFeaturesByte0 = 0;

            //Straight Flat
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.StraightFlat) ? 0x2 : 0x0);
            //Station Platform
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.StationPlatform) ? 0x4 : 0x0);
            //Lift Chain
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.LiftChain) ? 0x8 : 0x0);
            //Steep Lift Chain
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.SteepLiftChain) ? 0x10 : 0x0);
            //Curve Lift Chain
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.CurveLiftChain) ? 0x20 : 0x0);
            //Banking
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.Banking) ? 0x40 : 0x0);
            //Vertical Loop
            rideFeaturesByte0 |= (byte)((td6Data.RideFeatures.VerticalLoop) ? 0x80 : 0x0);
            td6Bytes.Add(rideFeaturesByte0);

            //03 - Ride Features Byte 1
            byte rideFeaturesByte1 = 0;

            //Normal Slope
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.NormalSlope) ? 0x1 : 0x0);
            //Steep Slope
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.SteepSlope) ? 0x2 : 0x0);
            //Flat-To-Steep
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.FlatToSteep) ? 0x4 : 0x0);
            //Sloped Curves
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.SlopedCurves) ? 0x8 : 0x0);
            //Steep Twist
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.SteepTwist) ? 0x10 : 0x0);
            //S-Bends
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.SBends) ? 0x20 : 0x0);
            //Small radius curves
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.SmallRadiusCurves) ? 0x40 : 0x0);
            //Small radius banked
            rideFeaturesByte1 |= (byte)((td6Data.RideFeatures.SmallRadiusBanked) ? 0x80 : 0x0);
            td6Bytes.Add(rideFeaturesByte1);

            //04 - Ride Features Byte 2
            byte rideFeaturesByte2 = 0;

            //Medium Radius Curves
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.MediumRadiusCurves) ? 0x1 : 0x0);
            //Inline Twist
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.InlineTwist) ? 0x2 : 0x0);
            //Half Loop
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.HalfLoop) ? 0x4 : 0x0);
            //Half Corkscrew
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.HalfCorkscrew) ? 0x8 : 0x0);
            //Tower Base/Vertical
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.TowerBaseVertical) ? 0x10 : 0x0);
            //Helix Banked
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.HelixBanked) ? 0x20 : 0x0);
            //Helix Banked
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.HelixBanked) ? 0x40 : 0x0);
            //Helix Unbanked
            rideFeaturesByte2 |= (byte)((td6Data.RideFeatures.HelixUnbanked) ? 0x80 : 0x0);
            td6Bytes.Add(rideFeaturesByte2);

            //05 - Ride Features Byte 3
            byte rideFeaturesByte3 = 0;

            //Brakes
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.Brakes) ? 0x1 : 0x0);
            //Booster
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.Booster) ? 0x2 : 0x0);
            //On-Ride-Photo
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.OnRidePhoto) ? 0x4 : 0x0);
            //Water Splash
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.WaterSplash) ? 0x8 : 0x0);
            //Vertical Track
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.VerticalTrack) ? 0x10 : 0x0);
            //Barrel Roll
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.BarrelRoll) ? 0x20 : 0x0);
            //Launched Lift Hill
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.LaunchedLiftHill) ? 0x40 : 0x0);
            //Large Half Loop
            rideFeaturesByte3 |= (byte)((td6Data.RideFeatures.LargeHalfLoop) ? 0x80 : 0x0);
            td6Bytes.Add(rideFeaturesByte3);

            //06 Operating Mode
            td6Bytes.Add((byte)td6Data.OperatingMode);

            //07 Vehicle Colour Scheme
            //Third bit is set to 1 for RCT2
            td6Bytes.Add((byte)(0x8 + td6Data.ColourScheme.ColourMode));

            //08-47 32 sets of two byte colour specifiers for vehicles.
            //first byte = body colour, second byte = trim colour
            for (int i = 0; i < 32; i++)
            {
                if (i < td6Data.ColourScheme.BodyColours.Length)
                {
                    td6Bytes.Add((byte)td6Data.ColourScheme.BodyColours[i]);
                }
                else
                {
                    td6Bytes.Add((byte)RCT2VehicleColourScheme.RCT2Colour.Black);
                }

                if (i < td6Data.ColourScheme.TrimColours.Length)
                {
                    td6Bytes.Add((byte)td6Data.ColourScheme.TrimColours[i]);
                }
                else
                {
                    td6Bytes.Add((byte)RCT2VehicleColourScheme.RCT2Colour.Black);
                }
            }

            //48 ?
            td6Bytes.Add(dummyByte);

            //49 Entrance Style
            td6Bytes.Add((byte)td6Data.EntranceStyle);

            //4A Air Time (in seconds / 4)
            td6Bytes.Add((byte)(td6Data.AirTimeInSeconds / 4));

            //4B Departure Control Flags
            //http://freerct.github.io/RCTTechDepot-Archive/controlFlags.html
            byte departureControlFlagsByte = 0;

            //Load Info
            if (td6Data.DepartureFlags.WaitForQuarterLoad)
            {
                departureControlFlagsByte = 0;
            }
            else if (td6Data.DepartureFlags.WaitForHalfLoad)
            {
                departureControlFlagsByte = 0x1;
            }
            else if (td6Data.DepartureFlags.WaitForThreeQuarterLoad)
            {
                departureControlFlagsByte = 0x2;
            }
            else if (td6Data.DepartureFlags.WaitForFullLoad)
            {
                departureControlFlagsByte = 0x3;
            }
            else if (td6Data.DepartureFlags.WaitForAnyLoad)
            {
                departureControlFlagsByte = 0x4;
            }

            //Departure Info
            if (td6Data.DepartureFlags.UseMaximumTime)
            {
                departureControlFlagsByte |= 0x80;
            }
            else if (td6Data.DepartureFlags.UseMinimumTime)
            {
                departureControlFlagsByte |= 0x40;
            }
            else if (td6Data.DepartureFlags.SyncWithAdjacentStation)
            {
                departureControlFlagsByte |= 0x20;
            }
            else if (td6Data.DepartureFlags.LeaveIfAnotherArrives)
            {
                departureControlFlagsByte |= 0x10;
            }
            else if (td6Data.DepartureFlags.WaitForLoad)
            {
                departureControlFlagsByte |= 0x8;
            }

            td6Bytes.Add(departureControlFlagsByte);

            //4C Number of Trains
            td6Bytes.Add((byte)td6Data.NumberOfTrains);

            //4D Number Of Cars per Train
            td6Bytes.Add((byte)td6Data.NumberOfCarsPerTrain);

            //4E Minimum Wait Time in Seconds
            td6Bytes.Add((byte)td6Data.MinWaitTimeInSeconds);

            //4F Maximum Wait Time in Seconds
            td6Bytes.Add((byte)td6Data.MaxWaitTimeInSeconds);

            //50 Speed (Powered Launch/Chairlift/Whoa Belly, or num of laps for go kart, or num of people in a maze)
            //1 bit = 3.616 km/hr 2.25 mph
            if (td6Data.SpeedOfPoweredLaunch != default(float))
            {
                //Speed of powered launch
                td6Bytes.Add((byte)(Math.Round(td6Data.SpeedOfPoweredLaunch / MPHToBit)));
            }
            else if (td6Data.NumberOfGoKartLaps != default(int))
            {
                //Max number of go kart laps
                td6Bytes.Add((byte)td6Data.NumberOfGoKartLaps);
            }
            else
            {
                //Max Number of people in maze
                td6Bytes.Add((byte)td6Data.MaxNumberOfPeopleMaze);
            }

            //51 Max Speed of Ride
            //1 bit = 3.616 km/hr 2.25 mph
            td6Bytes.Add((byte)(Math.Round(td6Data.MaxSpeedOfRide / MPHToBit)));

            //52 Average Speed of Ride
            //1 bit = 3.616 km/hr 2.25 mph
            td6Bytes.Add((byte)(Math.Round((td6Data.AverageSpeedOfRide / MPHToBit))));

            //53-54 Ride Length in Meters
            td6Bytes.Add((byte)td6Data.RideLengthInMetres);
            td6Bytes.Add((byte)(td6Data.RideLengthInMetres >> 8));

            //55 Positive G-Force
            //1 bit = 0.32g
            td6Bytes.Add((byte)(Math.Round((td6Data.PosGForce / GForceToBit))));

            //56 Negative G-Force
            //1 bit = 0.32g
            td6Bytes.Add((byte)(Math.Round((td6Data.NegGForce / GForceToBit))));

            //57 Lateral G-Force
            //1 bit = 0.32g
            td6Bytes.Add((byte)(Math.Round((td6Data.LatGForce / GForceToBit))));

            //58 Number of Inversions
            //Max 31
            td6Bytes.Add((byte)Math.Min(31, td6Data.NumberOfInversions));

            //59 Number of drops
            //Max 63
            td6Bytes.Add((byte)Math.Min(63, td6Data.NumberOfDrops));

            //5A Highest Drop
            //1 bit = 3/4 meter
            td6Bytes.Add((byte)(Math.Round((td6Data.HighestDrop / DropMeterToBit))));

            //5B Excitement
            td6Bytes.Add((byte)td6Data.ExcitementTimesTen);

            //5C Intensity
            td6Bytes.Add((byte)td6Data.IntensityTimesTen);

            //5D Nausea
            td6Bytes.Add((byte)td6Data.NauseaTimesTen);

            //5E ?
            td6Bytes.Add(dummyByte);

            //5F ?
            td6Bytes.Add(dummyByte);

            //60 Track Main Spine Color (Main)
            td6Bytes.Add((byte)td6Data.TrackMainColour);

            //61 Track Main Spine Color (Alt 1)
            td6Bytes.Add((byte)td6Data.TrackMainColourAlt1);

            //62 Track Main Spine Color (Alt 2)
            td6Bytes.Add((byte)td6Data.TrackMainColourAlt2);

            //63 Track Main Spine Color (Alt 3)
            td6Bytes.Add((byte)td6Data.TrackMainColourAlt3);

            //64 Track Additional Rail Color (Main)
            td6Bytes.Add((byte)td6Data.TrackAdditionalColour);

            //65 Track Additional Rail Color (Alt 1)
            td6Bytes.Add((byte)td6Data.TrackAdditionalColourAlt1);

            //66 Track Additional Rail Color (Alt 2)
            td6Bytes.Add((byte)td6Data.TrackAdditionalColourAlt2);

            //67 Track Additional Rail Color (Alt 3)
            td6Bytes.Add((byte)td6Data.TrackAdditionalColourAlt3);

            //68 Track Support Color (Main)
            td6Bytes.Add((byte)td6Data.TrackSupportColour);

            //69 Track Support Color (Alt 1)
            td6Bytes.Add((byte)td6Data.TrackSupportColourAlt1);

            //6A Track Support Color (Alt 2)
            td6Bytes.Add((byte)td6Data.TrackSupportColourAlt2);

            //6B Track Support Color (Alt 3)
            td6Bytes.Add((byte)td6Data.TrackSupportColourAlt3);

            //6C ?
            td6Bytes.Add(dummyByte);

            //6D ?
            td6Bytes.Add(dummyByte);

            //6E ?
            td6Bytes.Add(dummyByte);

            //6F - Six Flags Design if MSB is 1
            td6Bytes.Add(td6Data.IsSixFlagsDesign ? (byte)0x80 : dummyByte);

            //70-73 DAT file flags
            //TODO
            //For now we'll cheat and always use ones for a PTCT1 Track
            td6Bytes.Add(0x80);
            td6Bytes.Add(0xB1);
            td6Bytes.Add(0x58);
            td6Bytes.Add(0x0C);

            //74-7B Vehicle (Alphanumeric - 8 characters with trailing spaces)
            //We're using Wooden Roller Coaster - 4 Seater (PTCT1) for our example
            //And so this will only work properly with PTCT1, as the DAT file flags / checksum will be different
            string vehicle = RCT2RideCode.RideNameVehicleMap[td6Data.TrackType.RideType];

            for (int i = 0; i < 8; i++)
            {
                if (i < vehicle.Length)
                {
                    td6Bytes.Add((byte)vehicle[i]);
                }
                else
                {
                    td6Bytes.Add((byte)' ');
                }
            }


            //7C-7F DAT file checksum
            //TODO
            //For now we'll cheat and always use ones for a PTCT1 Track
            td6Bytes.Add(0xB2);
            td6Bytes.Add(0x81);
            td6Bytes.Add(0x15);
            td6Bytes.Add(0xFF);

            //80-81 Map Space Required (X and Y)
            td6Bytes.Add((byte)td6Data.RequiredMapSpace.X);
            td6Bytes.Add((byte)td6Data.RequiredMapSpace.Y);

            //82-A1 One-byte colour specifiers for vehicles additional colour
            for (int i = 0; i < 32; i++)
            {
                if (i < td6Data.ColourScheme.AdditionalColours.Length)
                {
                    td6Bytes.Add((byte)td6Data.ColourScheme.AdditionalColours[i]);
                }
                else
                {
                    td6Bytes.Add((byte)RCT2VehicleColourScheme.RCT2Colour.Black);
                }
            }

            //A2 - Low 5 bites = lift chain speed (1.6 km/hr per bit)
            //     Upper 3 bits = number of circuits
            byte a2Byte = (byte)(td6Data.NumberOfCircuits & 0x7);

            a2Byte <<= 5;
            a2Byte  |= (byte)((byte)td6Data.LiftChainSpeed & 0x1F);
            td6Bytes.Add(a2Byte);

            //A3 Beginning of track data
            //Each track element is the track segment, then the qualifier, ends with an FF for track segment
            for (int i = 0; i < td6Data.TrackData.TrackData.Count(); i++)
            {
                if (td6Data.TrackData.TrackData[i].TrackElement == RCT2TrackElements.RCT2TrackElement.EndOfTrack)
                {
                    break;
                }

                RCT2TrackElements.RCT2TrackElement currentTrackPiece = td6Data.TrackData.TrackData[i].TrackElement;
                byte currentTrackByte = (byte)currentTrackPiece;

                byte qualifierByte = 0;
                //7 Bit - Chain lift
                if (td6Data.TrackData.TrackData[i].Qualifier.IsChainLift)
                {
                    qualifierByte |= 0x80;
                }

                //6 Bit - Inverted
                if (RCT2TrackElements.TrackElementPropertyMap[currentTrackPiece].InputTrackBank == RCT2TrackElementProperty.RCT2TrackBank.Flipped ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrackPiece].OutputTrackBank == RCT2TrackElementProperty.RCT2TrackBank.Flipped)
                {
                    qualifierByte |= 0x40;
                }

                //5 & 4 - Colour Scheme
                qualifierByte |= (byte)((td6Data.TrackData.TrackData[i].Qualifier.TrackColourSchemeNumber) << 4);

                //3, 2, 1 - Stations:
                if (td6Data.TrackData.TrackData[i].Qualifier.AtTerminalStation)
                {
                    qualifierByte |= 0x8;
                    qualifierByte |= (byte)td6Data.TrackData.TrackData[i].Qualifier.StationNumber;
                }
                else
                {
                    //Rotation value
                    qualifierByte |= (byte)td6Data.TrackData.TrackData[i].Qualifier.TrackRotation;
                }

                //Add to file
                Console.WriteLine("Adding Track Piece: " + currentTrackPiece.ToString() + ", with byte: " + currentTrackByte.ToString());
                Console.WriteLine("Adding Qualifier: " + qualifierByte.ToString());

                td6Bytes.Add(currentTrackByte);
                td6Bytes.Add(qualifierByte);
            }

            //End of track byte
            td6Bytes.Add(0xFF);

            //Add in the Entracne/Exit data
            //This is just entrance/exit data taken from an existing RCT2 TD6 file
            //With them next to each other on a two-station long area
            td6Bytes.Add(0x00);
            td6Bytes.Add(0x03);
            td6Bytes.Add(0x00);
            td6Bytes.Add(0x00);
            td6Bytes.Add(0x20);
            td6Bytes.Add(0x00);
            td6Bytes.Add(0x00);
            td6Bytes.Add(0x83);
            td6Bytes.Add(0xE0);
            td6Bytes.Add(0xFF);
            td6Bytes.Add(0x20);
            td6Bytes.Add(0x00);
            td6Bytes.Add(0xFF);
            td6Bytes.Add(0xFF);

            //Pad out to 24,735 which is the fixed length
            for (int i = td6Bytes.Count; i < TD6FileSize; i++)
            {
                td6Bytes.Add(dummyByte);
            }

            return(td6Bytes.ToArray());
        }
Esempio n. 9
0
        public void Populate(RCT2TrackData track)
        {
            //If the track is empty, return
            if (track == null || track.TrackData == null || track.TrackData.Count <= 0)
            {
                return;
            }

            //Give all our bytes an initial value
            StraightFlat    = false;
            StationPlatform = false;
            LiftChain       = false;
            SteepLiftChain  = false;
            CurveLiftChain  = false;
            Banking         = false;
            VerticalLoop    = false;

            NormalSlope       = false;
            SteepSlope        = false;
            FlatToSteep       = false;
            SlopedCurves      = false;
            SteepTwist        = false;
            SBends            = false;
            SmallRadiusCurves = false;
            SmallRadiusBanked = false;

            MediumRadiusCurves = false;
            InlineTwist        = false;
            HalfLoop           = false;
            HalfCorkscrew      = false;
            TowerBaseVertical  = false;
            HelixBanked        = false;
            HelixUnbanked      = false;

            Brakes           = false;
            Booster          = false;
            OnRidePhoto      = false;
            WaterSplash      = false;
            VerticalTrack    = false;
            BarrelRoll       = false;
            LaunchedLiftHill = false;
            LargeHalfLoop    = false;


            //Go through every track piece and populate our bytes
            RCT2TrackElements.RCT2TrackElement prevTrackPiece = track.TrackData[0].TrackElement;
            for (int i = 0; i < track.TrackData.Count; i++)
            {
                RCT2TrackElements.RCT2TrackElement currentTrack = track.TrackData[i].TrackElement;

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.Flat)
                {
                    StraightFlat = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.BeginStation ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.MiddleStation ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.EndStation)
                {
                    StationPlatform = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.CableLiftHill ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.LeftCurvedLiftHill ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.PoweredLift ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.RightCurvedLiftHill)
                {
                    LiftChain = true;
                }

                //Steep Lift Chain not needed for our chosen problem space

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.LeftCurvedLiftHill ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.RightCurvedLiftHill)
                {
                    CurveLiftChain = true;
                }

                if (RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackBank != RCT2TrackElementProperty.RCT2TrackBank.None ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackBank != RCT2TrackElementProperty.RCT2TrackBank.None)
                {
                    Banking = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.LeftVerticalLoop ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.RightVerticalLoop)
                {
                    VerticalLoop = true;
                }

                if (RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Up25 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Up25 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Down25 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Down25)
                {
                    NormalSlope = true;
                }

                if (RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Up60 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Up60 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Down60 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Down60)
                {
                    SteepSlope = true;
                }

                if (RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackBank == RCT2TrackElementProperty.RCT2TrackBank.Flipped ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackBank == RCT2TrackElementProperty.RCT2TrackBank.Flipped)
                {
                    SteepTwist = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.LeftSBend ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.LeftSBendCovered ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.RightSBend ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.RightSBendCovered)
                {
                    SBends = true;
                }

                if (currentTrack.ToString().ToLower().Contains("across1"))
                {
                    SmallRadiusCurves = true;
                }

                if (currentTrack.ToString().ToLower().Contains("bank"))
                {
                    SmallRadiusBanked = true;
                }

                if (currentTrack.ToString().ToLower().Contains("across3"))
                {
                    MediumRadiusCurves = true;
                }

                if (currentTrack.ToString().ToLower().Contains("twist"))
                {
                    InlineTwist = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.HalfLoopUp ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.HalfLoopDown ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.FlyerHalfLoopUp ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.FlyerHalfLoopDown)
                {
                    HalfLoop = true;
                }

                if (currentTrack.ToString().ToLower().Contains("corkscrew"))
                {
                    HalfCorkscrew = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.TowerBase ||
                    currentTrack == RCT2TrackElements.RCT2TrackElement.TowerSection)
                {
                    TowerBaseVertical = true;
                }

                if (currentTrack.ToString().ToLower().Contains("bankedhelix"))
                {
                    HelixBanked = true;
                }
                else if (currentTrack.ToString().ToLower().Contains("helix"))
                {
                    HelixUnbanked = true;
                }

                if (currentTrack.ToString().ToLower().Contains("brake"))
                {
                    Brakes = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.OnRidePhoto)
                {
                    OnRidePhoto = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.Watersplash)
                {
                    WaterSplash = true;
                }

                if (RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Down90 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Down90 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].InputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Up90 ||
                    RCT2TrackElements.TrackElementPropertyMap[currentTrack].OutputTrackDegree == RCT2TrackElementProperty.RCT2TrackDegree.Up90)
                {
                    VerticalTrack = true;
                }

                if (currentTrack.ToString().ToLower().Contains("barrelroll"))
                {
                    BarrelRoll = true;
                }

                if (currentTrack == RCT2TrackElements.RCT2TrackElement.PoweredLift)
                {
                    LaunchedLiftHill = true;
                }

                if (currentTrack.ToString().ToLower().Contains("largehalfloop"))
                {
                    LargeHalfLoop = true;
                }

                prevTrackPiece = currentTrack;
            }
        }