diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index 337bda3221..8e87610dfb 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -98,11 +98,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double speedDifficultyValue = speed.DifficultyValue();
double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue);
+ double sliderFactor = aimDifficultyValue > 0 ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) : 1;
- var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating);
+ var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating, sliderFactor);
double aimRating = osuRatingCalculator.ComputeAimRating(aimDifficultyValue);
- double aimRatingNoSliders = osuRatingCalculator.ComputeAimRating(aimNoSlidersDifficultyValue);
double speedRating = osuRatingCalculator.ComputeSpeedRating(speedDifficultyValue);
double flashlightRating = 0.0;
@@ -110,8 +110,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (flashlight is not null)
flashlightRating = osuRatingCalculator.ComputeFlashlightRating(flashlight.DifficultyValue());
- double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
-
double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits);
double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap);
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index 7230c52f9c..c076b6cfe6 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate);
else if (score.Mods.Any(m => m is OsuModTraceable))
{
- aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate);
+ aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate, attributes.SliderFactor);
}
aimValue *= accuracy;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs
index 8793582847..4d78db4788 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs
@@ -18,14 +18,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private readonly double approachRate;
private readonly double overallDifficulty;
private readonly double mechanicalDifficultyRating;
+ private readonly double sliderFactor;
- public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating)
+ public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating, double sliderFactor)
{
this.mods = mods;
this.totalHits = totalHits;
this.approachRate = approachRate;
this.overallDifficulty = overallDifficulty;
this.mechanicalDifficultyRating = mechanicalDifficultyRating;
+ this.sliderFactor = sliderFactor;
}
public double ComputeAimRating(double aimDifficultyValue)
@@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (mods.Any(m => m is OsuModHidden))
{
double visibilityFactor = calculateAimVisibilityFactor(approachRate);
- ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor);
+ ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor, sliderFactor);
}
// It is important to consider accuracy difficulty when scaling with accuracy.
@@ -179,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
///
/// Calculates a visibility bonus that is applicable to Hidden and Traceable.
///
- public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1)
+ public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1, double sliderFactor = 1)
{
// NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side.
bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any();
@@ -189,13 +191,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
readingBonus *= visibilityFactor;
+ // We want to reward slideraim on low AR less
+ double sliderVisibilityFactor = Math.Pow(sliderFactor, 3);
+
// For AR up to 0 - reduce reward for very low ARs when object is visible
if (approachRate < 7)
- readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0));
+ readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0)) * sliderVisibilityFactor;
// Starting from AR0 - cap values so they won't grow to infinity
if (approachRate < 0)
- readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate));
+ readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)) * sliderVisibilityFactor;
return readingBonus;
}