diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs index 9b1903e6137c..cac4febf1dd6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/FlowAimEvaluator.cs @@ -77,7 +77,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Acute angles are also hard to flow // We square root velocity to make acute angle switches in streams aren't having difficulty higher than snap flowDifficulty += Math.Sqrt(currVelocity) * - SnapAimEvaluator.CalcAcuteAngleBonus(osuCurrObj.Angle.Value) * + SnapAimEvaluator.CalcAngleAcuteness(osuCurrObj.Angle.Value) * overlappedNotesWeight; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs index 75ecfe89ecc1..3a67c84ac3c5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs @@ -55,51 +55,37 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance; double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime; - double wideAngleBonus = 0; - double acuteAngleBonus = 0; - double sliderBonus = 0; - double velocityChangeBonus = 0; - double wiggleBonus = 0; - double aimStrain = currVelocity; // Start strain with regular velocity. + // Penalize angle repetition. + aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj); + if (osuCurrObj.Angle != null && osuLastObj.Angle != null) { double currAngle = osuCurrObj.Angle.Value; double lastAngle = osuLastObj.Angle.Value; // Rewarding angles, take the smaller velocity as base. - double angleBonus = Math.Min(currVelocity, prevVelocity); + double velocityInfluence = Math.Min(currVelocity, prevVelocity); + + double acuteAngleBonus = 0; 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 = velocityInfluence * CalcAngleAcuteness(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) * + acuteAngleBonus *= DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter * 2); + + // Penalize angle repetition. + acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(CalcAngleAcuteness(lastAngle), 3))); } - wideAngleBonus = calcWideAngleBonus(currAngle); + double wideAngleBonus = velocityInfluence * calcAngleWideness(currAngle); // Penalize angle repetition. - wideAngleBonus *= 0.25 + 0.75 * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); - - wideAngleBonus *= angleBonus; - - // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle - // https://www.desmos.com/calculator/dp0v0nvowc - wiggleBonus = angleBonus - * DifficultyCalculationUtils.Smootherstep(currDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8) - * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) - * DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8) - * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + wideAngleBonus *= 0.25 + 0.75 * (1 - Math.Min(wideAngleBonus, Math.Pow(calcAngleWideness(lastAngle), 3))); if (osuLast2Obj != null) { @@ -115,6 +101,21 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with wideAngleBonus *= 1 - 0.55 * (1 - distance); } } + + // Add in acute angle bonus or wide angle bonus, whichever is larger. + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + + // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle + // https://www.desmos.com/calculator/dp0v0nvowc + double wiggleBonus = velocityInfluence + * DifficultyCalculationUtils.Smootherstep(currDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) + * DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + + aimStrain += wiggleBonus * wiggle_multiplier; } if (Math.Max(prevVelocity, currVelocity) != 0) @@ -131,30 +132,20 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. double overlapVelocityBuff = Math.Min(diameter * 1.25 / Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), Math.Abs(prevVelocity - currVelocity)); - velocityChangeBonus = overlapVelocityBuff * distRatio; + double velocityChangeBonus = overlapVelocityBuff * distRatio; // Penalize for rhythm changes. velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) / Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), 2); - } - if (osuCurrObj.BaseObject is Slider) - { - // Reward sliders based on velocity. - sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; + aimStrain += velocityChangeBonus * velocity_change_multiplier; } - // Penalize angle repetition. - aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj); - - aimStrain += wiggleBonus * wiggle_multiplier; - 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); - - // Add in additional slider velocity bonus. - if (withSliderTravelDistance) + // Reward sliders based on velocity. + if (osuCurrObj.BaseObject is Slider && withSliderTravelDistance) + { + double sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; aimStrain += (sliderBonus < 1 ? sliderBonus : Math.Pow(sliderBonus, 0.75)) * slider_multiplier; + } // Apply high circle size bonus aimStrain *= osuCurrObj.SmallCircleBonus; @@ -208,13 +199,13 @@ private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuD double angleDifferenceAdjusted = Math.Cos(2 * Math.Min(double.DegreesToRadians(45), Math.Abs(currAngle - lastAngle) * stackFactor)); - double baseNerf = 1 - maximum_repetition_nerf * CalcAcuteAngleBonus(lastAngle) * angleDifferenceAdjusted; + double baseNerf = 1 - maximum_repetition_nerf * CalcAngleAcuteness(lastAngle) * angleDifferenceAdjusted; return Math.Pow(baseNerf + (1 - baseNerf) * vectorRepetition * maximum_vector_influence * stackFactor, 2); } - private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); + private static double calcAngleWideness(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140)); - public static double CalcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); + public static double CalcAngleAcuteness(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40)); } }