From c75373d7fa57f7f1fd33fe47435ef28b6ccedf91 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 01:45:23 +0300 Subject: [PATCH 01/23] simple implementation --- .../Difficulty/Evaluators/AimEvaluator.cs | 40 ++++++++++++++++++- .../Preprocessing/OsuDifficultyHitObject.cs | 6 ++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 594244885555..77087f1aebf5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; @@ -75,6 +76,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; + // Console.Out.WriteLine(getConstantAngleNerfFactor(osuCurrObj)); + // Console.Out.WriteLine(osuCurrObj.VectorAngle.Value); + // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); @@ -83,7 +87,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with acuteAngleBonus = calcAcuteAngleBonus(currAngle); // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), getConstantAngleNerfFactor(osuCurrObj)))); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * @@ -94,7 +98,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); + wideAngleBonus *= 1 - Math.Max(1, Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 5 - getConstantAngleNerfFactor(osuCurrObj)))); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -165,6 +169,38 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with return aimStrain; } + private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) + { + const double time_limit = 1000; // 2 seconds + const double time_limit_low = 200; + + double constantAngleCount = 0; + int index = 0; + double currentTimeGap = 0; + + while (currentTimeGap < time_limit) + { + var loopObj = (OsuDifficultyHitObject)current.Previous(index); + + if (loopObj.IsNull()) + break; + + // Account less for objects that are close to the time limit. + double longIntervalFactor = Math.Clamp(1 - (loopObj.StrainTime - time_limit_low) / (time_limit - time_limit_low), 0, 1); + + if (loopObj.VectorAngle.IsNotNull() && current.VectorAngle.IsNotNull()) + { + double angleDifference = Math.Abs(current.VectorAngle.Value - loopObj.VectorAngle.Value); + constantAngleCount += Math.Cos(4 * Math.Min(Math.PI / 8, angleDifference)) / 2 * longIntervalFactor; + } + + currentTimeGap = current.StartTime - loopObj.StartTime; + index++; + } + + return 1 / Math.Clamp(1.5 / constantAngleCount, 0.2, 1); + } + private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 8ad72daeb59c..c81030a4377c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -110,6 +110,8 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public double SmallCircleBonus { get; private set; } + public double? VectorAngle { get; private set; } + private readonly OsuDifficultyHitObject? lastLastDifficultyObject; private readonly OsuDifficultyHitObject? lastDifficultyObject; @@ -237,12 +239,14 @@ private void setDistances(double clockRate) MinimumJumpDistance = Math.Max(0, Math.Min(LazyJumpDistance - (maximum_slider_radius - assumed_slider_radius), tailJumpDistance - maximum_slider_radius)); } + Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition; + VectorAngle = Math.Atan2(Math.Abs(v2.Y), Math.Abs(v2.X)); + if (lastLastDifficultyObject != null && lastLastDifficultyObject.BaseObject is not Spinner) { Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastDifficultyObject); Vector2 v1 = lastLastCursorPosition - LastObject.StackedPosition; - Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition; float dot = Vector2.Dot(v1, v2); float det = v1.X * v2.Y - v1.Y * v2.X; From 7e9ce3571217717e759be5e8d1a0664470d1b90f Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 02:13:45 +0300 Subject: [PATCH 02/23] fix wide being worth nothing --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 77087f1aebf5..25d88fbaba49 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -98,7 +98,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Max(1, Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 5 - getConstantAngleNerfFactor(osuCurrObj)))); + wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 6 - getConstantAngleNerfFactor(osuCurrObj))); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -198,7 +198,7 @@ private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) index++; } - return 1 / Math.Clamp(1.5 / constantAngleCount, 0.2, 1); + return 1 / Math.Clamp(Math.Pow(1.5 / constantAngleCount, 2), 0.2, 1); } private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); From cfbc9e2cdd344644bfbff4aad797da92483e581f Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 04:12:43 +0300 Subject: [PATCH 03/23] realize im stupid and have shit backwards --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 25d88fbaba49..598608b2c451 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -98,7 +98,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 6 - getConstantAngleNerfFactor(osuCurrObj))); + wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), getConstantAngleNerfFactor(osuCurrObj))); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -198,7 +198,7 @@ private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) index++; } - return 1 / Math.Clamp(Math.Pow(1.5 / constantAngleCount, 2), 0.2, 1); + return 1 / Math.Clamp(Math.Pow(1 / constantAngleCount, 2), 0.2, 1); } private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); From da069c6b95923b26c30945b0638f2a0248bb9acc Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 04:16:21 +0300 Subject: [PATCH 04/23] rename method --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 598608b2c451..7b7ecdf9b316 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -87,7 +87,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with acuteAngleBonus = calcAcuteAngleBonus(currAngle); // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), getConstantAngleNerfFactor(osuCurrObj)))); + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), angleVectorRepetition(osuCurrObj)))); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * @@ -98,7 +98,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), getConstantAngleNerfFactor(osuCurrObj))); + wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), angleVectorRepetition(osuCurrObj))); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -169,7 +169,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with return aimStrain; } - private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current) + private static double angleVectorRepetition(OsuDifficultyHitObject current) { const double time_limit = 1000; // 2 seconds const double time_limit_low = 200; From 4debd0bc9b379192b557bdc6dbc3b781a90bd1de Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 04:23:05 +0300 Subject: [PATCH 05/23] 4am brain malfunctions --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 7b7ecdf9b316..aa4ef64d8f92 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -76,7 +76,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; - // Console.Out.WriteLine(getConstantAngleNerfFactor(osuCurrObj)); + // Console.Out.WriteLine(angleVectorRepetition(osuCurrObj)); // Console.Out.WriteLine(osuCurrObj.VectorAngle.Value); // Rewarding angles, take the smaller velocity as base. @@ -87,7 +87,9 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with acuteAngleBonus = calcAcuteAngleBonus(currAngle); // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), angleVectorRepetition(osuCurrObj)))); + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 6 - angleVectorRepetition(osuCurrObj)))); + + // Console.Out.WriteLine(1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3)) + ", " + (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 6 - angleVectorRepetition(osuCurrObj))))); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * From fc6ab4f9b9355b19afdf8486679a2d02ed98e3c0 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 14:55:31 +0300 Subject: [PATCH 06/23] remove wide angle considerations and new acute repetition nerf --- .../Difficulty/Evaluators/AimEvaluator.cs | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index aa4ef64d8f92..1c826a3cb0a6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -82,25 +82,22 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same. - { - acuteAngleBonus = calcAcuteAngleBonus(currAngle); + acuteAngleBonus = calcAcuteAngleBonus(currAngle); - // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 6 - angleVectorRepetition(osuCurrObj)))); + // Penalize angle repetition. + acuteAngleBonus *= (1 - angleDifference(currAngle, lastAngle)) * angleVectorRepetition(osuCurrObj); - // Console.Out.WriteLine(1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3)) + ", " + (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 6 - angleVectorRepetition(osuCurrObj))))); + // Console.Out.WriteLine((1 -angleDifference(currAngle, lastAngle)) * angleVectorRepetition(osuCurrObj)); - // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= angleBonus * - DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); - } + // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter + acuteAngleBonus *= angleBonus * + DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), angleVectorRepetition(osuCurrObj))); + wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -171,36 +168,37 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with return aimStrain; } + private static double angleDifference(double curAngle, double lastAngle) + { + return Math.Cos(2 * Math.Min(Math.PI / 4, Math.Abs(curAngle - lastAngle))); + } + private static double angleVectorRepetition(OsuDifficultyHitObject current) { - const double time_limit = 1000; // 2 seconds - const double time_limit_low = 200; + const double note_limit = 6; double constantAngleCount = 0; int index = 0; - double currentTimeGap = 0; + double notesProcessed = 0; - while (currentTimeGap < time_limit) + while (notesProcessed < note_limit) { var loopObj = (OsuDifficultyHitObject)current.Previous(index); if (loopObj.IsNull()) break; - // Account less for objects that are close to the time limit. - double longIntervalFactor = Math.Clamp(1 - (loopObj.StrainTime - time_limit_low) / (time_limit - time_limit_low), 0, 1); - if (loopObj.VectorAngle.IsNotNull() && current.VectorAngle.IsNotNull()) { double angleDifference = Math.Abs(current.VectorAngle.Value - loopObj.VectorAngle.Value); - constantAngleCount += Math.Cos(4 * Math.Min(Math.PI / 8, angleDifference)) / 2 * longIntervalFactor; + constantAngleCount += Math.Cos(4 * Math.Min(Math.PI / 8, angleDifference)); } - currentTimeGap = current.StartTime - loopObj.StartTime; + notesProcessed++; index++; } - return 1 / Math.Clamp(Math.Pow(1 / constantAngleCount, 2), 0.2, 1); + return Math.Min(1 / constantAngleCount, 1); } private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); From f03a253e9e9fa74c3d7292e5543ea06f693e8bd8 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Mon, 15 Sep 2025 16:40:51 +0300 Subject: [PATCH 07/23] I did it...I nerfed crystalia --- .../Difficulty/Evaluators/AimEvaluator.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 1c826a3cb0a6..0a072e8d615b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -78,16 +78,19 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Console.Out.WriteLine(angleVectorRepetition(osuCurrObj)); // Console.Out.WriteLine(osuCurrObj.VectorAngle.Value); + // Console.Out.WriteLine(angleDifference(currAngle, lastAngle)); // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); acuteAngleBonus = calcAcuteAngleBonus(currAngle); + double baseFactor = 1 - 0.9 * Math.Min(acuteAngleBonus, calcAcuteAngleBonus(currAngle) * angleDifference(currAngle, lastAngle)); + // Penalize angle repetition. - acuteAngleBonus *= (1 - angleDifference(currAngle, lastAngle)) * angleVectorRepetition(osuCurrObj); + acuteAngleBonus *= Math.Pow(baseFactor + (1 - baseFactor) * 0.9 * angleVectorRepetition(osuCurrObj), 2); - // Console.Out.WriteLine((1 -angleDifference(currAngle, lastAngle)) * angleVectorRepetition(osuCurrObj)); + // Console.Out.WriteLine(Math.Pow(baseFactor + (1 - baseFactor) * 0.9 * angleVectorRepetition(osuCurrObj), 2)); // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * @@ -156,7 +159,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + aimStrain += Math.Max(acuteAngleBonus * 0.7, wideAngleBonus * wide_angle_multiplier); // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; @@ -191,14 +194,14 @@ private static double angleVectorRepetition(OsuDifficultyHitObject current) if (loopObj.VectorAngle.IsNotNull() && current.VectorAngle.IsNotNull()) { double angleDifference = Math.Abs(current.VectorAngle.Value - loopObj.VectorAngle.Value); - constantAngleCount += Math.Cos(4 * Math.Min(Math.PI / 8, angleDifference)); + constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)); } notesProcessed++; index++; } - return Math.Min(1 / constantAngleCount, 1); + return Math.Pow(Math.Min(0.5 / constantAngleCount, 1), 2); } private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); From 08b906585bf39613db4d07986810acdffbe9c5d3 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 17 Sep 2025 14:04:04 +0300 Subject: [PATCH 08/23] make it cursed --- .../Difficulty/Evaluators/AimEvaluator.cs | 8 ++++++++ osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 5635cc873aa8..955b2fcf2fc5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -68,6 +68,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double sliderBonus = 0; double velocityChangeBonus = 0; double wiggleBonus = 0; + double angleRepetitionNerf = 1; double aimStrain = currVelocity; // Start strain with regular velocity. @@ -76,6 +77,11 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; + double baseFactor = 1 - 0.15 * angleDifference(currAngle, lastAngle); + + // Penalize angle repetition. + angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.95 * angleVectorRepetition(osuCurrObj), 2); + // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); @@ -156,6 +162,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Add in acute angle bonus or wide angle bonus, whichever is larger. aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + aimStrain *= angleRepetitionNerf; + // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index 6823512cef12..c6b9942fcd3d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -16,7 +16,7 @@ public abstract class OsuStrainSkill : StrainSkill /// The number of sections with the highest strains, which the peak strain reductions will apply to. /// This is done in order to decrease their impact on the overall difficulty of the map for this skill. /// - protected virtual int ReducedSectionCount => 10; + protected virtual int ReducedSectionCount => 0; /// /// The baseline multiplier applied to the section with the biggest strain. From fd5f6248c9fb38ecf395273a2ab42d1587252d2b Mon Sep 17 00:00:00 2001 From: kwotaq Date: Thu, 18 Sep 2025 21:57:27 +0300 Subject: [PATCH 09/23] make it more cursed --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 955b2fcf2fc5..b6ca3e39d002 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -77,7 +77,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; - double baseFactor = 1 - 0.15 * angleDifference(currAngle, lastAngle); + double baseFactor = 1 - 0.15 * DifficultyCalculationUtils.Smoothstep(lastAngle, double.DegreesToRadians(90), double.DegreesToRadians(40)) * angleDifference(currAngle, lastAngle); // Penalize angle repetition. angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.95 * angleVectorRepetition(osuCurrObj), 2); @@ -160,7 +160,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * 0.8); aimStrain *= angleRepetitionNerf; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 5816d27a5e81..c6eb8bd241dc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -27,7 +27,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplier => 26; + private double skillMultiplier => 27; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); From fea2fee61c075d9cc4b789015b4d3f3e7cfd1fb4 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Sat, 20 Sep 2025 14:00:20 +0300 Subject: [PATCH 10/23] i hate flow aim --- .../Difficulty/Evaluators/AimEvaluator.cs | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index b6ca3e39d002..2f91ea4e4579 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -85,23 +85,17 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. - { - acuteAngleBonus = calcAcuteAngleBonus(currAngle); - - // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); + acuteAngleBonus = calcAcuteAngleBonus(currAngle); - // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= angleBonus * - DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); - } + // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter + acuteAngleBonus *= angleBonus * + DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); + wideAngleBonus *= 1 - DifficultyCalculationUtils.Smoothstep(lastAngle, double.DegreesToRadians(90), double.DegreesToRadians(140)) * angleDifference(currAngle, lastAngle); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -160,7 +154,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * 0.8); + aimStrain += Math.Max(acuteAngleBonus * 0.3, wideAngleBonus * 0.8); aimStrain *= angleRepetitionNerf; From 0e30c0508ad8e18b63d0cd478468be68845d4b09 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Tue, 23 Sep 2025 03:18:34 +0300 Subject: [PATCH 11/23] small refactor and isolate to only acute aim --- .../Difficulty/Evaluators/AimEvaluator.cs | 30 +++++++++++-------- .../Preprocessing/OsuDifficultyHitObject.cs | 4 +-- .../Difficulty/Skills/Aim.cs | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 2f91ea4e4579..94c514915e4b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class AimEvaluator { - private const double wide_angle_multiplier = 1.5; + private const double wide_angle_multiplier = 1.0; private const double acute_angle_multiplier = 2.55; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; @@ -77,7 +77,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; - double baseFactor = 1 - 0.15 * DifficultyCalculationUtils.Smoothstep(lastAngle, double.DegreesToRadians(90), double.DegreesToRadians(40)) * angleDifference(currAngle, lastAngle); + double baseFactor = 1 - 0.15 * DifficultyCalculationUtils.Smoothstep(lastAngle, double.DegreesToRadians(90), double.DegreesToRadians(40)) * angleSimilarity(currAngle, lastAngle); // Penalize angle repetition. angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.95 * angleVectorRepetition(osuCurrObj), 2); @@ -85,17 +85,23 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - acuteAngleBonus = calcAcuteAngleBonus(currAngle); + if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. + { + acuteAngleBonus = calcAcuteAngleBonus(currAngle); + + // Penalize angle repetition. + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); - // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= angleBonus * - DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); + // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter + acuteAngleBonus *= angleBonus * + DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); + } wideAngleBonus = calcWideAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - DifficultyCalculationUtils.Smoothstep(lastAngle, double.DegreesToRadians(90), double.DegreesToRadians(140)) * angleDifference(currAngle, lastAngle); + wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); // Apply full wide angle bonus for distance more than one diameter wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); @@ -154,7 +160,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * 0.3, wideAngleBonus * 0.8); + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); aimStrain *= angleRepetitionNerf; @@ -168,7 +174,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with return aimStrain; } - private static double angleDifference(double curAngle, double lastAngle) + private static double angleSimilarity(double curAngle, double lastAngle) { return Math.Cos(2 * Math.Min(Math.PI / 4, Math.Abs(curAngle - lastAngle))); } @@ -188,9 +194,9 @@ private static double angleVectorRepetition(OsuDifficultyHitObject current) if (loopObj.IsNull()) break; - if (loopObj.VectorAngle.IsNotNull() && current.VectorAngle.IsNotNull()) + if (loopObj.NormalisedVectorAngle.IsNotNull() && current.NormalisedVectorAngle.IsNotNull()) { - double angleDifference = Math.Abs(current.VectorAngle.Value - loopObj.VectorAngle.Value); + double angleDifference = Math.Abs(current.NormalisedVectorAngle.Value - loopObj.NormalisedVectorAngle.Value); constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 4c4a9adaf739..887089b96d60 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -110,7 +110,7 @@ public class OsuDifficultyHitObject : DifficultyHitObject /// public double SmallCircleBonus { get; private set; } - public double? VectorAngle { get; private set; } + public double? NormalisedVectorAngle { get; private set; } private readonly OsuDifficultyHitObject? lastLastDifficultyObject; private readonly OsuDifficultyHitObject? lastDifficultyObject; @@ -240,7 +240,7 @@ private void setDistances(double clockRate) } Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition; - VectorAngle = Math.Atan2(Math.Abs(v2.Y), Math.Abs(v2.X)); + NormalisedVectorAngle = Math.Atan2(Math.Abs(v2.Y), Math.Abs(v2.X)); if (lastLastDifficultyObject != null && lastLastDifficultyObject.BaseObject is not Spinner) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index c6eb8bd241dc..6dcd496a41a9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -27,7 +27,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplier => 27; + private double skillMultiplier => 27.0; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); From 8807a623ddc0760b23b058942997e876ff53cc93 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 24 Sep 2025 16:19:43 +0300 Subject: [PATCH 12/23] remember breaks exist --- .../Difficulty/Evaluators/AimEvaluator.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 94c514915e4b..769c06cb4be3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -181,26 +181,33 @@ private static double angleSimilarity(double curAngle, double lastAngle) private static double angleVectorRepetition(OsuDifficultyHitObject current) { + const double time_limit = 2000; // 2 seconds + const double time_limit_low = 200; const double note_limit = 6; double constantAngleCount = 0; int index = 0; + double currentTimeGap = 0; double notesProcessed = 0; - while (notesProcessed < note_limit) + while (notesProcessed < note_limit && currentTimeGap < time_limit) { var loopObj = (OsuDifficultyHitObject)current.Previous(index); if (loopObj.IsNull()) break; + // Account less for objects that are close to the time limit. + double longIntervalFactor = Math.Clamp(1 - (loopObj.AdjustedDeltaTime - time_limit_low) / (time_limit - time_limit_low), 0, 1); + if (loopObj.NormalisedVectorAngle.IsNotNull() && current.NormalisedVectorAngle.IsNotNull()) { double angleDifference = Math.Abs(current.NormalisedVectorAngle.Value - loopObj.NormalisedVectorAngle.Value); - constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)); + constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)) * longIntervalFactor; } notesProcessed++; + currentTimeGap = current.StartTime - loopObj.StartTime; index++; } From 63ac0c9b18b525d84fd5758bd8bc91efaad19666 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 24 Sep 2025 23:23:51 +0300 Subject: [PATCH 13/23] realise i can just use rhythm instead --- .../Difficulty/Evaluators/AimEvaluator.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 769c06cb4be3..a356fc131914 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -181,33 +181,29 @@ private static double angleSimilarity(double curAngle, double lastAngle) private static double angleVectorRepetition(OsuDifficultyHitObject current) { - const double time_limit = 2000; // 2 seconds - const double time_limit_low = 200; const double note_limit = 6; double constantAngleCount = 0; int index = 0; - double currentTimeGap = 0; double notesProcessed = 0; - while (notesProcessed < note_limit && currentTimeGap < time_limit) + while (notesProcessed < note_limit) { var loopObj = (OsuDifficultyHitObject)current.Previous(index); if (loopObj.IsNull()) break; - // Account less for objects that are close to the time limit. - double longIntervalFactor = Math.Clamp(1 - (loopObj.AdjustedDeltaTime - time_limit_low) / (time_limit - time_limit_low), 0, 1); + if (Math.Abs(current.DeltaTime - loopObj.DeltaTime) > 25) + break; if (loopObj.NormalisedVectorAngle.IsNotNull() && current.NormalisedVectorAngle.IsNotNull()) { double angleDifference = Math.Abs(current.NormalisedVectorAngle.Value - loopObj.NormalisedVectorAngle.Value); - constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)) * longIntervalFactor; + constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)); } notesProcessed++; - currentTimeGap = current.StartTime - loopObj.StartTime; index++; } From 4062ea4daa8d2a1b913ef7acc7bf0ee3ddddfb2f Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 21 Jan 2026 16:29:35 +0200 Subject: [PATCH 14/23] kinda cursed but at least it works in live --- .../Difficulty/Evaluators/AimEvaluator.cs | 43 ++++++++++--------- .../Difficulty/Skills/Aim.cs | 2 +- .../Difficulty/Skills/OsuStrainSkill.cs | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index a356fc131914..e274a0221fd9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -68,7 +68,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double sliderBonus = 0; double velocityChangeBonus = 0; double wiggleBonus = 0; - double angleRepetitionNerf = 1; + double aimComplexityBonus = 0; double aimStrain = currVelocity; // Start strain with regular velocity. @@ -77,26 +77,27 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; - double baseFactor = 1 - 0.15 * DifficultyCalculationUtils.Smoothstep(lastAngle, double.DegreesToRadians(90), double.DegreesToRadians(40)) * angleSimilarity(currAngle, lastAngle); - - // Penalize angle repetition. - angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.95 * angleVectorRepetition(osuCurrObj), 2); - // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. - { - acuteAngleBonus = calcAcuteAngleBonus(currAngle); + double angleDif = angleDifference(currAngle, lastAngle); + double vectorRepetition = angleVectorRepetition(osuCurrObj); - // Penalize angle repetition. - acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); + double stackFactor = DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, 0, diameter); - // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= angleBonus * - DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); - } + double baseFactor = 1 - angleDif; + + // Penalize angle repetition. + aimComplexityBonus = angleBonus * Math.Pow(baseFactor + (1 - baseFactor) * vectorRepetition * stackFactor, 2); + + acuteAngleBonus = calcAcuteAngleBonus(currAngle); + + // Penalize angle repetition. + acuteAngleBonus *= 0.15 + 0.85 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); + + // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter + acuteAngleBonus *= DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2) * stackFactor; wideAngleBonus = calcWideAngleBonus(currAngle); @@ -156,13 +157,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; } + aimStrain += aimComplexityBonus * 0.5; + aimStrain += wiggleBonus * wiggle_multiplier; - aimStrain += velocityChangeBonus * velocity_change_multiplier; + aimStrain += velocityChangeBonus * 1.2; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); - - aimStrain *= angleRepetitionNerf; + aimStrain += Math.Max(acuteAngleBonus * 6.5, wideAngleBonus * 1.5); // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; @@ -174,7 +175,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with return aimStrain; } - private static double angleSimilarity(double curAngle, double lastAngle) + private static double angleDifference(double curAngle, double lastAngle) { return Math.Cos(2 * Math.Min(Math.PI / 4, Math.Abs(curAngle - lastAngle))); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index a9fb5e4ca370..532577024fb2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -27,7 +27,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentStrain; - private double skillMultiplier => 27.0; + private double skillMultiplier => 20.5; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index 87d8daa19215..916b6e7b2d51 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -16,7 +16,7 @@ public abstract class OsuStrainSkill : StrainSkill /// The number of sections with the highest strains, which the peak strain reductions will apply to. /// This is done in order to decrease their impact on the overall difficulty of the map for this skill. /// - protected virtual int ReducedSectionCount => 0; + protected virtual int ReducedSectionCount => 10; /// /// The baseline multiplier applied to the section with the biggest strain. From 7be74baa709a1f7938e91b3cc9d11957109313c9 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 21 Jan 2026 16:54:45 +0200 Subject: [PATCH 15/23] make it more live --- .../Difficulty/Evaluators/AimEvaluator.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index e274a0221fd9..819b0a257c2c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -90,14 +90,18 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Penalize angle repetition. aimComplexityBonus = angleBonus * Math.Pow(baseFactor + (1 - baseFactor) * vectorRepetition * stackFactor, 2); - acuteAngleBonus = calcAcuteAngleBonus(currAngle); + if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. + { + acuteAngleBonus = calcAcuteAngleBonus(currAngle); - // Penalize angle repetition. - acuteAngleBonus *= 0.15 + 0.85 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); + // Penalize angle repetition. + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); - // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter - acuteAngleBonus *= DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * - DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2) * stackFactor; + // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter + acuteAngleBonus *= angleBonus * + DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); + } wideAngleBonus = calcWideAngleBonus(currAngle); @@ -128,7 +132,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (distance < 1) { - wideAngleBonus *= 1 - 0.35 * (1 - distance); + wideAngleBonus *= 1 - 0.5 * (1 - distance); } } } @@ -163,7 +167,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * 1.2; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * 6.5, wideAngleBonus * 1.5); + aimStrain += Math.Max(acuteAngleBonus * 3.5, wideAngleBonus * 1.7); // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; From 627cdf126e286a96823e34b55ab66343b81bd5ce Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 21 Jan 2026 17:03:11 +0200 Subject: [PATCH 16/23] mess with more angle stuff --- .../Difficulty/Evaluators/AimEvaluator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 819b0a257c2c..f6ae4a429ab8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -132,7 +132,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (distance < 1) { - wideAngleBonus *= 1 - 0.5 * (1 - distance); + wideAngleBonus *= 1 - 0.9 * (1 - distance); } } } @@ -167,7 +167,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * 1.2; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * 3.5, wideAngleBonus * 1.7); + aimStrain += Math.Max(acuteAngleBonus * 3.5, wideAngleBonus * 2.0); // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; @@ -215,8 +215,8 @@ private static double angleVectorRepetition(OsuDifficultyHitObject current) return Math.Pow(Math.Min(0.5 / constantAngleCount, 1), 2); } - private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); + private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(60), double.DegreesToRadians(110)); - private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); + private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(110), double.DegreesToRadians(60)); } } From 346f42a9557baa503da84d3db28ff59289fb9b82 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Wed, 21 Jan 2026 17:30:48 +0200 Subject: [PATCH 17/23] nerf acute a bit --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index f6ae4a429ab8..35229b8093a1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -167,7 +167,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * 1.2; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * 3.5, wideAngleBonus * 2.0); + aimStrain += Math.Max(acuteAngleBonus * 3.0, wideAngleBonus * 2.0); // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; From 6b9fc0e388fcb36a9beebd8fc1dc620f12601073 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Thu, 29 Jan 2026 03:33:37 +0200 Subject: [PATCH 18/23] go back to the old ways --- .../Difficulty/Evaluators/AimEvaluator.cs | 12 ++++++------ osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 12655e0023dc..98abab123cd0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -70,7 +70,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double sliderBonus = 0; double velocityChangeBonus = 0; double wiggleBonus = 0; - double aimComplexityBonus = 0; + double angleRepetitionNerf = 1; double aimStrain = currVelocity; // Start strain with regular velocity. @@ -87,10 +87,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double stackFactor = DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, 0, diameter); - double baseFactor = 1 - angleDif; + double baseFactor = 1 - 0.15 * calcAcuteAngleBonus(lastAngle) * angleDif; // Penalize angle repetition. - aimComplexityBonus = angleBonus * Math.Pow(baseFactor + (1 - baseFactor) * vectorRepetition * stackFactor, 2); + angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.95 * vectorRepetition * stackFactor, 2); if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. { @@ -166,13 +166,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; } - aimStrain += aimComplexityBonus * 0.5; + aimStrain *= angleRepetitionNerf; aimStrain += wiggleBonus * wiggle_multiplier; - aimStrain += velocityChangeBonus * 1.2; + aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * 3.0, wideAngleBonus * 2.0); + aimStrain += Math.Max(acuteAngleBonus * 2.8, wideAngleBonus * 1.2); // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 146ef8167dd9..175ec047bb3d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,7 +31,7 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 26.0; + private double skillMultiplierAim => 28.3; private double skillMultiplierSpeed => 1.3; private double skillMultiplierTotal => 1.01; private double meanExponent => 1.2; From 2bf37e403f28ef35ff683bf6351ce5d70fa6fe2b Mon Sep 17 00:00:00 2001 From: kwotaq Date: Fri, 30 Jan 2026 19:43:43 +0200 Subject: [PATCH 19/23] revert acute curve and mult balance --- .../Difficulty/Evaluators/AimEvaluator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 68295ad939b8..78561ad98ca8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -90,7 +90,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double baseFactor = 1 - 0.15 * calcAcuteAngleBonus(lastAngle) * angleDif; // Penalize angle repetition. - angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.95 * vectorRepetition * stackFactor, 2); + angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.9 * vectorRepetition * stackFactor, 2); if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. { @@ -134,7 +134,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with if (distance < 1) { - wideAngleBonus *= 1 - 0.9 * (1 - distance); + wideAngleBonus *= 1 - 0.55 * (1 - distance); } } } @@ -172,7 +172,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * 2.8, wideAngleBonus * 1.2); + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * 1.2); // Add in additional slider velocity bonus. if (withSliderTravelDistance) @@ -226,6 +226,6 @@ private static double angleVectorRepetition(OsuDifficultyHitObject current) private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(60), double.DegreesToRadians(110)); - private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); } } From 4a80450895e07988b739b2274185b08b284835ff Mon Sep 17 00:00:00 2001 From: kwotaq Date: Sat, 31 Jan 2026 03:48:36 +0200 Subject: [PATCH 20/23] clean up, revert wide too because i forgot --- .../Difficulty/Evaluators/AimEvaluator.cs | 15 +++++---------- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 78561ad98ca8..7e0745f530cf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { public static class AimEvaluator { - private const double wide_angle_multiplier = 1.5; + private const double wide_angle_multiplier = 1.2; private const double acute_angle_multiplier = 2.3; private const double slider_multiplier = 1.5; private const double velocity_change_multiplier = 0.75; @@ -82,12 +82,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - double angleDif = angleDifference(currAngle, lastAngle); + double angleDifference = Math.Cos(2 * Math.Min(Math.PI / 4, Math.Abs(currAngle - lastAngle))); double vectorRepetition = angleVectorRepetition(osuCurrObj); double stackFactor = DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, 0, diameter); - double baseFactor = 1 - 0.15 * calcAcuteAngleBonus(lastAngle) * angleDif; + double baseFactor = 1 - 0.15 * calcAcuteAngleBonus(lastAngle) * angleDifference; // Penalize angle repetition. angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.9 * vectorRepetition * stackFactor, 2); @@ -172,7 +172,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with aimStrain += velocityChangeBonus * velocity_change_multiplier; // Add in acute angle bonus or wide angle bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * 1.2); + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); // Add in additional slider velocity bonus. if (withSliderTravelDistance) @@ -188,11 +188,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.15, ms / 1000)); - private static double angleDifference(double curAngle, double lastAngle) - { - return Math.Cos(2 * Math.Min(Math.PI / 4, Math.Abs(curAngle - lastAngle))); - } - private static double angleVectorRepetition(OsuDifficultyHitObject current) { const double note_limit = 6; @@ -224,7 +219,7 @@ private static double angleVectorRepetition(OsuDifficultyHitObject current) return Math.Pow(Math.Min(0.5 / constantAngleCount, 1), 2); } - private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(60), double.DegreesToRadians(110)); + private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 175ec047bb3d..9a96bef76680 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 28.3; - private double skillMultiplierSpeed => 1.3; + private double skillMultiplierAim => 28.8; + private double skillMultiplierSpeed => 1.1; private double skillMultiplierTotal => 1.01; private double meanExponent => 1.2; From 2ce0ff85176cd01de778cf9b0e4cbb73e69c5f0f Mon Sep 17 00:00:00 2001 From: kwotaq Date: Sat, 31 Jan 2026 04:20:15 +0200 Subject: [PATCH 21/23] move lastvectorposition initialization --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index be19bdaf92c0..7dfcb23863ba 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -275,9 +275,6 @@ private void setDistances(double clockRate) MinimumJumpDistance = Math.Max(0, Math.Min(LazyJumpDistance - (maximum_slider_radius - assumed_slider_radius), tailJumpDistance - maximum_slider_radius)); } - Vector2 v = BaseObject.StackedPosition - lastCursorPosition; - NormalisedVectorAngle = Math.Atan2(Math.Abs(v.Y), Math.Abs(v.X)); - if (lastLastDifficultyObject != null && lastLastDifficultyObject.BaseObject is not Spinner) { if (lastDifficultyObject!.BaseObject is Slider prevSlider && lastDifficultyObject.TravelDistance > 0) @@ -288,6 +285,9 @@ private void setDistances(double clockRate) double angle = calculateAngle(BaseObject.StackedPosition, lastCursorPosition, lastLastCursorPosition); double sliderAngle = calculateSliderAngle(lastDifficultyObject!, lastLastCursorPosition); + Vector2 v = BaseObject.StackedPosition - lastCursorPosition; + NormalisedVectorAngle = Math.Atan2(Math.Abs(v.Y), Math.Abs(v.X)); + Angle = Math.Min(angle, sliderAngle); } } From ca2aa53358d69029c41c3e9beba9cecc161a03dc Mon Sep 17 00:00:00 2001 From: kwotaq Date: Sat, 31 Jan 2026 14:22:43 +0200 Subject: [PATCH 22/23] use radians --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 7e0745f530cf..bb9681e3fb36 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -82,12 +82,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - double angleDifference = Math.Cos(2 * Math.Min(Math.PI / 4, Math.Abs(currAngle - lastAngle))); + double angleDifferenceAdjusted = Math.Cos(2 * Math.Min(double.DegreesToRadians(45), Math.Abs(currAngle - lastAngle))); double vectorRepetition = angleVectorRepetition(osuCurrObj); double stackFactor = DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, 0, diameter); - double baseFactor = 1 - 0.15 * calcAcuteAngleBonus(lastAngle) * angleDifference; + double baseFactor = 1 - 0.15 * calcAcuteAngleBonus(lastAngle) * angleDifferenceAdjusted; // Penalize angle repetition. angleRepetitionNerf = Math.Pow(baseFactor + (1 - baseFactor) * 0.9 * vectorRepetition * stackFactor, 2); @@ -209,7 +209,7 @@ private static double angleVectorRepetition(OsuDifficultyHitObject current) if (loopObj.NormalisedVectorAngle.IsNotNull() && current.NormalisedVectorAngle.IsNotNull()) { double angleDifference = Math.Abs(current.NormalisedVectorAngle.Value - loopObj.NormalisedVectorAngle.Value); - constantAngleCount += Math.Cos(8 * Math.Min(Math.PI / 16, angleDifference)); + constantAngleCount += Math.Cos(8 * Math.Min(double.DegreesToRadians(11.25), angleDifference)); } notesProcessed++; From 2c88f7adfdedf47f34fac33d7f18b6f4e1865dd1 Mon Sep 17 00:00:00 2001 From: kwotaq Date: Fri, 6 Feb 2026 00:08:27 +0200 Subject: [PATCH 23/23] few balance changes --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 9a96bef76680..9f5f2d87e442 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders) private double currentAimStrain; private double currentSpeedStrain; - private double skillMultiplierAim => 28.8; - private double skillMultiplierSpeed => 1.1; + private double skillMultiplierAim => 30; + private double skillMultiplierSpeed => 0.7; private double skillMultiplierTotal => 1.01; private double meanExponent => 1.2;