diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs
index a12bdf7f20..aa94572cb4 100644
--- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs
@@ -18,7 +18,17 @@ namespace osu.Game.Rulesets.Osu.Scoring
private readonly int beatmapMaxCombo;
private Mod[] mods;
+
+ ///
+ /// Approach rate adjusted by mods.
+ ///
private double realApproachRate;
+
+ ///
+ /// Overall difficulty adjusted by mods.
+ ///
+ private double realOverallDifficulty;
+
private double accuracy;
private int scoreMaxCombo;
private int count300;
@@ -58,9 +68,13 @@ namespace osu.Game.Rulesets.Osu.Scoring
ar = Math.Min(10, ar * 1.4);
if (mods.Any(m => m is OsuModEasy))
ar = Math.Max(0, ar / 2);
- double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450);
- realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
+ double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate;
+ double hitWindow300 = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
+
+ realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
+ realOverallDifficulty = (80 - 0.5 - hitWindow300) / 6;
+
// Custom multipliers for NoFail and SpunOut.
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
@@ -133,7 +147,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
// Scale the aim value with accuracy _slightly_
aimValue *= 0.5f + accuracy / 2.0f;
// It is important to also consider accuracy difficulty when doing that
- aimValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
+ aimValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500;
return aimValue;
}
@@ -159,7 +173,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
// Scale the speed value with accuracy _slightly_
speedValue *= 0.5f + accuracy / 2.0f;
// It is important to also consider accuracy difficulty when doing that
- speedValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
+ speedValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500;
return speedValue;
}
@@ -181,7 +195,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
// Lots of arbitrary values from testing.
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
- double accuracyValue = Math.Pow(1.52163f, Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
+ double accuracyValue = Math.Pow(1.52163f, realOverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs
index 37155c09cd..5cac9ed923 100644
--- a/osu.Game/Beatmaps/DifficultyCalculator.cs
+++ b/osu.Game/Beatmaps/DifficultyCalculator.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps
protected readonly IBeatmap Beatmap;
protected readonly Mod[] Mods;
- protected double TimeRate = 1;
+ protected double TimeRate { get; private set; } = 1;
protected DifficultyCalculator(IBeatmap beatmap, Mod[] mods = null)
{
diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs
index 5b8f5f0d0f..b23e06e15c 100644
--- a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs
+++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs
@@ -2,7 +2,11 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Extensions.IEnumerableExtensions;
+using osu.Framework.Timing;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Scoring
{
@@ -14,6 +18,8 @@ namespace osu.Game.Rulesets.Scoring
protected readonly IBeatmap Beatmap;
protected readonly Score Score;
+ protected double TimeRate { get; private set; } = 1;
+
protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
{
Score = score;
@@ -22,6 +28,15 @@ namespace osu.Game.Rulesets.Scoring
var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods);
diffCalc.Calculate(attributes);
+
+ ApplyMods(score.Mods);
+ }
+
+ protected virtual void ApplyMods(Mod[] mods)
+ {
+ var clock = new StopwatchClock();
+ mods.OfType().ForEach(m => m.ApplyToClock(clock));
+ TimeRate = clock.Rate;
}
public abstract double Calculate(Dictionary categoryDifficulty = null);