Skip to content

Commit

Permalink
Merge pull request #13483 from emu1337/diffspike-balance
Browse files Browse the repository at this point in the history
Spike difficulty / AR&FL adjustments
  • Loading branch information
peppy authored Jul 22, 2021
2 parents 29ffae4 + 84fd597 commit cde8ae6
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 16 deletions.
8 changes: 4 additions & 4 deletions osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public class OsuDifficultyCalculatorTest : DifficultyCalculatorTest
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";

[TestCase(6.9311451172574934d, "diffcalc-test")]
[TestCase(1.0736586907780401d, "zero-length-sliders")]
[TestCase(6.7568168283591499d, "diffcalc-test")]
[TestCase(1.0348244046058293d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);

[TestCase(8.7212283220412345d, "diffcalc-test")]
[TestCase(1.3212137158641493d, "zero-length-sliders")]
[TestCase(8.4783236764532557d, "diffcalc-test")]
[TestCase(1.2708532136987165d, "zero-length-sliders")]
public void TestClockRateAdjusted(double expected, string name)
=> Test(expected, name, new OsuModDoubleTime());

Expand Down
16 changes: 10 additions & 6 deletions osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,26 @@ private double computeAimValue()

double approachRateTotalHitsFactor = 1.0 / (1.0 + Math.Exp(-(0.007 * (totalHits - 400))));

aimValue *= 1.0 + (0.03 + 0.37 * approachRateTotalHitsFactor) * approachRateFactor;
double approachRateBonus = 1.0 + (0.03 + 0.37 * approachRateTotalHitsFactor) * approachRateFactor;

// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
if (mods.Any(h => h is OsuModHidden))
aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);

double flashlightBonus = 1.0;

if (mods.Any(h => h is OsuModFlashlight))
{
// Apply object-based bonus for flashlight.
aimValue *= 1.0 + 0.35 * Math.Min(1.0, totalHits / 200.0) +
(totalHits > 200
? 0.3 * Math.Min(1.0, (totalHits - 200) / 300.0) +
(totalHits > 500 ? (totalHits - 500) / 1200.0 : 0.0)
: 0.0);
flashlightBonus = 1.0 + 0.35 * Math.Min(1.0, totalHits / 200.0) +
(totalHits > 200
? 0.3 * Math.Min(1.0, (totalHits - 200) / 300.0) +
(totalHits > 500 ? (totalHits - 500) / 1200.0 : 0.0)
: 0.0);
}

aimValue *= Math.Max(flashlightBonus, approachRateBonus);

// Scale the aim value with accuracy _slightly_
aimValue *= 0.5 + accuracy / 2.0;
// It is important to also consider accuracy difficulty when doing that
Expand Down
5 changes: 2 additions & 3 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Objects;
Expand All @@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
/// <summary>
/// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
/// </summary>
public class Aim : StrainSkill
public class Aim : OsuStrainSkill
{
private const double angle_bonus_begin = Math.PI / 3;
private const double timing_threshold = 107;
Expand Down Expand Up @@ -47,7 +46,7 @@ protected override double StrainValueOf(DifficultyHitObject current)
Math.Max(osuPrevious.JumpDistance - scale, 0)
* Math.Pow(Math.Sin(osuCurrent.Angle.Value - angle_bonus_begin), 2)
* Math.Max(osuCurrent.JumpDistance - scale, 0));
result = 1.5 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime);
result = 1.4 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime);
}
}

Expand Down
61 changes: 61 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
using System.Linq;
using osu.Framework.Utils;

namespace osu.Game.Rulesets.Osu.Difficulty.Skills
{
public abstract class OsuStrainSkill : StrainSkill
{
/// <summary>
/// The number of sections with the highest strains, which the peak strain reductions will apply to.
/// This is done in order to decrease their impact on the overall difficulty of the map for this skill.
/// </summary>
protected virtual int ReducedSectionCount => 10;

/// <summary>
/// The baseline multiplier applied to the section with the biggest strain.
/// </summary>
protected virtual double ReducedStrainBaseline => 0.75;

/// <summary>
/// The final multiplier to be applied to <see cref="DifficultyValue"/> after all other calculations.
/// </summary>
protected virtual double DifficultyMultiplier => 1.06;

protected OsuStrainSkill(Mod[] mods)
: base(mods)
{
}

public override double DifficultyValue()
{
double difficulty = 0;
double weight = 1;

List<double> strains = GetCurrentStrainPeaks().OrderByDescending(d => d).ToList();

// We are reducing the highest strains first to account for extreme difficulty spikes
for (int i = 0; i < Math.Min(strains.Count, ReducedSectionCount); i++)
{
double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((float)i / ReducedSectionCount, 0, 1)));
strains[i] *= Interpolation.Lerp(ReducedStrainBaseline, 1.0, scale);
}

// Difficulty is the weighted sum of the highest strains from every section.
// We're sorting from highest to lowest strain.
foreach (double strain in strains.OrderByDescending(d => d))
{
difficulty += strain * weight;
weight *= DecayWeight;
}

return difficulty * DifficultyMultiplier;
}
}
}
5 changes: 3 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Objects;
Expand All @@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
/// <summary>
/// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
/// </summary>
public class Speed : StrainSkill
public class Speed : OsuStrainSkill
{
private const double single_spacing_threshold = 125;

Expand All @@ -23,6 +22,8 @@ public class Speed : StrainSkill

protected override double SkillMultiplier => 1400;
protected override double StrainDecayBase => 0.3;
protected override int ReducedSectionCount => 5;
protected override double DifficultyMultiplier => 1.04;

private const double min_speed_bonus = 75; // ~200BPM
private const double max_speed_bonus = 45; // ~330BPM
Expand Down
2 changes: 1 addition & 1 deletion osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private void startNewSectionFrom(double time)
/// <summary>
/// Returns the calculated difficulty value representing all <see cref="DifficultyHitObject"/>s that have been processed up to this point.
/// </summary>
public sealed override double DifficultyValue()
public override double DifficultyValue()
{
double difficulty = 0;
double weight = 1;
Expand Down

0 comments on commit cde8ae6

Please sign in to comment.