override protected void triggerInternal(GameStateData previousGameState, GameStateData currentGameState) { // if we've crashed hard and are waiting for the player to say they're OK, don't process anything else in this event: if (waitingForDriverIsOKResponse) { if (timeWhenAskedIfDriverIsOK.Add(TimeSpan.FromSeconds(8)) < currentGameState.Now) { timeWhenAskedIfDriverIsOK = currentGameState.Now; if (driverIsOKRequestCount == 1) { audioPlayer.playMessageImmediately(new QueuedMessage(folderAreYouOKSecondTry, 0, type: SoundType.CRITICAL_MESSAGE, priority: 15)); driverIsOKRequestCount = 2; } else if (driverIsOKRequestCount == 2) { // no response after 3 requests, he's dead, jim. audioPlayer.playMessageImmediately(new QueuedMessage(folderAreYouOKThirdTry, 0, type: SoundType.CRITICAL_MESSAGE, priority: 15)); cancelWaitingForDriverIsOK(DriverOKResponseType.NONE); } } return; } if (waitingAfterPotentiallyDangerousAcceleration) { if (currentGameState.PositionAndMotionData.CarSpeed > speedAfterPotentiallyDangerousAcceleration + 5) { Console.WriteLine("Car has accelerated, cancelling wait for crash message"); waitingAfterPotentiallyDangerousAcceleration = false; timeToRecheckAfterPotentiallyDangerousAcceleration = DateTime.MaxValue; } else if (timeToRecheckAfterPotentiallyDangerousAcceleration > currentGameState.Now) { waitingAfterPotentiallyDangerousAcceleration = false; timeToRecheckAfterPotentiallyDangerousAcceleration = DateTime.MaxValue; timeOfDangerousAcceleration = currentGameState.Now; // special case for iRacing: no damage data so we can't hang this off 'destroyed' components triggerCheckDriverIsOKForIRacingAfter = currentGameState.Now.Add(TimeSpan.FromSeconds(2)); } else { // suspend the rest of this event return; } } // need to be careful with interval here. // Disable these for iRacing, which has some spikes in car speed data that trigger false positives if (CrewChief.gameDefinition.gameEnum != GameEnum.IRACING && enableCrashMessages && !playedAreYouOKInThisSession && !currentGameState.PitData.InPitlane && currentGameState.PositionAndMotionData.CarSpeed > 0.001) { if (previousGameState != null) { double interval = (currentGameState.Now - previousGameState.Now).TotalSeconds; if (interval > 0.01) { double calculatedAcceleration = Math.Abs(currentGameState.PositionAndMotionData.CarSpeed - previousGameState.PositionAndMotionData.CarSpeed) / interval; /*Console.WriteLine("Interval = " + interval + * " Current speed = " + currentGameState.PositionAndMotionData.CarSpeed + * " previous speed = " + previousGameState.PositionAndMotionData.CarSpeed + " acceleration = " + calculatedAcceleration / 9.8f + "g");*/ // if we're subject to > 40G (400m/s2), this is considered dangerous. If we've stopped (or nearly stopped) immediately // after the impact, assume it's a bad 'un. If we're still moving after the impact, track the speed for 3 seconds and // if it doesn't increase in that time, we can assume it's a bad 'un if (calculatedAcceleration > 400) { Console.WriteLine("Massive impact. Current speed = " + currentGameState.PositionAndMotionData.CarSpeed.ToString("0.000") + " previous speed = " + previousGameState.PositionAndMotionData.CarSpeed.ToString("0.000") + " acceleration = " + (calculatedAcceleration / 9.8f).ToString("0.0000") + "g"); if (currentGameState.PositionAndMotionData.CarSpeed < 3) { timeOfDangerousAcceleration = currentGameState.Now; // special case for iRacing: no damage data so we can't hang this off 'destroyed' components triggerCheckDriverIsOKForIRacingAfter = currentGameState.Now.Add(TimeSpan.FromSeconds(4)); } else { // massive acceleration but we're still moving timeToRecheckAfterPotentiallyDangerousAcceleration = currentGameState.Now.Add(TimeSpan.FromSeconds(3)); waitingAfterPotentiallyDangerousAcceleration = true; speedAfterPotentiallyDangerousAcceleration = currentGameState.PositionAndMotionData.CarSpeed; } } } } } Boolean orientationSamplesFull = orientationSamples.Count > orientationSamplesCount; if (orientationSamplesFull) { orientationSamples.RemoveFirst(); } orientationSamples.AddLast(currentGameState.PositionAndMotionData.Orientation); // don't check for rolling if we've just had a dangerous acceleration as we don't want both messages to trigger if (enableCrashMessages && currentGameState.Now > nextOrientationCheckDue && orientationSamplesFull && currentGameState.Now.Subtract(timeOfDangerousAcceleration) > TimeSpan.FromSeconds(10)) { nextOrientationCheckDue = currentGameState.Now.Add(orientationCheckEvery); checkOrientation(currentGameState.PositionAndMotionData.CarSpeed); } if (currentGameState.CarDamageData.DamageEnabled && currentGameState.SessionData.SessionRunningTime > 10 && currentGameState.Now > nextPunctureCheck) { nextPunctureCheck = currentGameState.Now + timeToWaitForDamageToSettle; CornerData.Corners puncture = getPuncture(currentGameState.TyreData); if (puncture != lastReportedPunctureCorner) { lastReportedPunctureCorner = puncture; switch (puncture) { case CornerData.Corners.FRONT_LEFT: audioPlayer.playMessage(new QueuedMessage(folderLeftFrontPuncture, 0, abstractEvent: this, priority: 10)); break; case CornerData.Corners.FRONT_RIGHT: audioPlayer.playMessage(new QueuedMessage(folderRightFrontPuncture, 0, abstractEvent: this, priority: 10)); break; case CornerData.Corners.REAR_LEFT: audioPlayer.playMessage(new QueuedMessage(folderLeftRearPuncture, 0, abstractEvent: this, priority: 10)); break; case CornerData.Corners.REAR_RIGHT: audioPlayer.playMessage(new QueuedMessage(folderRightRearPuncture, 0, abstractEvent: this, priority: 10)); break; } } } if (currentGameState.CarDamageData.DamageEnabled) { aeroDamage = currentGameState.CarDamageData.OverallAeroDamage; trannyDamage = currentGameState.CarDamageData.OverallTransmissionDamage; engineDamage = currentGameState.CarDamageData.OverallEngineDamage; if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.DESTROYED)) { maxBrakeDamage = DamageLevel.DESTROYED; componentDestroyed = Component.BRAKES; } else if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.MAJOR)) { maxBrakeDamage = DamageLevel.MAJOR; } else if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.MINOR)) { maxBrakeDamage = DamageLevel.MINOR; } else if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.TRIVIAL)) { maxBrakeDamage = DamageLevel.TRIVIAL; } else { maxBrakeDamage = DamageLevel.NONE; } if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.DESTROYED)) { maxSuspensionDamage = DamageLevel.DESTROYED; componentDestroyed = Component.SUSPENSION; } else if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.MAJOR)) { maxSuspensionDamage = DamageLevel.MAJOR; } else if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.MINOR)) { maxSuspensionDamage = DamageLevel.MINOR; } else if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.TRIVIAL)) { maxSuspensionDamage = DamageLevel.TRIVIAL; } else { maxSuspensionDamage = DamageLevel.NONE; } isMissingWheel = !currentGameState.PitData.InPitlane && (!currentGameState.TyreData.LeftFrontAttached || !currentGameState.TyreData.RightFrontAttached || !currentGameState.TyreData.LeftRearAttached || !currentGameState.TyreData.RightRearAttached); if (engineDamage < getLastReportedDamageLevel(Component.ENGINE)) { resetReportedDamage(Component.ENGINE, engineDamage); } if (trannyDamage < getLastReportedDamageLevel(Component.TRANNY)) { resetReportedDamage(Component.TRANNY, trannyDamage); } if (maxSuspensionDamage < getLastReportedDamageLevel(Component.SUSPENSION)) { resetReportedDamage(Component.SUSPENSION, maxSuspensionDamage); } if (maxBrakeDamage < getLastReportedDamageLevel(Component.BRAKES)) { resetReportedDamage(Component.BRAKES, maxBrakeDamage); } if (aeroDamage < getLastReportedDamageLevel(Component.AERO)) { resetReportedDamage(Component.AERO, aeroDamage); } minDamageToReport = (DamageLevel)Math.Max((int)engineDamage, Math.Max((int)trannyDamage, Math.Max((int)maxSuspensionDamage, Math.Max((int)maxBrakeDamage, (int)aeroDamage)))); Tuple <Component, DamageLevel> worstUnreportedDamage = getWorstUnreportedDamage(); if (worstUnreportedDamage != null && worstUnreportedDamage.Item2 >= minDamageToReport) { if (damageToReportNext == null || worstUnreportedDamage.Item1 != damageToReportNext.Item1 || worstUnreportedDamage.Item2 != damageToReportNext.Item2) { timeWhenDamageLastChanged = currentGameState.Now; damageToReportNext = worstUnreportedDamage; } else if (timeWhenDamageLastChanged.Add(timeToWaitForDamageToSettle) < currentGameState.Now) { Console.WriteLine("Reporting ..."); Console.WriteLine(damageToReportNext.Item1 + ", " + damageToReportNext.Item2); // put *all* the damage levels in the 'reported' set, even though we haven't actually reported them. // This ensure we only ever play the worst damage on the car when damage has just increased // Only do this if the component damage is *less* than the one we just reported if (Component.AERO == damageToReportNext.Item1 || aeroDamage < damageToReportNext.Item2) { addReportedDamage(Component.AERO, aeroDamage); } if (Component.BRAKES == damageToReportNext.Item1 || maxBrakeDamage < damageToReportNext.Item2) { addReportedDamage(Component.BRAKES, maxBrakeDamage); } if (Component.ENGINE == damageToReportNext.Item1 || engineDamage < damageToReportNext.Item2) { addReportedDamage(Component.ENGINE, engineDamage); } if (Component.SUSPENSION == damageToReportNext.Item1 || maxSuspensionDamage < damageToReportNext.Item2) { addReportedDamage(Component.SUSPENSION, maxSuspensionDamage); } if (Component.TRANNY == damageToReportNext.Item1 || trannyDamage < damageToReportNext.Item2) { addReportedDamage(Component.TRANNY, trannyDamage); } if (enableDamageMessages) { playDamageToReport(currentGameState.SessionData.SessionType == SessionType.Race && currentGameState.SessionData.NumCarsOverall > 2, currentGameState.Now); } } } } else if (CrewChief.gameDefinition.gameEnum == GameEnum.IRACING && currentGameState.Now > triggerCheckDriverIsOKForIRacingAfter) { triggerCheckDriverIsOKForIRacingAfter = DateTime.MaxValue; checkIfDriverIsOK(currentGameState.Now); } }
override protected void triggerInternal(GameStateData previousGameState, GameStateData currentGameState) { if (currentGameState.CarDamageData.DamageEnabled && currentGameState.SessionData.SessionRunningTime > 10 && currentGameState.Now > nextPunctureCheck) { nextPunctureCheck = currentGameState.Now + timeToWaitForDamageToSettle; CornerData.Corners puncture = getPuncture(currentGameState.TyreData); if (puncture != lastReportedPunctureCorner) { lastReportedPunctureCorner = puncture; switch (puncture) { case CornerData.Corners.FRONT_LEFT: audioPlayer.playMessage(new QueuedMessage(folderLeftFrontPuncture, 0, this)); break; case CornerData.Corners.FRONT_RIGHT: audioPlayer.playMessage(new QueuedMessage(folderRightFrontPuncture, 0, this)); break; case CornerData.Corners.REAR_LEFT: audioPlayer.playMessage(new QueuedMessage(folderLeftRearPuncture, 0, this)); break; case CornerData.Corners.REAR_RIGHT: audioPlayer.playMessage(new QueuedMessage(folderRightRearPuncture, 0, this)); break; } } } if (currentGameState.CarDamageData.DamageEnabled) { aeroDamage = currentGameState.CarDamageData.OverallAeroDamage; trannyDamage = currentGameState.CarDamageData.OverallTransmissionDamage; engineDamage = currentGameState.CarDamageData.OverallEngineDamage; if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.DESTROYED)) { maxBrakeDamage = DamageLevel.DESTROYED; } else if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.MAJOR)) { maxBrakeDamage = DamageLevel.MAJOR; } else if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.MINOR)) { maxBrakeDamage = DamageLevel.MINOR; } else if (currentGameState.CarDamageData.BrakeDamageStatus.hasValueAtLevel(DamageLevel.TRIVIAL)) { maxBrakeDamage = DamageLevel.TRIVIAL; } if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.DESTROYED)) { maxSuspensionDamage = DamageLevel.DESTROYED; } else if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.MAJOR)) { maxSuspensionDamage = DamageLevel.MAJOR; } else if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.MINOR)) { maxSuspensionDamage = DamageLevel.MINOR; } else if (currentGameState.CarDamageData.SuspensionDamageStatus.hasValueAtLevel(DamageLevel.TRIVIAL)) { maxSuspensionDamage = DamageLevel.TRIVIAL; } isMissingWheel = !currentGameState.PitData.InPitlane && (!currentGameState.TyreData.LeftFrontAttached || !currentGameState.TyreData.RightFrontAttached || !currentGameState.TyreData.LeftRearAttached || !currentGameState.TyreData.RightRearAttached); if (engineDamage < getLastReportedDamageLevel(Component.ENGINE)) { resetReportedDamage(Component.ENGINE, engineDamage); } if (trannyDamage < getLastReportedDamageLevel(Component.TRANNY)) { resetReportedDamage(Component.TRANNY, trannyDamage); } if (maxSuspensionDamage < getLastReportedDamageLevel(Component.SUSPENSION)) { resetReportedDamage(Component.SUSPENSION, maxSuspensionDamage); } if (maxBrakeDamage < getLastReportedDamageLevel(Component.BRAKES)) { resetReportedDamage(Component.BRAKES, maxBrakeDamage); } if (aeroDamage < getLastReportedDamageLevel(Component.AERO)) { resetReportedDamage(Component.AERO, aeroDamage); } minDamageToReport = (DamageLevel)Math.Max((int)engineDamage, Math.Max((int)trannyDamage, Math.Max((int)maxSuspensionDamage, Math.Max((int)maxBrakeDamage, (int)aeroDamage)))); Tuple <Component, DamageLevel> worstUnreportedDamage = getWorstUnreportedDamage(); if (worstUnreportedDamage != null && worstUnreportedDamage.Item2 >= minDamageToReport) { if (damageToReportNext == null || worstUnreportedDamage.Item1 != damageToReportNext.Item1 || worstUnreportedDamage.Item2 != damageToReportNext.Item2) { timeWhenDamageLastChanged = currentGameState.Now; damageToReportNext = worstUnreportedDamage; } else if (timeWhenDamageLastChanged.Add(timeToWaitForDamageToSettle) < currentGameState.Now) { Console.WriteLine("reporting ..."); Console.WriteLine(damageToReportNext.Item1 + ", " + damageToReportNext.Item2); // put *all* the damage levels in the 'reported' set, even though we haven't actually reported them. // This ensure we only ever play the worst damage on the car when damage has just increased // Only do this if the component damage is *less* than the one we just reported if (Component.AERO == damageToReportNext.Item1 || aeroDamage < damageToReportNext.Item2) { addReportedDamage(Component.AERO, aeroDamage); } if (Component.BRAKES == damageToReportNext.Item1 || maxBrakeDamage < damageToReportNext.Item2) { addReportedDamage(Component.BRAKES, maxBrakeDamage); } if (Component.ENGINE == damageToReportNext.Item1 || engineDamage < damageToReportNext.Item2) { addReportedDamage(Component.ENGINE, engineDamage); } if (Component.SUSPENSION == damageToReportNext.Item1 || maxSuspensionDamage < damageToReportNext.Item2) { addReportedDamage(Component.SUSPENSION, maxSuspensionDamage); } if (Component.TRANNY == damageToReportNext.Item1 || trannyDamage < damageToReportNext.Item2) { addReportedDamage(Component.TRANNY, trannyDamage); } if (enableDamageMessages) { playDamageToReport(); } } } } }