1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 07:42:57 +08:00

Move osu! difficulty attributes to OsuDifficultyCalculator

This commit is contained in:
smoogipoo 2018-06-14 16:27:05 +09:00
parent 01dd2d7919
commit 41abd5990c
3 changed files with 26 additions and 29 deletions

View File

@ -10,6 +10,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{ {
public double AimStrain; public double AimStrain;
public double SpeedStrain; public double SpeedStrain;
public double ApproachRate;
public double OverallDifficulty;
public int MaxCombo;
public OsuDifficultyAttributes(Mod[] mods, double starRating) public OsuDifficultyAttributes(Mod[] mods, double starRating)
: base(mods, starRating) : base(mods, starRating)

View File

@ -58,10 +58,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
int maxCombo = beatmap.HitObjects.Count();
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
return new OsuDifficultyAttributes(mods, starRating) return new OsuDifficultyAttributes(mods, starRating)
{ {
AimStrain = aimRating, AimStrain = aimRating,
SpeedStrain = speedRating SpeedStrain = speedRating,
ApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
MaxCombo = maxCombo
}; };
} }

View File

@ -22,16 +22,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private Mod[] mods; private Mod[] mods;
/// <summary>
/// Approach rate adjusted by mods.
/// </summary>
private double realApproachRate;
/// <summary>
/// Overall difficulty adjusted by mods.
/// </summary>
private double realOverallDifficulty;
private double accuracy; private double accuracy;
private int scoreMaxCombo; private int scoreMaxCombo;
private int countGreat; private int countGreat;
@ -63,13 +53,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (mods.Any(m => !m.Ranked)) if (mods.Any(m => !m.Ranked))
return 0; return 0;
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate;
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
realOverallDifficulty = (80 - hitWindowGreat) / 6;
// Custom multipliers for NoFail and SpunOut. // Custom multipliers for NoFail and SpunOut.
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
@ -94,8 +77,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
categoryRatings.Add("Aim", aimValue); categoryRatings.Add("Aim", aimValue);
categoryRatings.Add("Speed", speedValue); categoryRatings.Add("Speed", speedValue);
categoryRatings.Add("Accuracy", accuracyValue); categoryRatings.Add("Accuracy", accuracyValue);
categoryRatings.Add("OD", realOverallDifficulty); categoryRatings.Add("OD", Attributes.OverallDifficulty);
categoryRatings.Add("AR", realApproachRate); categoryRatings.Add("AR", Attributes.ApproachRate);
categoryRatings.Add("Max Combo", beatmapMaxCombo); categoryRatings.Add("Max Combo", beatmapMaxCombo);
} }
@ -120,22 +103,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f); aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
double approachRateFactor = 1.0f; double approachRateFactor = 1.0f;
if (realApproachRate > 10.33f) if (Attributes.ApproachRate > 10.33f)
approachRateFactor += 0.45f * (realApproachRate - 10.33f); approachRateFactor += 0.45f * (Attributes.ApproachRate - 10.33f);
else if (realApproachRate < 8.0f) else if (Attributes.ApproachRate < 8.0f)
{ {
// HD is worth more with lower ar! // HD is worth more with lower ar!
if (mods.Any(h => h is OsuModHidden)) if (mods.Any(h => h is OsuModHidden))
approachRateFactor += 0.02f * (8.0f - realApproachRate); approachRateFactor += 0.02f * (8.0f - Attributes.ApproachRate);
else else
approachRateFactor += 0.01f * (8.0f - realApproachRate); approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate);
} }
aimValue *= approachRateFactor; aimValue *= 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. // 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)) if (mods.Any(h => h is OsuModHidden))
aimValue *= 1.02 + (11.0f - realApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11. aimValue *= 1.02 + (11.0f - Attributes.ApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11.
if (mods.Any(h => h is OsuModFlashlight)) if (mods.Any(h => h is OsuModFlashlight))
{ {
@ -146,7 +129,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
// Scale the aim value with accuracy _slightly_ // Scale the aim value with accuracy _slightly_
aimValue *= 0.5f + accuracy / 2.0f; aimValue *= 0.5f + accuracy / 2.0f;
// It is important to also consider accuracy difficulty when doing that // It is important to also consider accuracy difficulty when doing that
aimValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500; aimValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
return aimValue; return aimValue;
} }
@ -172,7 +155,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
// Scale the speed value with accuracy _slightly_ // Scale the speed value with accuracy _slightly_
speedValue *= 0.5f + accuracy / 2.0f; speedValue *= 0.5f + accuracy / 2.0f;
// It is important to also consider accuracy difficulty when doing that // It is important to also consider accuracy difficulty when doing that
speedValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500; speedValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
return speedValue; return speedValue;
} }
@ -194,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
// Lots of arbitrary values from testing. // Lots of arbitrary values from testing.
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
double accuracyValue = Math.Pow(1.52163f, realOverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f; double accuracyValue = Math.Pow(1.52163f, Attributes.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer // Bonus for many hitcircles - it's harder to keep good accuracy up for longer
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f)); accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));