private void testDriverNames() { List <OpponentData> driversToTest = new List <OpponentData>(); List <String> rawDriverNames = new List <string>(); DirectoryInfo soundDirectory = new DirectoryInfo(AudioPlayer.soundFilesPath); FileInfo[] filesInSoundDirectory = soundDirectory.GetFiles(); foreach (FileInfo fileInSoundDirectory in filesInSoundDirectory) { if (fileInSoundDirectory.Name == "names_test.txt") { String[] lines = File.ReadAllLines(Path.Combine(AudioPlayer.soundFilesPath, fileInSoundDirectory.Name)); foreach (String line in lines) { if (line.Trim().Length > 0) { driversToTest.Add(makeTempDriver(line.Trim(), rawDriverNames)); } } break; } } if (rawDriverNames.Count > 0) { Console.WriteLine("Playing test sounds for drivers " + String.Join(", ", rawDriverNames)); List <String> usableDriverNames = DriverNameHelper.getUsableDriverNames(rawDriverNames); int index = 0; foreach (OpponentData driverToTest in driversToTest) { if (SoundCache.availableDriverNames.Contains(DriverNameHelper.getUsableDriverName(driverToTest.DriverRawName))) { audioPlayer.playMessage(new QueuedMessage("gap_in_front" + index, 0, messageFragments: MessageContents(Timings.folderTheGapTo, driverToTest, Timings.folderAheadIsIncreasing, TimeSpan.FromSeconds((float)Utilities.random.NextDouble() * 10)), alternateMessageFragments: MessageContents(Timings.folderGapInFrontIncreasing, TimeSpan.FromSeconds((float)Utilities.random.NextDouble() * 10)), abstractEvent: this)); audioPlayer.wakeMonitorThreadForRegularMessages(DateTime.UtcNow); audioPlayer.playMessage(new QueuedMessage("leader_pitting" + index, 0, messageFragments: MessageContents(Opponents.folderTheLeader, driverToTest, Opponents.folderIsPitting), abstractEvent: this)); audioPlayer.wakeMonitorThreadForRegularMessages(DateTime.UtcNow); audioPlayer.playMessage(new QueuedMessage("new_fastest_lap" + index, 0, messageFragments: MessageContents(Opponents.folderNewFastestLapFor, driverToTest, TimeSpan.FromSeconds(Utilities.random.NextDouble() * 100)), abstractEvent: this)); audioPlayer.wakeMonitorThreadForRegularMessages(DateTime.UtcNow); index++; } else { Console.WriteLine("No sound file for driver " + driverToTest.DriverRawName + " - unable to play test sounds"); } } } }
override protected void triggerInternal(GameStateData previousGameState, GameStateData currentGameState) { var cgs = currentGameState; var pgs = previousGameState; if (cgs.PitData.InPitlane || /*|| cgs.SessionData.SessionRunningTime < 10 */ GameStateData.onManualFormationLap || // We may want manual formation to phase of FrozenOrder. pgs == null) { return; // don't process if we're in the pits or just started a session } var cfod = cgs.FrozenOrderData; var pfod = pgs.FrozenOrderData; var cfodp = cgs.FrozenOrderData.Phase; if (cfodp == FrozenOrderPhase.None) { return; // Nothing to do. } var useAmericanTerms = GlobalBehaviourSettings.useAmericanTerms || GlobalBehaviourSettings.useOvalLogic; var useOvalLogic = GlobalBehaviourSettings.useOvalLogic; if (pfod.Phase == FrozenOrderPhase.None) { Console.WriteLine("Frozen Order: New Phase detected: " + cfod.Phase); int delay = Utilities.random.Next(0, 3); if (cfod.Phase == FrozenOrderPhase.Rolling) { audioPlayer.playMessage(new QueuedMessage(folderRollingStartReminder, delay + 4, secondsDelay: delay, abstractEvent: this, priority: 10)); } else if (cfod.Phase == FrozenOrderPhase.FormationStanding) { audioPlayer.playMessage(new QueuedMessage(folderStandingStartReminder, delay + 4, secondsDelay: delay, abstractEvent: this, priority: 10)); } // Clear previous state. this.clearState(); } // Because FO Action is distance dependent, it tends to fluctuate. // We need to detect when it stabilizes (values stay identical for ACTION_STABLE_THRESHOLD times). if (cfod.Action == pfod.Action && cfod.DriverToFollowRaw == pfod.DriverToFollowRaw && cfod.AssignedColumn == pfod.AssignedColumn) { ++this.numUpdatesActionSame; } else { this.newFrozenOrderAction = cfod.Action; this.newDriverToFollow = cfod.DriverToFollowRaw; this.newFrozenOrderColumn = cfod.AssignedColumn; this.numUpdatesActionSame = 0; } var isActionUpdateStable = this.numUpdatesActionSame >= FrozenOrderMonitor.ACTION_STABLE_THRESHOLD; // Detect if we should be following SC, as SC has no driver name. var shouldFollowSafetyCar = false; var driverToFollow = ""; if (cfodp == FrozenOrderPhase.Rolling || cfodp == FrozenOrderPhase.FullCourseYellow) { shouldFollowSafetyCar = (cfod.AssignedColumn == FrozenOrderColumn.None && cfod.AssignedPosition == 1) || // Single file order. (cfod.AssignedColumn != FrozenOrderColumn.None && cfod.AssignedPosition <= 2); // Double file (grid) order. driverToFollow = shouldFollowSafetyCar ? (useAmericanTerms ? folderThePaceCar : folderTheSafetyCar) : cfod.DriverToFollowRaw; } if (cfodp == FrozenOrderPhase.Rolling) { var prevDriverToFollow = this.currDriverToFollow; var prevFrozenOrderAction = this.currFrozenOrderAction; if (isActionUpdateStable && (this.currFrozenOrderAction != this.newFrozenOrderAction || this.currDriverToFollow != this.newDriverToFollow || this.currFrozenOrderColumn != this.newFrozenOrderColumn)) { this.currFrozenOrderAction = this.newFrozenOrderAction; this.currDriverToFollow = this.newDriverToFollow; this.currFrozenOrderColumn = this.newFrozenOrderColumn; // canReadDriverToFollow will be true if we're behind the safety car or we can read the driver's name: var canReadDriverToFollow = shouldFollowSafetyCar || AudioPlayer.canReadName(driverToFollow); var usableDriverNameToFollow = shouldFollowSafetyCar ? driverToFollow : DriverNameHelper.getUsableDriverName(driverToFollow); var validationData = new Dictionary <string, object>(); validationData.Add(FrozenOrderMonitor.validateMessageTypeKey, FrozenOrderMonitor.validateMessageTypeAction); validationData.Add(FrozenOrderMonitor.validationActionKey, cfod.Action); validationData.Add(FrozenOrderMonitor.validationAssignedPositionKey, cfod.AssignedPosition); validationData.Add(FrozenOrderMonitor.validationDriverToFollowKey, cfod.DriverToFollowRaw); if (this.newFrozenOrderAction == FrozenOrderAction.Follow && prevDriverToFollow != this.currDriverToFollow) // Don't announce Follow messages for the driver that we caught up to or allowed to pass. { if (canReadDriverToFollow) { // Follow messages are only meaningful if there's name to announce. int delay = Utilities.random.Next(3, 6); if (cfod.AssignedColumn == FrozenOrderColumn.None || Utilities.random.Next(1, 11) > 8) // Randomly, announce message without coulmn info. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver" : "frozen_order/follow_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } else { string columnName; if (useOvalLogic) { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheInsideColumn : folderInTheOutsideColumn; } else { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheLeftColumn : folderInTheRightColumn; } audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver_in_col" : "frozen_order/follow_safecy_car_in_col", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow, columnName), abstractEvent: this, validationData: validationData, priority: 10)); } } } else if (this.newFrozenOrderAction == FrozenOrderAction.AllowToPass) { // Follow messages are only meaningful if there's name to announce. int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/allow_driver_to_pass" : "frozen_order/allow_safety_car_to_pass", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderAllow, usableDriverNameToFollow, folderToPass), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYoureAheadOfAGuyYouShouldBeFollowing, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.CatchUp) { int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/catch_up_to_driver" : "frozen_order/catch_up_to_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderCatchUpTo, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYouNeedToCatchUpToTheGuyAhead, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.StayInPole && prevFrozenOrderAction != FrozenOrderAction.MoveToPole) // No point in nagging user to stay in pole if we previously told them to move there. { int delay = Utilities.random.Next(0, 3); if (cfod.AssignedColumn == FrozenOrderColumn.None || Utilities.random.Next(1, 11) > 8) // Randomly, announce message without coulmn info. { audioPlayer.playMessage(new QueuedMessage("frozen_order/stay_in_pole", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderStayInPole), abstractEvent: this, validationData: validationData, priority: 10)); } else { string folderToPlay = null; if (useOvalLogic) { folderToPlay = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderStayInPoleInInsideColumn : folderStayInPoleInOutsideColumn; } else { folderToPlay = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderStayInPoleInLeftColumn : folderStayInPoleInRightColumn; } audioPlayer.playMessage(new QueuedMessage("frozen_order/stay_in_pole_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderToPlay), abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.MoveToPole) { int delay = Utilities.random.Next(2, 5); if (cfod.AssignedColumn == FrozenOrderColumn.None) { audioPlayer.playMessage(new QueuedMessage("frozen_order/move_to_pole", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderMoveToPole), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/move_to_pole_row", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderMoveToPoleRow), abstractEvent: this, validationData: validationData, priority: 10)); } } } } else if (cfodp == FrozenOrderPhase.FullCourseYellow) { var prevDriverToFollow = this.currDriverToFollow; var prevFrozenOrderColumn = this.currFrozenOrderColumn; var announceSCRLastFCYLapLane = useAmericanTerms && currentGameState.StockCarRulesData.stockCarRulesEnabled && (currentGameState.FlagData.fcyPhase == FullCourseYellowPhase.LAST_LAP_NEXT || currentGameState.FlagData.fcyPhase == FullCourseYellowPhase.LAST_LAP_CURRENT); if (isActionUpdateStable && (this.currFrozenOrderAction != this.newFrozenOrderAction || this.currDriverToFollow != this.newDriverToFollow || this.currFrozenOrderColumn != this.newFrozenOrderColumn || announceSCRLastFCYLapLane && !this.scrLastFCYLapLaneAnnounced)) { this.currFrozenOrderAction = this.newFrozenOrderAction; this.currDriverToFollow = this.newDriverToFollow; this.currFrozenOrderColumn = this.newFrozenOrderColumn; this.scrLastFCYLapLaneAnnounced = announceSCRLastFCYLapLane; // canReadDriverToFollow will be true if we're behind the safety car or we can read the driver's name: var canReadDriverToFollow = shouldFollowSafetyCar || AudioPlayer.canReadName(driverToFollow); var usableDriverNameToFollow = shouldFollowSafetyCar ? driverToFollow : DriverNameHelper.getUsableDriverName(driverToFollow); var validationData = new Dictionary <string, object>(); validationData.Add(FrozenOrderMonitor.validateMessageTypeKey, FrozenOrderMonitor.validateMessageTypeAction); validationData.Add(FrozenOrderMonitor.validationActionKey, cfod.Action); validationData.Add(FrozenOrderMonitor.validationAssignedPositionKey, cfod.AssignedPosition); validationData.Add(FrozenOrderMonitor.validationDriverToFollowKey, cfod.DriverToFollowRaw); if (this.newFrozenOrderAction == FrozenOrderAction.Follow && ((prevDriverToFollow != this.currDriverToFollow) || // Don't announce Follow messages for the driver that we caught up to or allowed to pass. (prevFrozenOrderColumn != this.currFrozenOrderColumn && announceSCRLastFCYLapLane))) // But announce for SCR last FCY lap. { int delay = Utilities.random.Next(0, 3); if (canReadDriverToFollow) { if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Left) { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver_in_left" : "frozen_order/follow_safety_car_in_left", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow, useOvalLogic ? folderInTheInsideColumn : folderInTheLeftColumn), abstractEvent: this, validationData: validationData, priority: 10)); } else if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Right) { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver_in_right" : "frozen_order/follow_safety_car_in_right", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow, useOvalLogic ? folderInTheOutsideColumn : folderInTheRightColumn), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver" : "frozen_order/follow_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } } else if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Left) { audioPlayer.playMessage(new QueuedMessage(useOvalLogic ? folderLineUpInInsideColumn : folderLineUpInLeftColumn, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } else if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Right) { audioPlayer.playMessage(new QueuedMessage(useOvalLogic ? folderLineUpInOutsideColumn : folderLineUpInRightColumn, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.AllowToPass) { int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/allow_driver_to_pass" : "frozen_order/allow_safety_car_to_pass", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderAllow, usableDriverNameToFollow, folderToPass), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYoureAheadOfAGuyYouShouldBeFollowing, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.CatchUp) { int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/catch_up_to_driver" : "frozen_order/catch_up_to_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderCatchUpTo, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYouNeedToCatchUpToTheGuyAhead, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } } } else if (cfodp == FrozenOrderPhase.FormationStanding) { string columnName = null; if (cfod.AssignedColumn != FrozenOrderColumn.None) { if (useOvalLogic) { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheInsideColumn : folderInTheOutsideColumn; } else { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheLeftColumn : folderInTheRightColumn; } } if (!this.formationStandingStartAnnounced && cgs.SessionData.SessionRunningTime > 10) { this.formationStandingStartAnnounced = true; var isStartingFromPole = cfod.AssignedPosition == 1; int delay = Utilities.random.Next(0, 3); if (isStartingFromPole) { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage(folderWereStartingFromPole, 6, abstractEvent: this)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/youre_starting_from_pole_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderWereStartingFromPole, columnName), abstractEvent: this, priority: 10)); } } else { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage("frozen_order/youre_starting_from_pos", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderWeStartingFromPosition, cfod.AssignedPosition), abstractEvent: this, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/youre_starting_from_pos_row_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderWeStartingFromPosition, cfod.AssignedPosition, folderRow, cfod.AssignedGridPosition, columnName), abstractEvent: this, priority: 10)); } } } if (!this.formationStandingPreStartReminderAnnounced && cgs.SessionData.SectorNumber == 3 && cgs.PositionAndMotionData.DistanceRoundTrack > (cgs.SessionData.TrackDefinition.trackLength - FrozenOrderMonitor.DIST_TO_START_TO_ANNOUNCE_POS_REMINDER)) { this.formationStandingPreStartReminderAnnounced = true; var isStartingFromPole = cfod.AssignedPosition == 1; int delay = Utilities.random.Next(0, 3); if (isStartingFromPole) { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_starting_from_pole", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWereStartingFromPole), abstractEvent: this, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_starting_from_pole_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWereStartingFromPole, columnName), abstractEvent: this, priority: 10)); } } else { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_youre_starting_from_pos", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWeStartingFromPosition, cfod.AssignedPosition), abstractEvent: this, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_youre_starting_from_pos_row_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWeStartingFromPosition, cfod.AssignedPosition, folderRow, cfod.AssignedGridPosition, columnName), abstractEvent: this, priority: 10)); } } } } // Announce SC speed. if (pfod.SafetyCarSpeed == -1.0f && cfod.SafetyCarSpeed != -1.0f) { // TODO: may also need to announce basic "SC in" message. var kmPerHour = cfod.SafetyCarSpeed * 3.6f; var messageFragments = new List <MessageFragment>(); if (useAmericanTerms) { messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderPaceCarSpeedIs)); var milesPerHour = kmPerHour * 0.621371f; messageFragments.Add(MessageFragment.Integer((int)Math.Round(milesPerHour), false)); messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderMilesPerHour)); } else { messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderSafetyCarSpeedIs)); messageFragments.Add(MessageFragment.Integer((int)Math.Round(kmPerHour), false)); messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderKilometresPerHour)); } int delay = Utilities.random.Next(10, 16); audioPlayer.playMessage(new QueuedMessage("frozen_order/pace_car_speed", delay + 6, secondsDelay: delay, messageFragments: messageFragments, abstractEvent: this, priority: 10)); } // Announce SC left. if (pfod.SafetyCarSpeed != -1.0f && cfod.SafetyCarSpeed == -1.0f) { if (useAmericanTerms) { audioPlayer.playMessage(new QueuedMessage(folderPaceCarJustLeft, 10, abstractEvent: this)); } else { audioPlayer.playMessage(new QueuedMessage(folderSafetyCarJustLeft, 10, abstractEvent: this)); } } // For fast rolling, do nothing for now. }
private Tuple <string, Boolean> getOpponentKey(String voiceMessage, String expectedNumberSuffix) { string opponentKey = null; Boolean gotByPositionNumber = false; if (voiceMessage.Contains(SpeechRecogniser.THE_LEADER)) { if (currentGameState.SessionData.Position > 1) { opponentKey = currentGameState.getOpponentKeyAtPosition(1, false); } else if (currentGameState.SessionData.Position == 1) { opponentKey = positionIsPlayerKey; } } if ((voiceMessage.Contains(SpeechRecogniser.THE_CAR_AHEAD) || voiceMessage.Contains(SpeechRecogniser.THE_GUY_AHEAD) || voiceMessage.Contains(SpeechRecogniser.THE_GUY_IN_FRONT) || voiceMessage.Contains(SpeechRecogniser.THE_CAR_IN_FRONT)) && currentGameState.SessionData.Position > 1) { opponentKey = currentGameState.getOpponentKeyInFront(false); } else if ((voiceMessage.Contains(SpeechRecogniser.THE_CAR_BEHIND) || voiceMessage.Contains(SpeechRecogniser.THE_GUY_BEHIND)) && !currentGameState.isLast()) { opponentKey = currentGameState.getOpponentKeyBehind(false); } else if (voiceMessage.Contains(SpeechRecogniser.POSITION_LONG) || voiceMessage.Contains(SpeechRecogniser.POSITION_SHORT)) { int position = 0; foreach (KeyValuePair <String, int> entry in SpeechRecogniser.numberToNumber) { if (expectedNumberSuffix.Length > 0) { if (voiceMessage.Contains(" " + entry.Key + expectedNumberSuffix)) { position = entry.Value; break; } } else { if (voiceMessage.EndsWith(" " + entry.Key)) { position = entry.Value; break; } } } if (position != currentGameState.SessionData.Position) { opponentKey = currentGameState.getOpponentKeyAtPosition(position, false); } else { opponentKey = positionIsPlayerKey; } gotByPositionNumber = true; } else { foreach (KeyValuePair <string, OpponentData> entry in currentGameState.OpponentData) { String usableDriverName = DriverNameHelper.getUsableDriverName(entry.Value.DriverRawName); if (voiceMessage.Contains(usableDriverName)) { opponentKey = entry.Key; break; } } } return(new Tuple <string, bool>(opponentKey, gotByPositionNumber)); }
override protected void triggerInternal(GameStateData previousGameState, GameStateData currentGameState) { this.currentGameState = currentGameState; if (nextCarAheadChangeMessage == DateTime.MinValue) { nextCarAheadChangeMessage = currentGameState.Now.Add(TimeSpan.FromSeconds(30)); } if (nextLeadChangeMessage == DateTime.MinValue) { nextLeadChangeMessage = currentGameState.Now.Add(TimeSpan.FromSeconds(30)); } if (currentGameState.SessionData.SessionType != SessionType.Race || frequencyOfOpponentRaceLapTimes > 0) { foreach (KeyValuePair <string, OpponentData> entry in currentGameState.OpponentData) { string opponentKey = entry.Key; OpponentData opponentData = entry.Value; if (opponentData.IsNewLap && opponentData.LastLapTime > 0 && opponentData.OpponentLapData.Count > 1 && opponentData.LastLapValid && opponentData.CurrentBestLapTime > 0) { float currentFastestLap; if (currentGameState.SessionData.PlayerLapTimeSessionBest == -1) { currentFastestLap = currentGameState.SessionData.OpponentsLapTimeSessionBestOverall; } else if (currentGameState.SessionData.OpponentsLapTimeSessionBestOverall == -1) { currentFastestLap = currentGameState.SessionData.PlayerLapTimeSessionBest; } else { currentFastestLap = Math.Min(currentGameState.SessionData.PlayerLapTimeSessionBest, currentGameState.SessionData.OpponentsLapTimeSessionBestOverall); } // this opponent has just completed a lap - do we need to report it? if it's fast overall and more than // a tenth quicker then his previous best we do... if (((currentGameState.SessionData.SessionType == SessionType.Race && opponentData.CompletedLaps > 2) || (currentGameState.SessionData.SessionType != SessionType.Race && opponentData.CompletedLaps > 1)) && opponentData.LastLapTime <= currentFastestLap && (SoundCache.hasSuitableTTSVoice || SoundCache.availableDriverNames.Contains(DriverNameHelper.getUsableDriverName(opponentData.DriverRawName)))) { audioPlayer.playMessage(new QueuedMessage("new_fastest_lap", MessageContents(folderNewFastestLapFor, opponentData, TimeSpan.FromSeconds(opponentData.LastLapTime)), 0, this)); } else if ((currentGameState.SessionData.SessionType == SessionType.Race && (opponentData.LastLapTime <= opponentData.CurrentBestLapTime && opponentData.LastLapTime < opponentData.PreviousBestLapTime - minImprovementBeforeReadingOpponentRaceTime && opponentData.LastLapTime < currentFastestLap + maxOffPaceBeforeReadingOpponentRaceTime)) || ((currentGameState.SessionData.SessionType == SessionType.Practice || currentGameState.SessionData.SessionType == SessionType.Qualify) && opponentData.LastLapTime <= opponentData.CurrentBestLapTime)) { if (currentGameState.SessionData.UnFilteredPosition > 1 && opponentData.UnFilteredPosition == 1 && (currentGameState.SessionData.SessionType == SessionType.Race || frequencyOfOpponentPracticeAndQualLapTimes > 0)) { // he's leading, and has recorded 3 or more laps, and this one's his fastest Console.WriteLine("Leader fast lap - this lap time = " + opponentData.LastLapTime + " session best = " + currentFastestLap); audioPlayer.playMessage(new QueuedMessage("leader_good_laptime", MessageContents(folderLeaderHasJustDoneA, TimeSpan.FromSeconds(opponentData.LastLapTime)), 0, this)); } else if (currentGameState.SessionData.UnFilteredPosition > 1 && opponentData.UnFilteredPosition == currentGameState.SessionData.Position - 1 && (currentGameState.SessionData.SessionType == SessionType.Race || random.Next(10) < frequencyOfOpponentPracticeAndQualLapTimes)) { // he's ahead of us, and has recorded 3 or more laps, and this one's his fastest Console.WriteLine("Car ahead fast lap - this lap time = " + opponentData.LastLapTime + " session best = " + currentFastestLap); audioPlayer.playMessage(new QueuedMessage("car_ahead_good_laptime", MessageContents(folderTheCarAheadHasJustDoneA, TimeSpan.FromSeconds(opponentData.LastLapTime)), 0, this)); } else if (!currentGameState.isLast() && opponentData.UnFilteredPosition == currentGameState.SessionData.Position + 1 && (currentGameState.SessionData.SessionType == SessionType.Race || random.Next(10) < frequencyOfOpponentPracticeAndQualLapTimes)) { // he's behind us, and has recorded 3 or more laps, and this one's his fastest Console.WriteLine("Car behind fast lap - this lap time = " + opponentData.LastLapTime + " session best = " + currentFastestLap); audioPlayer.playMessage(new QueuedMessage("car_behind_good_laptime", MessageContents(folderTheCarBehindHasJustDoneA, TimeSpan.FromSeconds(opponentData.LastLapTime)), 0, this)); } } } } } if (currentGameState.SessionData.SessionType == SessionType.Race) { if (!currentGameState.SessionData.IsRacingSameCarInFront) { if (currentGameState.SessionData.Position > 2 && currentGameState.Now > nextCarAheadChangeMessage && !currentGameState.PitData.InPitlane && currentGameState.SessionData.CompletedLaps > 0) { OpponentData opponentData = currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position - 1, false); if (opponentData != null && !opponentData.isEnteringPits() && !opponentData.InPits && (SoundCache.hasSuitableTTSVoice || SoundCache.availableDriverNames.Contains(DriverNameHelper.getUsableDriverName(opponentData.DriverRawName)))) { audioPlayer.playMessage(new QueuedMessage("new_car_ahead", MessageContents(folderNextCarIs, opponentData), random.Next(Position.maxSecondsToWaitBeforeReportingPass + 1, Position.maxSecondsToWaitBeforeReportingPass + 3), this, new Dictionary <string, object> { { validationDriverAheadKey, opponentData.DriverRawName } })); nextCarAheadChangeMessage = currentGameState.Now.Add(TimeSpan.FromSeconds(30)); } } } if (currentGameState.SessionData.HasLeadChanged) { OpponentData leader = currentGameState.getOpponentAtPosition(1, false); if (leader != null) { String name = leader.DriverRawName; if (currentGameState.SessionData.Position > 1 && previousGameState.SessionData.Position > 1 && currentGameState.Now > nextLeadChangeMessage && (SoundCache.hasSuitableTTSVoice || SoundCache.availableDriverNames.Contains(DriverNameHelper.getUsableDriverName(name)))) { Console.WriteLine("Lead change, current leader is " + name + " laps completed = " + currentGameState.SessionData.CompletedLaps); audioPlayer.playMessage(new QueuedMessage("new_leader", MessageContents(leader, folderIsNowLeading), 2, this, new Dictionary <string, object> { { validationNewLeaderKey, name } })); nextLeadChangeMessage = currentGameState.Now.Add(TimeSpan.FromSeconds(30)); } } } if (currentGameState.PitData.LeaderIsPitting && currentGameState.SessionData.SessionPhase != SessionPhase.Countdown && currentGameState.SessionData.SessionPhase != SessionPhase.Formation) { audioPlayer.playMessage(new QueuedMessage("leader_is_pitting", MessageContents(folderTheLeader, currentGameState.PitData.OpponentForLeaderPitting, folderIsPitting), MessageContents(folderLeaderIsPitting), 0, this)); } if (currentGameState.PitData.CarInFrontIsPitting && currentGameState.SessionData.TimeDeltaFront > 3 && currentGameState.SessionData.SessionPhase != SessionPhase.Countdown && currentGameState.SessionData.SessionPhase != SessionPhase.Formation) { audioPlayer.playMessage(new QueuedMessage("car_in_front_is_pitting", MessageContents(currentGameState.PitData.OpponentForCarAheadPitting, folderAheadIsPitting), MessageContents(folderCarAheadIsPitting), 0, this)); } if (currentGameState.PitData.CarBehindIsPitting && currentGameState.SessionData.TimeDeltaBehind > 3 && currentGameState.SessionData.SessionPhase != SessionPhase.Countdown && currentGameState.SessionData.SessionPhase != SessionPhase.Formation) { audioPlayer.playMessage(new QueuedMessage("car_behind_is_pitting", MessageContents(currentGameState.PitData.OpponentForCarBehindPitting, folderBehindIsPitting), MessageContents(folderCarBehindIsPitting), 0, this)); } } }