private bool CheckInversion(RCT2TrackElementProperty property) { //Check for ride inversions if ((property.InputTrackBank != RCT2TrackElementProperty.RCT2TrackBank.Flipped && property.OutputTrackBank == RCT2TrackElementProperty.RCT2TrackBank.Flipped) || (property.InputTrackBank == RCT2TrackElementProperty.RCT2TrackBank.Flipped && property.OutputTrackBank != RCT2TrackElementProperty.RCT2TrackBank.Flipped)) { return(true); } return(false); }
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); }
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); }
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); }
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); }
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; }