mirror of https://github.com/ppy/osu
Merge pull request #15564 from apollo-dw/sliderend-sr
Nerf dropped sliders in osu! difficulty calculation
This commit is contained in:
commit
a76247603f
|
@ -15,13 +15,13 @@ public class OsuDifficultyCalculatorTest : DifficultyCalculatorTest
|
|||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||
|
||||
[TestCase(6.6975550434910005d, "diffcalc-test")]
|
||||
[TestCase(1.4670676815251105d, "zero-length-sliders")]
|
||||
[TestCase(6.6972307565739273d, "diffcalc-test")]
|
||||
[TestCase(1.4484754139145539d, "zero-length-sliders")]
|
||||
public void Test(double expected, string name)
|
||||
=> base.Test(expected, name);
|
||||
|
||||
[TestCase(8.9389769779826267d, "diffcalc-test")]
|
||||
[TestCase(1.7786917985891204d, "zero-length-sliders")]
|
||||
[TestCase(8.9382559208689809d, "diffcalc-test")]
|
||||
[TestCase(1.7548875851757628d, "zero-length-sliders")]
|
||||
public void TestClockRateAdjusted(double expected, string name)
|
||||
=> Test(expected, name, new OsuModDoubleTime());
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ public class OsuDifficultyAttributes : DifficultyAttributes
|
|||
public double AimStrain { get; set; }
|
||||
public double SpeedStrain { get; set; }
|
||||
public double FlashlightRating { get; set; }
|
||||
public double SliderFactor { get; set; }
|
||||
public double ApproachRate { get; set; }
|
||||
public double OverallDifficulty { get; set; }
|
||||
public double DrainRate { get; set; }
|
||||
|
|
|
@ -34,8 +34,11 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
|
|||
return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
|
||||
|
||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||
double flashlightRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
|
||||
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
|
||||
double flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;
|
||||
|
||||
double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
|
||||
|
||||
if (mods.Any(h => h is OsuModRelax))
|
||||
speedRating = 0.0;
|
||||
|
@ -74,6 +77,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
|
|||
AimStrain = aimRating,
|
||||
SpeedStrain = speedRating,
|
||||
FlashlightRating = flashlightRating,
|
||||
SliderFactor = sliderFactor,
|
||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||
DrainRate = drainRate,
|
||||
|
@ -108,7 +112,8 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo
|
|||
|
||||
return new Skill[]
|
||||
{
|
||||
new Aim(mods),
|
||||
new Aim(mods, true),
|
||||
new Aim(mods, false),
|
||||
new Speed(mods, hitWindowGreat),
|
||||
new Flashlight(mods)
|
||||
};
|
||||
|
|
|
@ -125,6 +125,16 @@ private double computeAimValue()
|
|||
aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);
|
||||
}
|
||||
|
||||
// We assume 15% of sliders in a map are difficult since there's no way to tell from the performance calculator.
|
||||
double estimateDifficultSliders = Attributes.SliderCount * 0.15;
|
||||
|
||||
if (Attributes.SliderCount > 0)
|
||||
{
|
||||
double estimateSliderEndsDropped = Math.Clamp(Math.Min(countOk + countMeh + countMiss, Attributes.MaxCombo - scoreMaxCombo), 0, estimateDifficultSliders);
|
||||
double sliderNerfFactor = (1 - Attributes.SliderFactor) * Math.Pow(1 - estimateSliderEndsDropped / estimateDifficultSliders, 3) + Attributes.SliderFactor;
|
||||
aimValue *= sliderNerfFactor;
|
||||
}
|
||||
|
||||
aimValue *= accuracy;
|
||||
// It is important to also consider accuracy difficulty when doing that.
|
||||
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
|
||||
|
|
|
@ -14,7 +14,7 @@ public class OsuDifficultyHitObject : DifficultyHitObject
|
|||
private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||
private const int min_delta_time = 25;
|
||||
private const float maximum_slider_radius = normalized_radius * 2.4f;
|
||||
private const float assumed_slider_radius = normalized_radius * 1.65f;
|
||||
private const float assumed_slider_radius = normalized_radius * 1.8f;
|
||||
|
||||
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
||||
|
||||
|
|
|
@ -14,11 +14,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||
/// </summary>
|
||||
public class Aim : OsuStrainSkill
|
||||
{
|
||||
public Aim(Mod[] mods)
|
||||
public Aim(Mod[] mods, bool withSliders)
|
||||
: base(mods)
|
||||
{
|
||||
this.withSliders = withSliders;
|
||||
}
|
||||
|
||||
private readonly bool withSliders;
|
||||
|
||||
protected override int HistoryLength => 2;
|
||||
|
||||
private const double wide_angle_multiplier = 1.5;
|
||||
|
@ -44,7 +47,7 @@ private double strainValueOf(DifficultyHitObject current)
|
|||
double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
|
||||
|
||||
// But if the last object is a slider, then we extend the travel velocity through the slider into the current object.
|
||||
if (osuLastObj.BaseObject is Slider)
|
||||
if (osuLastObj.BaseObject is Slider && withSliders)
|
||||
{
|
||||
double movementVelocity = osuCurrObj.MovementDistance / osuCurrObj.MovementTime; // calculate the movement velocity from slider end to current object
|
||||
double travelVelocity = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // calculate the slider velocity from slider head to slider end.
|
||||
|
@ -55,7 +58,7 @@ private double strainValueOf(DifficultyHitObject current)
|
|||
// As above, do the same for the previous hitobject.
|
||||
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
|
||||
|
||||
if (osuLastLastObj.BaseObject is Slider)
|
||||
if (osuLastLastObj.BaseObject is Slider && withSliders)
|
||||
{
|
||||
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
|
||||
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
||||
|
@ -135,7 +138,8 @@ private double strainValueOf(DifficultyHitObject current)
|
|||
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
|
||||
|
||||
// Add in additional slider velocity bonus.
|
||||
aimStrain += sliderBonus * slider_multiplier;
|
||||
if (withSliders)
|
||||
aimStrain += sliderBonus * slider_multiplier;
|
||||
|
||||
return aimStrain;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue