Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
76 changes: 36 additions & 40 deletions osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
Expand All @@ -131,27 +132,22 @@ 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);

aimStrain += velocityChangeBonus * velocity_change_multiplier;
}

double sliderBonus = 0;

if (osuCurrObj.BaseObject is Slider)
{
// Reward sliders based on velocity.
sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
}

// 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)
aimStrain += (sliderBonus < 1 ? sliderBonus : Math.Pow(sliderBonus, 0.75)) * slider_multiplier;
Expand Down Expand Up @@ -208,13 +204,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));
}
}
Loading