/// <summary> /// Race mode only: detect whether the player is within <c>maxDistance</c> of the active checkpoint. Activate next checkpoint and return sector time, if within range. /// </summary> /// <param name="maxDistance">Maximum distance in meters to trigger checkpoint.</param> /// <param name="force3D">Distance computation defaults to 2D (x-y plane only) unless this flag is true</param> /// <returns></returns> public int activeCheckpointDetection(float margin = checkpointMargin, bool force3D = false) { // get player's position and compute distance to the position of the active checkpoint float dist = Game.Player.Character.Position.DistanceTo2D(activeCheckpoint.position); // get data on player's current vehicle Vehicle veh = Game.Player.Character.CurrentVehicle; // if player is not currently in a vehicle, display message and exit race mode if (veh == null) { GTA.UI.Screen.ShowSubtitle("Lap Timer: exited vehicle; leaving Race Mode."); exitRaceMode(); return(int.MaxValue); } try { // check if it is within the specified maximum (margin * checkpointRadius) if (dist < margin * SectorCheckpoint.checkpointRadius) { // compute time elapsed since race start int elapsedTime = Game.GameTime - lapStartTime; // save and display elapsed TimeType tType = activeCheckpoint.timing.updateTiming(elapsedTime, veh.DisplayName); string notifString = activeCheckpoint.timing.getLatestTimingSummaryString(); GTA.UI.Notification.Show(string.Format("Checkpoint {0}: ~n~{1}", activeSector, notifString)); // detect if the checkpoint reached is the final checkpoint if (activeCheckpoint.GetHashCode() == finishCheckpoint.GetHashCode()) { lapFinishedHandler(activeCheckpoint, lapRace); } // activate next checkpoint if race mode is still active if (raceMode) { activateRaceCheckpoint(activeSector + 1); } } } catch (Exception e) { GTA.UI.Notification.Show("Lap Timer Exception: " + e.StackTrace.ToString()); } return(0); }
/// <summary> /// Activate the provided SectorCheckpoint after deactivating the current active checkpoint. /// By activating, a marker will be placed at the checkpoint, and timer will run until player is in range of the checkpoint. /// If the index is out of bounds (>= no. of checkpoints), either end the race or reset the lap. /// </summary> /// <param name="idx">List index of SectorCheckpoint to activate in <c>markedSectorCheckpoints</c></param> /// <returns>The now-active SectorCheckpoint</returns> private SectorCheckpoint activateRaceCheckpoint(int idx) { // deactivate current active checkpoint's marker try { markedSectorCheckpoints[activeSector].hideMarker(); } catch { } // detect if index is out of expected range if (idx >= markedSectorCheckpoints.Count && lapRace) { //// if point-to-point race, then race is completed. Print time and exit race mode. //if (!lapRace) //{ // lapFinishedHandler(activeCheckpoint); // return activeCheckpoint; //} //// if lapped race, activate the 0th checkpoint //else //{ // idx = 0; //} idx = 0; } // set the new SectorCheckpoint as active (by index) activeSector = idx; activeCheckpoint = markedSectorCheckpoints[idx]; // determine if this is the final checkpoint based on the index bool isFinal = activeCheckpoint.GetHashCode() == finishCheckpoint.GetHashCode(); //idx == markedSectorCheckpoints.Count - 1 || idx == 0; // the marker placed should be different, depending on whether this checkpoint is final if (isFinal) { activeCheckpoint.marker = activeCheckpoint.placeMarker(MarkerType.raceFinish, idx); } // if not final checkpoint, place a checkpoint w/ an arrow pointing to the next checkpoint else { Vector3 nextChkptPosition = getNextCheckpoint(idx).position; activeCheckpoint.marker = activeCheckpoint.placeMarker(MarkerType.raceArrow, idx, nextChkptPosition); } return(activeCheckpoint); }