diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index bd4c0f2ad5..1f8b66edb7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public double AimStrain { get; set; } public double SpeedStrain { get; set; } + public double SpeedNoteCount { get; set; } public double FlashlightRating { get; set; } public double ApproachRate { get; set; } public double OverallDifficulty { get; set; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 790aa0eb7d..4160da9d5e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -36,6 +36,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double flashlightRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier; + double speedNotes = (skills[1] as Speed).RelevantNoteCount(); if (mods.Any(h => h is OsuModRelax)) speedRating = 0.0; @@ -72,6 +73,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty Mods = mods, AimStrain = aimRating, SpeedStrain = speedRating, + SpeedNoteCount = speedNotes, FlashlightRating = flashlightRating, ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5, OverallDifficulty = (80 - hitWindowGreat) / 6, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 4e4dbc02a1..140c49393b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -168,8 +168,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty speedValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate); } + // Calculate accuracy assuming the worst case scenario + double relevantTotalDiff = totalHits - Attributes.SpeedNoteCount; + double relevantCountGreat = Math.Max(0, countGreat - relevantTotalDiff); + double relevantCountOk = Math.Max(0, countOk - Math.Max(0, relevantTotalDiff - countGreat)); + double relevantCountMeh = Math.Max(0, countMeh - Math.Max(0, relevantTotalDiff - countGreat - countOk)); + double relevantAccuracy = (relevantCountGreat * 6.0 + relevantCountOk * 2.0 + relevantCountMeh) / (Attributes.SpeedNoteCount * 6.0); + // Scale the speed value with accuracy and OD. - speedValue *= (0.95 + Math.Pow(Attributes.OverallDifficulty, 2) / 750) * Math.Pow(accuracy, (14.5 - Math.Max(Attributes.OverallDifficulty, 8)) / 2); + speedValue *= (0.95 + Math.Pow(Attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(Attributes.OverallDifficulty, 8)) / 2); // Scale the speed value with # of 50s to punish doubletapping. speedValue *= Math.Pow(0.98, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index cae6b8e01c..f8c1042a10 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -7,6 +7,8 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; using osu.Framework.Utils; +using System.Collections.Generic; +using System.Linq; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -33,6 +35,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private readonly double greatWindow; + private List objectStrains = new List(); + public Speed(Mod[] mods, double hitWindowGreat) : base(mods) { @@ -170,7 +174,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills currentRhythm = calculateRhythmBonus(current); - return currentStrain * currentRhythm; + double totalStrain = currentStrain * currentRhythm; + + objectStrains.Add(totalStrain); + + return totalStrain; + } + + public double RelevantNoteCount() + { + double maxStrain = objectStrains.Max(); + return objectStrains.Aggregate((total, next) => total + (1.0 / (1.0 + Math.Pow(Math.E, -(next/maxStrain * 12.0 - 6.0))))); } } }