mirror of
https://github.com/osukey/osukey.git
synced 2025-06-25 05:07:59 +09:00
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 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
[TestCase(6.6975550434910005d, "diffcalc-test")]
|
[TestCase(6.6972307565739273d, "diffcalc-test")]
|
||||||
[TestCase(1.4670676815251105d, "zero-length-sliders")]
|
[TestCase(1.4484754139145539d, "zero-length-sliders")]
|
||||||
public void Test(double expected, string name)
|
public void Test(double expected, string name)
|
||||||
=> base.Test(expected, name);
|
=> base.Test(expected, name);
|
||||||
|
|
||||||
[TestCase(8.9389769779826267d, "diffcalc-test")]
|
[TestCase(8.9382559208689809d, "diffcalc-test")]
|
||||||
[TestCase(1.7786917985891204d, "zero-length-sliders")]
|
[TestCase(1.7548875851757628d, "zero-length-sliders")]
|
||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new OsuModDoubleTime());
|
=> Test(expected, name, new OsuModDoubleTime());
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
public double AimStrain { get; set; }
|
public double AimStrain { get; set; }
|
||||||
public double SpeedStrain { get; set; }
|
public double SpeedStrain { get; set; }
|
||||||
public double FlashlightRating { get; set; }
|
public double FlashlightRating { get; set; }
|
||||||
|
public double SliderFactor { get; set; }
|
||||||
public double ApproachRate { get; set; }
|
public double ApproachRate { get; set; }
|
||||||
public double OverallDifficulty { get; set; }
|
public double OverallDifficulty { get; set; }
|
||||||
public double DrainRate { get; set; }
|
public double DrainRate { get; set; }
|
||||||
|
@ -34,8 +34,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
|
return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
|
||||||
|
|
||||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||||
double flashlightRating = Math.Sqrt(skills[2].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))
|
if (mods.Any(h => h is OsuModRelax))
|
||||||
speedRating = 0.0;
|
speedRating = 0.0;
|
||||||
@ -74,6 +77,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
AimStrain = aimRating,
|
AimStrain = aimRating,
|
||||||
SpeedStrain = speedRating,
|
SpeedStrain = speedRating,
|
||||||
FlashlightRating = flashlightRating,
|
FlashlightRating = flashlightRating,
|
||||||
|
SliderFactor = sliderFactor,
|
||||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||||
DrainRate = drainRate,
|
DrainRate = drainRate,
|
||||||
@ -108,7 +112,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
return new Skill[]
|
return new Skill[]
|
||||||
{
|
{
|
||||||
new Aim(mods),
|
new Aim(mods, true),
|
||||||
|
new Aim(mods, false),
|
||||||
new Speed(mods, hitWindowGreat),
|
new Speed(mods, hitWindowGreat),
|
||||||
new Flashlight(mods)
|
new Flashlight(mods)
|
||||||
};
|
};
|
||||||
|
@ -125,6 +125,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);
|
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;
|
aimValue *= accuracy;
|
||||||
// It is important to also consider accuracy difficulty when doing that.
|
// It is important to also consider accuracy difficulty when doing that.
|
||||||
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
|
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
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 int min_delta_time = 25;
|
||||||
private const float maximum_slider_radius = normalized_radius * 2.4f;
|
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;
|
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
||||||
|
|
||||||
|
@ -14,11 +14,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Aim : OsuStrainSkill
|
public class Aim : OsuStrainSkill
|
||||||
{
|
{
|
||||||
public Aim(Mod[] mods)
|
public Aim(Mod[] mods, bool withSliders)
|
||||||
: base(mods)
|
: base(mods)
|
||||||
{
|
{
|
||||||
|
this.withSliders = withSliders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly bool withSliders;
|
||||||
|
|
||||||
protected override int HistoryLength => 2;
|
protected override int HistoryLength => 2;
|
||||||
|
|
||||||
private const double wide_angle_multiplier = 1.5;
|
private const double wide_angle_multiplier = 1.5;
|
||||||
@ -44,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
|
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.
|
// 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 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.
|
double travelVelocity = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // calculate the slider velocity from slider head to slider end.
|
||||||
@ -55,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
// As above, do the same for the previous hitobject.
|
// As above, do the same for the previous hitobject.
|
||||||
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
|
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
|
||||||
|
|
||||||
if (osuLastLastObj.BaseObject is Slider)
|
if (osuLastLastObj.BaseObject is Slider && withSliders)
|
||||||
{
|
{
|
||||||
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
|
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
|
||||||
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
||||||
@ -135,7 +138,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
|
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier);
|
||||||
|
|
||||||
// Add in additional slider velocity bonus.
|
// Add in additional slider velocity bonus.
|
||||||
aimStrain += sliderBonus * slider_multiplier;
|
if (withSliders)
|
||||||
|
aimStrain += sliderBonus * slider_multiplier;
|
||||||
|
|
||||||
return aimStrain;
|
return aimStrain;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user