diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs index 219f325ae0..596083c8f8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs @@ -18,8 +18,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double overlap_multiplier = 0.8; - public static double CalculateDenstityOf(OsuDifficultyHitObject currObj) + public static double EvaluateDenstityOf(DifficultyHitObject current) { + var currObj = (OsuDifficultyHitObject)current; double density = 0; double densityAnglesNerf = -2; // we have threshold of 2, so 2 or same angles won't be punished @@ -34,8 +35,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double loopDifficulty = currObj.OpacityAt(loopObj.BaseObject.StartTime, false); // Small distances means objects may be cheesed, so it doesn't matter whether they are arranged confusingly. - // For HD: it's not subtracting anything cuz it's multiplied by the aim difficulty anyways. - loopDifficulty *= logistic((loopObj.MinimumJumpDistance - 60) / 10); + loopDifficulty *= logistic((loopObj.MinimumJumpDistance - 30) / 10); // Reduce density bonus for this object if they're too apart in time // Nerf starts on 1500ms and reaches maximum (*=0) on 3000ms @@ -123,14 +123,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators return screenOverlapDifficulty; } - public static double EvaluateDensityDifficultyOf(DifficultyHitObject current) + public static double EvaluateDifficultyOf(DifficultyHitObject current) { if (current.BaseObject is Spinner || current.Index == 0) return 0; var currObj = (OsuDifficultyHitObject)current; - double pastObjectDifficultyInfluence = CalculateDenstityOf(currObj); + double pastObjectDifficultyInfluence = EvaluateDenstityOf(current); double screenOverlapDifficulty = CalculateOverlapDifficultyOf(currObj); double difficulty = Math.Pow(4 * Math.Log(Math.Max(1, pastObjectDifficultyInfluence)), 2.3); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingHighAREvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingHighAREvaluator.cs index c320b4c118..949860aa76 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingHighAREvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingHighAREvaluator.cs @@ -123,28 +123,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // https://www.desmos.com/calculator/hbj7swzlth public static double GetDifficulty(double preempt) { - double value = Math.Pow(3, 3 - 0.01 * preempt); // 1 for 300ms, 0.25 for 400ms, 0.0625 for 500ms + double value = Math.Pow(3.5, 3 - 0.01 * preempt); // 1 for 300ms, 0.25 for 400ms, 0.0625 for 500ms value = softmin(value, 2, 1.7); // use softmin to achieve full-memory cap, 2 times more than AR11 (300ms) return value; } - // This is very accurate on preempt > 300ms, breaking starting somewhere around 120ms - public static double GetPreempt(double difficulty) - { - double fixCoef = difficulty / GetDifficulty(highArCurveReversed(difficulty)); - return highArCurveReversed(difficulty * fixCoef); - } - - // This is an approximation cuz high AR curve is unsolvable - // https://www.desmos.com/calculator/n9vk18bcyh - private static double highArCurveReversed(double value) - { - double helperValue = value / Math.Pow(1 - Math.Pow(1.7, value - 2), 0.45); - double preempt = -(Math.Log(helperValue, 3) - 3) / 0.01; - - return preempt; - } - // We are using mutiply and divide instead of add and subtract, so values won't be negative // https://www.desmos.com/calculator/fv5xerwpd2 private static double softmin(double a, double b, double power = Math.E) => a * b / Math.Log(Math.Pow(power, a) + Math.Pow(power, b), power); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 7b329ce173..c04455f232 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModFlashlight)) baseFlashlightPerformance = Math.Pow(flashlightRating, 2.0) * 25.0; - double baseReadingLowARPerformance = Math.Pow(readingLowARRating, 2.5) * 17.0; + double baseReadingLowARPerformance = ReadingLowAR.DifficultyToPerformance(readingLowARRating); double baseReadingHighARPerformance = OsuStrainSkill.DifficultyToPerformance(readingHighARRating); double baseReadingARPerformance = Math.Pow(Math.Pow(baseReadingLowARPerformance, SUM_POWER) + Math.Pow(baseReadingHighARPerformance, SUM_POWER), 1.0 / SUM_POWER); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 92b9476a13..23045f4331 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -261,7 +261,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(m => m is OsuModTouchDevice)) rawReading = Math.Pow(rawReading, 0.8); - double readingValue = Math.Pow(rawReading, 2.5) * 17.0; + double readingValue = ReadingLowAR.DifficultyToPerformance(rawReading); // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. if (effectiveMissCount > 0) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index 998eed1f1a..353ccc4d80 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -35,6 +35,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// protected virtual double DifficultyMultiplier => DEFAULT_DIFFICULTY_MULTIPLIER; + protected virtual double StrainDecayBase => 0.15; + + protected double StrainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000); + protected OsuStrainSkill(Mod[] mods) : base(mods) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs index 3fbac64215..592db63144 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs @@ -16,18 +16,31 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills public class ReadingLowAR : GraphSkill { private readonly List difficulties = new List(); - private double skillMultiplier => 2; + private double skillMultiplier => 1.3; + private double aimComponentMultiplier => 0.7; + //private double skillMultiplier => 2; public ReadingLowAR(Mod[] mods) : base(mods) { } + private double strainDecayBase => 0.15; + private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); + + private double currentDensityAimStrain = 0; + public override void Process(DifficultyHitObject current) { - double currentDifficulty = ReadingEvaluator.EvaluateDensityDifficultyOf(current) * skillMultiplier; + double densityFactor = Math.Max(0, Math.Pow(ReadingEvaluator.EvaluateDenstityOf(current), 1.5) - 1); + // double density = Math.Max(0, ReadingEvaluator.EvaluateDenstityOf(current)); + currentDensityAimStrain *= strainDecay(current.DeltaTime); + currentDensityAimStrain += densityFactor * AimEvaluator.EvaluateDifficultyOf(current, false) * aimComponentMultiplier; - difficulties.Add(currentDifficulty); + double densityReadingDifficulty = ReadingEvaluator.EvaluateDifficultyOf(current); + double totalDensityDifficulty = (currentDensityAimStrain + densityReadingDifficulty) * skillMultiplier; + + difficulties.Add(totalDensityDifficulty); if (current.Index == 0) CurrentSectionEnd = Math.Ceiling(current.StartTime / SectionLength) * SectionLength; @@ -39,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills CurrentSectionEnd += SectionLength; } - CurrentSectionPeak = Math.Max(currentDifficulty, CurrentSectionPeak); + CurrentSectionPeak = Math.Max(totalDensityDifficulty, CurrentSectionPeak); } private double reducedNoteCount => 5; @@ -71,6 +84,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return difficulty; } + + public static double DifficultyToPerformance(double difficulty) => Math.Pow(difficulty, 3) * 10.0; } public class ReadingHidden : OsuStrainSkill @@ -82,15 +97,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double currentStrain; private double skillMultiplier => 5; - private double strainDecayBase => 0.15; - private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); - - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * StrainDecay(time - current.Previous(0).StartTime); protected override double StrainValueAt(DifficultyHitObject current) { - currentStrain *= strainDecay(current.DeltaTime); + currentStrain *= StrainDecay(current.DeltaTime); // We're not using slider aim because we assuming that HD doesn't makes sliders harder (what is not true, but we will ignore this for now) double hiddenDifficulty = AimEvaluator.EvaluateDifficultyOf(current, false); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/ReadingHighAR.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/ReadingHighAR.cs index 6e3049aec6..aa5c8d78fa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/ReadingHighAR.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/ReadingHighAR.cs @@ -29,12 +29,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private readonly List difficulties = new List(); private int objectsCount = 0; - private double preempt = -1; public override void Process(DifficultyHitObject current) { - if (preempt < 0) preempt = ((OsuDifficultyHitObject)current).Preempt; - aimComponent.Process(current); speedComponent.Process(current); @@ -97,17 +94,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private bool adjustHighAR; private double currentStrain; - private double skillMultiplier => 17.8; - private double defaultValueMultiplier => 30; - private double strainDecayBase => 0.15; + private double skillMultiplier => 17; + private double defaultValueMultiplier => 50; - private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); - - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * StrainDecay(time - current.Previous(0).StartTime); protected override double StrainValueAt(DifficultyHitObject current) { - currentStrain *= strainDecay(current.DeltaTime); + currentStrain *= StrainDecay(current.DeltaTime); double aimDifficulty = AimEvaluator.EvaluateDifficultyOf(current, true); double readingDifficulty = ReadingHighAREvaluator.EvaluateDifficultyOf(current, adjustHighAR); @@ -122,8 +116,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills public class HighARSpeedComponent : OsuStrainSkill { - private double skillMultiplier => 850; - private double strainDecayBase => 0.3; + private double skillMultiplier => 820; + protected override double StrainDecayBase => 0.3; private double currentStrain; private double currentRhythm; @@ -133,15 +127,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { } - private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); - - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => (currentStrain * currentRhythm) * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => (currentStrain * currentRhythm) * StrainDecay(time - current.Previous(0).StartTime); protected override double StrainValueAt(DifficultyHitObject current) { OsuDifficultyHitObject currODHO = (OsuDifficultyHitObject)current; - currentStrain *= strainDecay(currODHO.StrainTime); + currentStrain *= StrainDecay(currODHO.StrainTime); double speedDifficulty = SpeedEvaluator.EvaluateDifficultyOf(current) * skillMultiplier; speedDifficulty *= Math.Pow(ReadingHighAREvaluator.EvaluateDifficultyOf(current, false), 2); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index edc3302b09..9ada2b3c2c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills public class Speed : OsuStrainSkill { private double skillMultiplier => 1375; - private double strainDecayBase => 0.3; + protected override double StrainDecayBase => 0.3; private double currentStrain; private double currentRhythm; @@ -32,15 +32,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { } - private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); - - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => (currentStrain * currentRhythm) * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => (currentStrain * currentRhythm) * StrainDecay(time - current.Previous(0).StartTime); protected override double StrainValueAt(DifficultyHitObject current) { OsuDifficultyHitObject currODHO = (OsuDifficultyHitObject)current; - currentStrain *= strainDecay(currODHO.StrainTime); + currentStrain *= StrainDecay(currODHO.StrainTime); currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current) * skillMultiplier; currentRhythm = currODHO.RhythmDifficulty;