diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs index 24d4677981..53f9d6d5f1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs @@ -38,7 +38,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // The first jump is formed by the first two hitobjects of the map. // If the map has less than two OsuHitObjects, the enumerator will not return anything. for (int i = 1; i < objects.Count; i++) - yield return new OsuDifficultyHitObject(objects[i], objects[i - 1], timeRate); + { + var prev = objects[i - 1]; + var current = objects[i]; + var next = i < objects.Count - 1 ? objects[i + 1] : null; + + yield return new OsuDifficultyHitObject(prev, current, next, timeRate); + } } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index d8e3b340c9..5657f0008e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -40,15 +40,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double StrainTime { get; private set; } + public double? Angle { get; private set; } + private readonly OsuHitObject lastObject; + private readonly OsuHitObject nextObject; private readonly double timeRate; /// /// Initializes the object calculating extra data required for difficulty calculation. /// - public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate) + public OsuDifficultyHitObject(OsuHitObject lastObject, OsuHitObject currentObject, OsuHitObject nextObject, double timeRate) { this.lastObject = lastObject; + this.nextObject = nextObject; this.timeRate = timeRate; BaseObject = currentObject; @@ -82,6 +86,26 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; + + if (nextObject != null) + { + var endCursorPosition = BaseObject.StackedPosition; + + var currentSlider = BaseObject as Slider; + if (currentSlider != null) + { + computeSliderCursorPosition(currentSlider); + endCursorPosition = currentSlider.LazyEndPosition ?? endCursorPosition; + } + + Vector2 v1 = lastCursorPosition - BaseObject.StackedPosition; + Vector2 v2 = nextObject.StackedPosition - endCursorPosition; + + float dot = Vector2.Dot(v1, v2); + float det = v1.X * v2.Y - v1.Y * v2.X; + + Angle = Math.Atan2(det, dot); + } } private void setTimingValues() diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index f11b6d66f6..7ba373fcff 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -15,6 +15,27 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainDecayBase => 0.15; protected override double StrainValueOf(OsuDifficultyHitObject current) - => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime; + { + double angleBonus = 1.0; + + if (current.Angle != null) + { + double angle = current.Angle.Value * 180 / Math.PI; + + if (current.JumpDistance > SINGLE_SPACING_THRESHOLD) + { + if (angle > 75) + angleBonus = (angle / 45 - 75) / 2; + else if (angle > 120) + angleBonus = 0.5; + } + } + + return angleBonus * ( + Math.Pow(current.JumpDistance - SINGLE_SPACING_THRESHOLD, 0.99) + + Math.Pow(current.TravelDistance, 0.99) + + Math.Pow(current.JumpDistance, 0.99) + ) / current.StrainTime; + } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 788dab37d3..0c943c786a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -27,7 +27,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills if (deltaTime < min_speed_bonus) speedBonus = 1 + Math.Pow((min_speed_bonus - deltaTime) / speed_balancing_factor, 2); - return speedBonus * (0.95 + Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 4)) / current.StrainTime; + double angleBonus = 1.0; + + if (current.Angle != null) + { + double angle = current.Angle.Value * 180 / Math.PI; + + if (angle < 135) + angleBonus = (135 - angle / 45) * 0.25 + 1.0; + else if (angle <= 90) + angleBonus = 1.25; + } + + return angleBonus * (0.95 + Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 4)) / current.StrainTime; } } }