diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 75d6786d95..b83e504a7a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -32,8 +32,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (beatmap.HitObjects.Count == 0) return new OsuDifficultyAttributes { Mods = mods, Skills = skills }; - double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; - double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; + double aimRating = Math.Sqrt((skills[0] as OsuSkill).OsuDifficultyValue()) * difficulty_multiplier; + double speedRating = Math.Sqrt((skills[1] as OsuSkill).OsuDifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; HitWindows hitWindows = new OsuHitWindows(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 44a9dd2f1f..90ded2b837 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -106,22 +106,25 @@ namespace osu.Game.Rulesets.Osu.Difficulty else if (Attributes.ApproachRate < 8.0) approachRateFactor += 0.01 * (8.0 - Attributes.ApproachRate); - aimValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0)); + approachRateFactor = 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0)); // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. if (mods.Any(h => h is OsuModHidden)) aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate); + double flashlightBonus = 1.0; if (mods.Any(h => h is OsuModFlashlight)) { // Apply object-based bonus for flashlight. - aimValue *= 1.0 + 0.35 * Math.Min(1.0, totalHits / 200.0) + + flashlightBonus = 1.0 + 0.35 * Math.Min(1.0, totalHits / 200.0) + (totalHits > 200 ? 0.3 * Math.Min(1.0, (totalHits - 200) / 300.0) + (totalHits > 500 ? (totalHits - 500) / 1200.0 : 0.0) : 0.0); } + aimValue *= Math.Max(flashlightBonus, approachRateFactor); + // Scale the aim value with accuracy _slightly_ aimValue *= 0.5 + accuracy / 2.0; // It is important to also consider accuracy difficulty when doing that diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index cb819ec090..b7bb10a87e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : StrainSkill + public class Aim : OsuSkill { private const double angle_bonus_begin = Math.PI / 3; private const double timing_threshold = 107; @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills Math.Max(osuPrevious.JumpDistance - scale, 0) * Math.Pow(Math.Sin(osuCurrent.Angle.Value - angle_bonus_begin), 2) * Math.Max(osuCurrent.JumpDistance - scale, 0)); - result = 1.5 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime); + result = 1.35 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuSkill.cs new file mode 100644 index 0000000000..d113f7135f --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuSkill.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Mods; +using System.Linq; + +namespace osu.Game.Rulesets.Osu.Difficulty.Skills +{ + public abstract class OsuSkill : StrainSkill + { + public OsuSkill(Mod[] mods) : base(mods) + { + } + + public double OsuDifficultyValue() + { + double difficulty = 0; + double weight = 1; + + double strainMultiplier; + List strains = GetCurrentStrainPeaks().OrderByDescending(d => d).ToList(); + + double baseLine = 0.6; + + for (int i = 0; i <= 9; i++) + { + strainMultiplier = baseLine + Math.Log10(i+1) * (1.0 - baseLine); + strains[i] = strains[i] * strainMultiplier; + } + + // Difficulty is the weighted sum of the highest strains from every section. + // We're sorting from highest to lowest strain. + foreach (double strain in strains.OrderByDescending(d => d)) + { + difficulty += strain * weight; + weight *= DecayWeight; + } + + return difficulty * 1.06; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index fbac080fc6..975a633bad 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit. /// - public class Speed : StrainSkill + public class Speed : OsuSkill { private const double single_spacing_threshold = 125;