Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c75373d
simple implementation
kwotaq Sep 14, 2025
7e9ce35
fix wide being worth nothing
kwotaq Sep 14, 2025
cfbc9e2
realize im stupid and have shit backwards
kwotaq Sep 15, 2025
da069c6
rename method
kwotaq Sep 15, 2025
4debd0b
4am brain malfunctions
kwotaq Sep 15, 2025
fc6ab4f
remove wide angle considerations and new acute repetition nerf
kwotaq Sep 15, 2025
f03a253
I did it...I nerfed crystalia
kwotaq Sep 15, 2025
b6418d0
Merge branch 'pp-dev' into angle-vector-repeat
kwotaq Sep 17, 2025
08b9065
make it cursed
kwotaq Sep 17, 2025
fd5f624
make it more cursed
kwotaq Sep 18, 2025
fea2fee
i hate flow aim
kwotaq Sep 20, 2025
0e30c05
small refactor and isolate to only acute aim
kwotaq Sep 23, 2025
8807a62
remember breaks exist
kwotaq Sep 24, 2025
63ac0c9
realise i can just use rhythm instead
kwotaq Sep 24, 2025
bfb37bf
Merge branch 'pp-dev' into angle-vector-repeat
kwotaq Jan 21, 2026
4062ea4
kinda cursed but at least it works in live
kwotaq Jan 21, 2026
7be74ba
make it more live
kwotaq Jan 21, 2026
627cdf1
mess with more angle stuff
kwotaq Jan 21, 2026
346f42a
nerf acute a bit
kwotaq Jan 21, 2026
751495a
Merge branch 'pp-dev' into angle-vector-repeat
kwotaq Jan 29, 2026
6b9fc0e
go back to the old ways
kwotaq Jan 29, 2026
e84d350
Merge branch 'pp-dev' into angle-vector-repeat
kwotaq Jan 30, 2026
2bf37e4
revert acute curve and mult balance
kwotaq Jan 30, 2026
4a80450
clean up, revert wide too because i forgot
kwotaq Jan 31, 2026
2ce0ff8
move lastvectorposition initialization
kwotaq Jan 31, 2026
ca2aa53
use radians
kwotaq Jan 31, 2026
11c1cfe
Merge branch 'pp-dev' into angle-vector-repeat
kwotaq Feb 1, 2026
1909453
Merge remote-tracking branch 'ppy/pp-dev' into angle-vector-repeat
kwotaq Feb 4, 2026
ea527ad
Merge remote-tracking branch 'ppy/pp-dev' into angle-vector-repeat
kwotaq Feb 5, 2026
2c88f7a
few balance changes
kwotaq Feb 5, 2026
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
49 changes: 47 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -11,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;
Expand Down Expand Up @@ -69,6 +70,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.

Expand All @@ -80,6 +82,16 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
// Rewarding angles, take the smaller velocity as base.
double angleBonus = Math.Min(currVelocity, prevVelocity);

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) * angleDifferenceAdjusted;

// Penalize angle repetition.
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.
{
acuteAngleBonus = calcAcuteAngleBonus(currAngle);
Expand Down Expand Up @@ -122,7 +134,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with

if (distance < 1)
{
wideAngleBonus *= 1 - 0.35 * (1 - distance);
wideAngleBonus *= 1 - 0.55 * (1 - distance);
}
}
}
Expand Down Expand Up @@ -154,6 +166,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
}

aimStrain *= angleRepetitionNerf;

aimStrain += wiggleBonus * wiggle_multiplier;
aimStrain += velocityChangeBonus * velocity_change_multiplier;

Expand All @@ -178,6 +192,37 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math.Pow(0.15, ms / 1000))
* DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS);

private static double angleVectorRepetition(OsuDifficultyHitObject current)
{
const double note_limit = 6;

double constantAngleCount = 0;
int index = 0;
double notesProcessed = 0;

while (notesProcessed < note_limit)
{
var loopObj = (OsuDifficultyHitObject)current.Previous(index);

if (loopObj.IsNull())
break;

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(double.DegreesToRadians(11.25), angleDifference));
}

notesProcessed++;
index++;
}

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 calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ public class OsuDifficultyHitObject : DifficultyHitObject
/// </summary>
public double SmallCircleBonus { get; private set; }

public double? NormalisedVectorAngle { get; private set; }

private readonly OsuDifficultyHitObject? lastLastDifficultyObject;
private readonly OsuDifficultyHitObject? lastDifficultyObject;

Expand Down Expand Up @@ -279,6 +281,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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public Aim(Mod[] mods, bool includeSliders)
private double currentAimStrain;
private double currentSpeedStrain;

private double skillMultiplierAim => 26.0;
private double skillMultiplierSpeed => 1.3;
private double skillMultiplierAim => 30;
private double skillMultiplierSpeed => 0.7;
private double skillMultiplierTotal => 1.01;
private double meanExponent => 1.2;

Expand Down
Loading