mirror of
https://github.com/ppy/osu.git
synced 2025-02-12 23:53:21 +08:00
ported CSR correctly
This commit is contained in:
parent
7f3093ee49
commit
e72ae6d9ae
@ -70,6 +70,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
[JsonProperty("speed_difficult_strain_count")]
|
[JsonProperty("speed_difficult_strain_count")]
|
||||||
public double SpeedDifficultStrainCount { get; set; }
|
public double SpeedDifficultStrainCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("low_ar_difficult_strain_count")]
|
||||||
|
public double LowArDifficultStrainCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("hidden_difficult_strain_count")]
|
||||||
|
public double HiddenDifficultStrainCount { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
|
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -51,11 +51,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
|
double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;
|
||||||
|
|
||||||
|
double hiddenDifficultyStrainCount = 0;
|
||||||
double baseReadingHiddenPerformance = 0.0;
|
double baseReadingHiddenPerformance = 0.0;
|
||||||
if (mods.Any(h => h is OsuModHidden))
|
if (mods.Any(h => h is OsuModHidden))
|
||||||
{
|
{
|
||||||
hiddenRating = Math.Sqrt(skills[6].DifficultyValue()) * DIFFICULTY_MULTIPLIER;
|
hiddenRating = Math.Sqrt(skills[6].DifficultyValue()) * DIFFICULTY_MULTIPLIER;
|
||||||
baseReadingHiddenPerformance = ReadingHidden.DifficultyToPerformance(hiddenRating);
|
baseReadingHiddenPerformance = ReadingHidden.DifficultyToPerformance(hiddenRating);
|
||||||
|
hiddenDifficultyStrainCount = skills[5].CountDifficultStrains();
|
||||||
}
|
}
|
||||||
|
|
||||||
double baseFlashlightPerformance = 0.0;
|
double baseFlashlightPerformance = 0.0;
|
||||||
@ -63,8 +65,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating);
|
baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating);
|
||||||
}
|
}
|
||||||
double aimDifficultyStrainCount = ((OsuStrainSkill)skills[0]).CountDifficultStrains();
|
|
||||||
double speedDifficultyStrainCount = ((OsuStrainSkill)skills[2]).CountDifficultStrains();
|
double aimDifficultyStrainCount = skills[0].CountDifficultStrains();
|
||||||
|
double speedDifficultyStrainCount = skills[2].CountDifficultStrains();
|
||||||
|
double lowArDifficultyStrainCount = skills[4].CountDifficultStrains();
|
||||||
|
|
||||||
if (mods.Any(m => m is OsuModTouchDevice))
|
if (mods.Any(m => m is OsuModTouchDevice))
|
||||||
{
|
{
|
||||||
@ -135,13 +139,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
SliderFactor = sliderFactor,
|
SliderFactor = sliderFactor,
|
||||||
AimDifficultStrainCount = aimDifficultyStrainCount,
|
AimDifficultStrainCount = aimDifficultyStrainCount,
|
||||||
SpeedDifficultStrainCount = speedDifficultyStrainCount,
|
SpeedDifficultStrainCount = speedDifficultyStrainCount,
|
||||||
|
LowArDifficultStrainCount = lowArDifficultyStrainCount,
|
||||||
|
HiddenDifficultStrainCount = hiddenDifficultyStrainCount,
|
||||||
ApproachRate = IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, 1800, 1200, 450),
|
ApproachRate = IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, 1800, 1200, 450),
|
||||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||||
DrainRate = drainRate,
|
DrainRate = drainRate,
|
||||||
MaxCombo = beatmap.GetMaxCombo(),
|
MaxCombo = beatmap.GetMaxCombo(),
|
||||||
HitCircleCount = hitCirclesCount,
|
HitCircleCount = hitCirclesCount,
|
||||||
SliderCount = sliderCount,
|
SliderCount = sliderCount,
|
||||||
SpinnerCount = spinnerCount,
|
SpinnerCount = spinnerCount
|
||||||
};
|
};
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
|
@ -216,6 +216,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
if (!usingClassicSliderAccuracy)
|
if (!usingClassicSliderAccuracy)
|
||||||
amountHitObjectsWithAccuracy += attributes.SliderCount;
|
amountHitObjectsWithAccuracy += attributes.SliderCount;
|
||||||
|
|
||||||
|
if (score.Mods.OfType<OsuModClassic>().All(m => !m.NoSliderHeadAccuracy.Value))
|
||||||
|
amountHitObjectsWithAccuracy += attributes.SliderCount;
|
||||||
|
|
||||||
if (amountHitObjectsWithAccuracy > 0)
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
||||||
else
|
else
|
||||||
@ -289,9 +292,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||||
if (effectiveMissCount > 0)
|
if (effectiveMissCount > 0)
|
||||||
readingValue *= 0.97 * Math.Pow(1 - Math.Pow(effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
|
readingValue *= calculateMissPenalty(effectiveMissCount, attributes.LowArDifficultStrainCount);
|
||||||
|
|
||||||
readingValue *= getComboScalingFactor(attributes);
|
|
||||||
|
|
||||||
// Scale the reading value with accuracy _harshly_. Additional note: it would have it's own curve in Statistical Accuracy rework.
|
// Scale the reading value with accuracy _harshly_. Additional note: it would have it's own curve in Statistical Accuracy rework.
|
||||||
readingValue *= accuracy * accuracy;
|
readingValue *= accuracy * accuracy;
|
||||||
@ -305,12 +306,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
double highARValue = OsuStrainSkill.DifficultyToPerformance(attributes.ReadingDifficultyHighAR);
|
double highARValue = OsuStrainSkill.DifficultyToPerformance(attributes.ReadingDifficultyHighAR);
|
||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
|
||||||
if (effectiveMissCount > 0)
|
|
||||||
highARValue *= 0.97 * Math.Pow(1 - Math.Pow(effectiveMissCount / totalHits, 0.775), effectiveMissCount);
|
|
||||||
|
|
||||||
highARValue *= getComboScalingFactor(attributes);
|
|
||||||
|
|
||||||
// Approximate how much of high AR difficulty is aim
|
// Approximate how much of high AR difficulty is aim
|
||||||
double aimPerformance = OsuStrainSkill.DifficultyToPerformance(attributes.AimDifficulty);
|
double aimPerformance = OsuStrainSkill.DifficultyToPerformance(attributes.AimDifficulty);
|
||||||
double speedPerformance = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty);
|
double speedPerformance = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty);
|
||||||
@ -330,6 +325,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimPartValue *= sliderNerfFactor;
|
aimPartValue *= sliderNerfFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (effectiveMissCount > 0)
|
||||||
|
aimPartValue *= calculateMissPenalty(effectiveMissCount, attributes.AimDifficultStrainCount);
|
||||||
|
|
||||||
aimPartValue *= accuracy;
|
aimPartValue *= accuracy;
|
||||||
// It is important to consider accuracy difficulty when scaling with accuracy.
|
// It is important to consider accuracy difficulty when scaling with accuracy.
|
||||||
aimPartValue *= 0.98 + Math.Pow(attributes.OverallDifficulty, 2) / 2500;
|
aimPartValue *= 0.98 + Math.Pow(attributes.OverallDifficulty, 2) / 2500;
|
||||||
@ -345,6 +343,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
double relevantCountMeh = Math.Max(0, countMeh - Math.Max(0, relevantTotalDiff - countGreat - countOk));
|
double relevantCountMeh = Math.Max(0, countMeh - Math.Max(0, relevantTotalDiff - countGreat - countOk));
|
||||||
double relevantAccuracy = attributes.SpeedNoteCount == 0 ? 0 : (relevantCountGreat * 6.0 + relevantCountOk * 2.0 + relevantCountMeh) / (attributes.SpeedNoteCount * 6.0);
|
double relevantAccuracy = attributes.SpeedNoteCount == 0 ? 0 : (relevantCountGreat * 6.0 + relevantCountOk * 2.0 + relevantCountMeh) / (attributes.SpeedNoteCount * 6.0);
|
||||||
|
|
||||||
|
if (effectiveMissCount > 0)
|
||||||
|
speedPartValue *= calculateMissPenalty(effectiveMissCount, attributes.SpeedDifficultStrainCount);
|
||||||
|
|
||||||
// Scale the speed value with accuracy and OD.
|
// Scale the speed value with accuracy and OD.
|
||||||
speedPartValue *= (0.95 + Math.Pow(attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(attributes.OverallDifficulty, 8)) / 2);
|
speedPartValue *= (0.95 + Math.Pow(attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(attributes.OverallDifficulty, 8)) / 2);
|
||||||
|
|
||||||
@ -365,11 +366,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
double lengthBonus = CalculateDefaultLengthBonus(totalHits);
|
double lengthBonus = CalculateDefaultLengthBonus(totalHits);
|
||||||
hiddenValue *= lengthBonus;
|
hiddenValue *= lengthBonus;
|
||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
|
||||||
if (effectiveMissCount > 0)
|
if (effectiveMissCount > 0)
|
||||||
hiddenValue *= 0.97 * Math.Pow(1 - Math.Pow(effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
|
hiddenValue *= calculateMissPenalty(effectiveMissCount, attributes.HiddenDifficultStrainCount);
|
||||||
|
|
||||||
hiddenValue *= getComboScalingFactor(attributes);
|
|
||||||
|
|
||||||
// Scale the reading value with accuracy _harshly_. Additional note: it would have it's own curve in Statistical Accuracy rework.
|
// Scale the reading value with accuracy _harshly_. Additional note: it would have it's own curve in Statistical Accuracy rework.
|
||||||
hiddenValue *= accuracy * accuracy;
|
hiddenValue *= accuracy * accuracy;
|
||||||
@ -442,13 +440,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return 1 + result;
|
return 1 + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Miss penalty assumes that a player will miss on the hardest parts of a map,
|
|
||||||
// so we use the amount of relatively difficult sections to adjust miss penalty
|
|
||||||
// to make it more punishing on maps with lower amount of hard sections.
|
|
||||||
private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.96 / ((missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94))) + 1);
|
|
||||||
private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0);
|
|
||||||
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
|
||||||
|
|
||||||
// Limits reading difficulty by the difficulty of full-memorisation (assumed to be mechanicalPerformance + flashlightPerformance + 25)
|
// Limits reading difficulty by the difficulty of full-memorisation (assumed to be mechanicalPerformance + flashlightPerformance + 25)
|
||||||
// Desmos graph assuming that x = cognitionPerformance, while y = mechanicalPerformance + flaslightPerformance
|
// Desmos graph assuming that x = cognitionPerformance, while y = mechanicalPerformance + flaslightPerformance
|
||||||
// https://www.desmos.com/3d/vjygrxtkqs
|
// https://www.desmos.com/3d/vjygrxtkqs
|
||||||
@ -464,7 +455,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return ratio * capPerformance;
|
return ratio * capPerformance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Miss penalty assumes that a player will miss on the hardest parts of a map,
|
||||||
|
// so we use the amount of relatively difficult sections to adjust miss penalty
|
||||||
|
// to make it more punishing on maps with lower amount of hard sections.
|
||||||
|
private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.96 / ((missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94))) + 1);
|
||||||
|
|
||||||
|
private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
private static double softmin(double a, double b, double power = Math.E) => a * b / Math.Log(Math.Pow(power, a) + Math.Pow(power, b), power);
|
private static double softmin(double a, double b, double power = Math.E) => a * b / Math.Log(Math.Pow(power, a) + Math.Pow(power, b), power);
|
||||||
|
|
||||||
private static double logistic(double x) => 1 / (1 + Math.Exp(-x));
|
private static double logistic(double x) => 1 / (1 + Math.Exp(-x));
|
||||||
|
|
||||||
|
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
{
|
{
|
||||||
CurrentStrain *= StrainDecay(current.DeltaTime);
|
CurrentStrain *= StrainDecay(current.DeltaTime);
|
||||||
CurrentStrain += AimEvaluator.EvaluateDifficultyOf(current, withSliders) * SkillMultiplier;
|
CurrentStrain += AimEvaluator.EvaluateDifficultyOf(current, withSliders) * SkillMultiplier;
|
||||||
ObjectStrains.Add(currentStrain);
|
ObjectStrains.Add(CurrentStrain);
|
||||||
|
|
||||||
return CurrentStrain;
|
return CurrentStrain;
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
protected virtual double StrainDecayBase => 0.15;
|
protected virtual double StrainDecayBase => 0.15;
|
||||||
|
|
||||||
protected double StrainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
|
protected double StrainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
|
||||||
protected List<double> ObjectStrains = new List<double>();
|
|
||||||
protected double Difficulty;
|
|
||||||
|
|
||||||
protected OsuStrainSkill(Mod[] mods)
|
protected OsuStrainSkill(Mod[] mods)
|
||||||
: base(mods)
|
: base(mods)
|
||||||
@ -63,20 +61,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
return Difficulty;
|
return Difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the number of strains weighted against the top strain.
|
|
||||||
/// The result is scaled by clock rate as it affects the total number of strains.
|
|
||||||
/// </summary>
|
|
||||||
public double CountDifficultStrains()
|
|
||||||
{
|
|
||||||
if (Difficulty == 0)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
double consistentTopStrain = Difficulty / 10; // What would the top strain be if all strain values were identical
|
|
||||||
// Use a weighted sum of all strains. Constants are arbitrary and give nice values
|
|
||||||
return ObjectStrains.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts difficulty value from <see cref="OsuDifficultyAttributes"/> to base performance.
|
/// Converts difficulty value from <see cref="OsuDifficultyAttributes"/> to base performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
{
|
{
|
||||||
public class ReadingLowAR : GraphSkill
|
public class ReadingLowAR : GraphSkill
|
||||||
{
|
{
|
||||||
private readonly List<double> difficulties = new List<double>();
|
|
||||||
private double skillMultiplier => 1.23;
|
private double skillMultiplier => 1.23;
|
||||||
private double aimComponentMultiplier => 0.4;
|
private double aimComponentMultiplier => 0.4;
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
|
|
||||||
double totalDensityDifficulty = (currentDensityAimStrain + densityReadingDifficulty) * skillMultiplier;
|
double totalDensityDifficulty = (currentDensityAimStrain + densityReadingDifficulty) * skillMultiplier;
|
||||||
|
|
||||||
difficulties.Add(totalDensityDifficulty);
|
ObjectStrains.Add(totalDensityDifficulty);
|
||||||
|
|
||||||
if (current.Index == 0)
|
if (current.Index == 0)
|
||||||
CurrentSectionEnd = Math.Ceiling(current.StartTime / SectionLength) * SectionLength;
|
CurrentSectionEnd = Math.Ceiling(current.StartTime / SectionLength) * SectionLength;
|
||||||
@ -59,11 +58,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
private double reducedNoteBaseline => 0.7;
|
private double reducedNoteBaseline => 0.7;
|
||||||
public override double DifficultyValue()
|
public override double DifficultyValue()
|
||||||
{
|
{
|
||||||
double difficulty = 0;
|
|
||||||
|
|
||||||
// Sections with 0 difficulty are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
// Sections with 0 difficulty are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
||||||
// These sections will not contribute to the difficulty.
|
// These sections will not contribute to the difficulty.
|
||||||
var peaks = difficulties.Where(p => p > 0);
|
var peaks = ObjectStrains.Where(p => p > 0);
|
||||||
|
|
||||||
List<double> values = peaks.OrderByDescending(d => d).ToList();
|
List<double> values = peaks.OrderByDescending(d => d).ToList();
|
||||||
|
|
||||||
@ -75,14 +72,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
|
|
||||||
values = values.OrderByDescending(d => d).ToList();
|
values = values.OrderByDescending(d => d).ToList();
|
||||||
|
|
||||||
|
Difficulty = 0;
|
||||||
|
|
||||||
// Difficulty is the weighted sum of the highest strains from every section.
|
// Difficulty is the weighted sum of the highest strains from every section.
|
||||||
// We're sorting from highest to lowest strain.
|
// We're sorting from highest to lowest strain.
|
||||||
for (int i = 0; i < values.Count; i++)
|
for (int i = 0; i < values.Count; i++)
|
||||||
{
|
{
|
||||||
difficulty += values[i] / (i + 1);
|
Difficulty += values[i] / (i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return difficulty;
|
return Difficulty;
|
||||||
}
|
}
|
||||||
public static double DifficultyToPerformance(double difficulty) => Math.Max(
|
public static double DifficultyToPerformance(double difficulty) => Math.Max(
|
||||||
Math.Max(Math.Pow(difficulty, 1.5) * 20, Math.Pow(difficulty, 2) * 17.0),
|
Math.Max(Math.Pow(difficulty, 1.5) * 20, Math.Pow(difficulty, 2) * 17.0),
|
||||||
@ -95,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
: base(mods, false)
|
: base(mods, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
protected new double SkillMultiplier => 7.2;
|
protected new double SkillMultiplier => 7.632;
|
||||||
|
|
||||||
protected override double StrainValueAt(DifficultyHitObject current)
|
protected override double StrainValueAt(DifficultyHitObject current)
|
||||||
{
|
{
|
||||||
@ -107,6 +106,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
hiddenDifficulty *= SkillMultiplier;
|
hiddenDifficulty *= SkillMultiplier;
|
||||||
|
|
||||||
CurrentStrain += hiddenDifficulty;
|
CurrentStrain += hiddenDifficulty;
|
||||||
|
ObjectStrains.Add(CurrentStrain);
|
||||||
|
|
||||||
return CurrentStrain;
|
return CurrentStrain;
|
||||||
}
|
}
|
||||||
@ -204,8 +204,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
double adjustedDifficulty = performanceToDifficulty(totalPerformance);
|
double adjustedDifficulty = performanceToDifficulty(totalPerformance);
|
||||||
double difficultyValue = Math.Pow(adjustedDifficulty / OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER, 2.0);
|
double difficultyValue = Math.Pow(adjustedDifficulty / OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER, 2.0);
|
||||||
|
|
||||||
|
Difficulty = skill_multiplier * Math.Pow(difficultyValue, MECHANICAL_PP_POWER);
|
||||||
|
|
||||||
// Sqrt value to make difficulty depend less on mechanical difficulty
|
// Sqrt value to make difficulty depend less on mechanical difficulty
|
||||||
return skill_multiplier * Math.Pow(difficultyValue, MECHANICAL_PP_POWER);
|
return Difficulty;
|
||||||
}
|
}
|
||||||
public class HighARAimComponent : Aim
|
public class HighARAimComponent : Aim
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
@ -27,6 +29,9 @@ namespace osu.Game.Rulesets.Difficulty.Skills
|
|||||||
this.mods = mods;
|
this.mods = mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<double> ObjectStrains = new List<double>();
|
||||||
|
protected double Difficulty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process a <see cref="DifficultyHitObject"/>.
|
/// Process a <see cref="DifficultyHitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -37,5 +42,19 @@ namespace osu.Game.Rulesets.Difficulty.Skills
|
|||||||
/// Returns the calculated difficulty value representing all <see cref="DifficultyHitObject"/>s that have been processed up to this point.
|
/// Returns the calculated difficulty value representing all <see cref="DifficultyHitObject"/>s that have been processed up to this point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract double DifficultyValue();
|
public abstract double DifficultyValue();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the number of strains weighted against the top strain.
|
||||||
|
/// The result is scaled by clock rate as it affects the total number of strains.
|
||||||
|
/// </summary>
|
||||||
|
public double CountDifficultStrains()
|
||||||
|
{
|
||||||
|
if (Difficulty == 0)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
double consistentTopStrain = Difficulty / 10; // What would the top strain be if all strain values were identical
|
||||||
|
// Use a weighted sum of all strains. Constants are arbitrary and give nice values
|
||||||
|
return ObjectStrains.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user