diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
index 8b9575334a..8e0939a290 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
@@ -58,25 +58,42 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills
catchCurrent.NormalizedPosition + (normalized_hitobject_radius - absolute_player_positioning_error)
);
- float distanceMoved = playerPosition - lastPlayerPosition.Value;
+ float groupness = getGroupness(catchCurrent);
- if (catchCurrent.NormalizedPositionLast0.IsNotNull() && catchCurrent.NormalizedPositionLast1.IsNotNull())
+ // If 3 objects are in group - player will try to cheese them
+ if (groupness > 0)
{
- float lenience = normalized_hitobject_radius * 2;
- float antiCheese = 1;
+ // Coordinates of the group
+ float leftCoords = Math.Min(Math.Min(catchCurrent.NormalizedPosition, catchCurrent.NormalizedPositionLast0), (float)catchCurrent.NormalizedPositionLast1!);
+ float rightCoords = Math.Max(Math.Max(catchCurrent.NormalizedPosition, catchCurrent.NormalizedPositionLast0), (float)catchCurrent.NormalizedPositionLast1!);
+ float centerCoords = (leftCoords + rightCoords) / 2;
- float deltaCurrLast0 = Math.Clamp(lenience - Math.Abs(catchCurrent.NormalizedPosition - catchCurrent.NormalizedPositionLast0), 0, absolute_player_positioning_error);
- antiCheese *= deltaCurrLast0 / absolute_player_positioning_error;
+ // Distance from player to the boundaries of group
+ float leftDelta = Math.Abs(lastPlayerPosition.Value - leftCoords);
+ float rightDelta = Math.Abs(lastPlayerPosition.Value - rightCoords);
- float deltaCurrLast1 = Math.Clamp(lenience - Math.Abs((float)(catchCurrent.NormalizedPosition - catchCurrent.NormalizedPositionLast1)), 0, absolute_player_positioning_error);
- antiCheese *= deltaCurrLast1 / absolute_player_positioning_error;
+ // Normalized deltas:
+ leftDelta = normalizeDelta(leftDelta, normalized_hitobject_radius);
+ rightDelta = normalizeDelta(rightDelta, normalized_hitobject_radius);
- float deltaLast0Last1 = Math.Clamp(lenience - Math.Abs((float)(catchCurrent.NormalizedPositionLast0 - catchCurrent.NormalizedPositionLast1)), 0, absolute_player_positioning_error);
- antiCheese *= deltaLast0Last1 / absolute_player_positioning_error;
+ // Determines how close player is to position where they can hit it
+ float closetness = 1;
+ closetness *= 1 - leftDelta;
+ closetness *= 1 - rightDelta;
- distanceMoved *= 1 - antiCheese;
+ // Player will be more likely to move if it's far away from center of group
+ float resultPosition = float.Lerp(centerCoords, lastPlayerPosition.Value, closetness);
+
+ // Assume that player will take the easier route
+ if (Math.Abs(playerPosition - lastPlayerPosition.Value) < Math.Abs(resultPosition - lastPlayerPosition.Value))
+ resultPosition = playerPosition;
+
+ // Player will be more likely to move to group center if objects are close enough
+ playerPosition = float.Lerp(playerPosition, resultPosition, groupness);
}
+ float distanceMoved = playerPosition - lastPlayerPosition.Value;
+
double weightedStrainTime = catchCurrent.StrainTime + 13 + (3 / catcherSpeedMultiplier);
double distanceAddition = (Math.Pow(Math.Abs(distanceMoved), 1.3) / 510);
@@ -119,5 +136,39 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills
return distanceAddition / weightedStrainTime;
}
+
+ private float getGroupness(CatchDifficultyHitObject obj)
+ {
+ if (obj.NormalizedPositionLast1.IsNull())
+ return 0;
+
+ // Raw deltas between objects
+ float delta01 = Math.Abs(obj.NormalizedPosition - obj.NormalizedPositionLast0);
+ float delta02 = Math.Abs((float)(obj.NormalizedPosition - obj.NormalizedPositionLast1));
+ float delta12 = Math.Abs((float)(obj.NormalizedPositionLast0 - obj.NormalizedPositionLast1));
+
+ // Normalized deltas:
+ // 0 - very close, inbetween - moderately close, 1 - too far
+ delta01 = normalizeDelta(delta01, 2 * normalized_hitobject_radius);
+ delta02 = normalizeDelta(delta02, 2 * normalized_hitobject_radius);
+ delta12 = normalizeDelta(delta12, 2 * normalized_hitobject_radius);
+
+ // If at least one is far apart - groupness is 0
+ float groupness = 1;
+ groupness *= 1 - delta01;
+ groupness *= 1 - delta02;
+ groupness *= 1 - delta12;
+
+ return groupness;
+ }
+
+ ///
+ /// Normalizing delta:
+ /// 0 - very close, inbetween - moderately close, 1 - too far
+ ///
+ ///
+ /// Deltas lower than shift will be 0
+ ///
+ private float normalizeDelta(float delta, float shift) => Math.Clamp(delta - shift + absolute_player_positioning_error, 0, absolute_player_positioning_error) / absolute_player_positioning_error;
}
}