diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ReadingEvaluator.cs index a6a1513842..2877f8d19e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ReadingEvaluator.cs @@ -31,13 +31,28 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The reading difficulty value for the given hit object. public static double EvaluateDifficultyOf(TaikoDifficultyHitObject noteObject) { - double effectiveBPM = noteObject.EffectiveBPM; + double effectiveBPM = Math.Max(1.0, noteObject.EffectiveBPM); + // Expected deltatime is the deltatime this note would need + // to be spaced equally to a base SV 1/4 note + double expectedDeltaTime = 21000.0 / effectiveBPM; + var midVelocity = new VelocityRange(360, 480); var highVelocity = new VelocityRange(480, 640); - var midVelocity = new VelocityRange(360, 480); + + double midVelDifficulty = 0.5 * DifficultyCalculationUtils.Logistic(effectiveBPM, midVelocity.Center, 1.0 / (midVelocity.Range / 10)); - return 1.0 * DifficultyCalculationUtils.Logistic(effectiveBPM, highVelocity.Center, 1.0 / (highVelocity.Range / 10)) - + 0.5 * DifficultyCalculationUtils.Logistic(effectiveBPM, midVelocity.Center, 1.0 / (midVelocity.Range / 10)); + // Density refers to an object's deltatime relative to its expected deltatime + double density = expectedDeltaTime / Math.Max(1.0, noteObject.DeltaTime); + + // Dense notes are penalised at high velocities + // https://www.desmos.com/calculator/u63f3ntdsi + double densityPenalty = DifficultyCalculationUtils.Logistic(density, 0.925, 15); + + double midpointOffset = highVelocity.Center + 8 * densityPenalty; + double multiplier = (1.0 + 0.5 * densityPenalty) / (highVelocity.Range / 10); + double highVelDifficulty = (1.0 - 0.33 * densityPenalty) * DifficultyCalculationUtils.Logistic(effectiveBPM, midpointOffset, multiplier); + + return midVelDifficulty + highVelDifficulty; } } }