mirror of
https://github.com/osukey/osukey.git
synced 2025-05-24 23:17:25 +09:00
Slightly refactor difficulty and pp calculators
This commit is contained in:
parent
ed5d7046f3
commit
2f2006715e
@ -90,6 +90,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
if (mods.Any(m => m is ModNoFail))
|
if (mods.Any(m => m is ModNoFail))
|
||||||
value *= 0.90;
|
value *= 0.90;
|
||||||
|
|
||||||
|
if (categoryDifficulty != null)
|
||||||
|
{
|
||||||
|
categoryDifficulty.Add("AR", Attributes.ApproachRate);
|
||||||
|
categoryDifficulty.Add("Max Combo", Attributes.MaxCombo);
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
yield return v;
|
yield return v;
|
||||||
|
|
||||||
// Todo: osu!mania doesn't output MaxCombo attribute for some reason.
|
// Todo: osu!mania doesn't output MaxCombo attribute for some reason.
|
||||||
yield return (ATTRIB_ID_STRAIN, StarRating);
|
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
||||||
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||||
yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier);
|
yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier);
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
{
|
{
|
||||||
base.FromDatabaseAttributes(values);
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
StarRating = values[ATTRIB_ID_STRAIN];
|
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
||||||
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||||
ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER];
|
ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER];
|
||||||
}
|
}
|
||||||
|
@ -61,48 +61,51 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
if (mods.Any(m => m is ModEasy))
|
if (mods.Any(m => m is ModEasy))
|
||||||
multiplier *= 0.5;
|
multiplier *= 0.5;
|
||||||
|
|
||||||
double strainValue = computeStrainValue();
|
double difficultyValue = computeDifficultyValue();
|
||||||
double accValue = computeAccuracyValue(strainValue);
|
double accValue = computeAccuracyValue(difficultyValue);
|
||||||
double totalValue =
|
double totalValue =
|
||||||
Math.Pow(
|
Math.Pow(
|
||||||
Math.Pow(strainValue, 1.1) +
|
Math.Pow(difficultyValue, 1.1) +
|
||||||
Math.Pow(accValue, 1.1), 1.0 / 1.1
|
Math.Pow(accValue, 1.1), 1.0 / 1.1
|
||||||
) * multiplier;
|
) * multiplier;
|
||||||
|
|
||||||
if (categoryDifficulty != null)
|
if (categoryDifficulty != null)
|
||||||
{
|
{
|
||||||
categoryDifficulty["Strain"] = strainValue;
|
categoryDifficulty.Add("Difficulty", difficultyValue);
|
||||||
categoryDifficulty["Accuracy"] = accValue;
|
categoryDifficulty.Add("Accuracy", accValue);
|
||||||
|
categoryDifficulty.Add("Scaled Score", scaledScore);
|
||||||
|
categoryDifficulty.Add("Great Hit Window", Attributes.GreatHitWindow);
|
||||||
|
categoryDifficulty.Add("Max Combo", Attributes.MaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeStrainValue()
|
private double computeDifficultyValue()
|
||||||
{
|
{
|
||||||
// Obtain strain difficulty
|
// Obtain difficulty
|
||||||
double strainValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
|
double difficultyValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
|
||||||
|
|
||||||
// Longer maps are worth more
|
// Longer maps are worth more
|
||||||
strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
difficultyValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
||||||
|
|
||||||
if (scaledScore <= 500000)
|
if (scaledScore <= 500000)
|
||||||
strainValue = 0;
|
difficultyValue = 0;
|
||||||
else if (scaledScore <= 600000)
|
else if (scaledScore <= 600000)
|
||||||
strainValue *= (scaledScore - 500000) / 100000 * 0.3;
|
difficultyValue *= (scaledScore - 500000) / 100000 * 0.3;
|
||||||
else if (scaledScore <= 700000)
|
else if (scaledScore <= 700000)
|
||||||
strainValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
|
difficultyValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
|
||||||
else if (scaledScore <= 800000)
|
else if (scaledScore <= 800000)
|
||||||
strainValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
|
difficultyValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
|
||||||
else if (scaledScore <= 900000)
|
else if (scaledScore <= 900000)
|
||||||
strainValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
|
difficultyValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
|
||||||
else
|
else
|
||||||
strainValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
|
difficultyValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
|
||||||
|
|
||||||
return strainValue;
|
return difficultyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeAccuracyValue(double strainValue)
|
private double computeAccuracyValue(double difficultyValue)
|
||||||
{
|
{
|
||||||
if (Attributes.GreatHitWindow <= 0)
|
if (Attributes.GreatHitWindow <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -110,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.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.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667)
|
double accuracyValue = Math.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667)
|
||||||
* strainValue
|
* difficultyValue
|
||||||
* Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
|
* Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -12,14 +12,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
public class OsuDifficultyAttributes : DifficultyAttributes
|
public class OsuDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
[JsonProperty("aim_strain")]
|
[JsonProperty("aim_difficulty")]
|
||||||
public double AimStrain { get; set; }
|
public double AimDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonProperty("speed_strain")]
|
[JsonProperty("speed_difficulty")]
|
||||||
public double SpeedStrain { get; set; }
|
public double SpeedDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonProperty("flashlight_rating")]
|
[JsonProperty("flashlight_difficulty")]
|
||||||
public double FlashlightRating { get; set; }
|
public double FlashlightDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonProperty("slider_factor")]
|
[JsonProperty("slider_factor")]
|
||||||
public double SliderFactor { get; set; }
|
public double SliderFactor { get; set; }
|
||||||
@ -43,15 +43,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
foreach (var v in base.ToDatabaseAttributes())
|
foreach (var v in base.ToDatabaseAttributes())
|
||||||
yield return v;
|
yield return v;
|
||||||
|
|
||||||
yield return (ATTRIB_ID_AIM, AimStrain);
|
yield return (ATTRIB_ID_AIM, AimDifficulty);
|
||||||
yield return (ATTRIB_ID_SPEED, SpeedStrain);
|
yield return (ATTRIB_ID_SPEED, SpeedDifficulty);
|
||||||
yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
|
yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
|
||||||
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
||||||
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
yield return (ATTRIB_ID_STRAIN, StarRating);
|
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
||||||
|
|
||||||
if (ShouldSerializeFlashlightRating())
|
if (ShouldSerializeFlashlightRating())
|
||||||
yield return (ATTRIB_ID_FLASHLIGHT, FlashlightRating);
|
yield return (ATTRIB_ID_FLASHLIGHT, FlashlightDifficulty);
|
||||||
|
|
||||||
yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
|
yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
|
||||||
}
|
}
|
||||||
@ -60,13 +60,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
base.FromDatabaseAttributes(values);
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
AimStrain = values[ATTRIB_ID_AIM];
|
AimDifficulty = values[ATTRIB_ID_AIM];
|
||||||
SpeedStrain = values[ATTRIB_ID_SPEED];
|
SpeedDifficulty = values[ATTRIB_ID_SPEED];
|
||||||
OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY];
|
OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY];
|
||||||
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
||||||
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
||||||
StarRating = values[ATTRIB_ID_STRAIN];
|
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
||||||
FlashlightRating = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
|
FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
|
||||||
SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR];
|
SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +74,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
AimStrain = aimRating,
|
AimDifficulty = aimRating,
|
||||||
SpeedStrain = speedRating,
|
SpeedDifficulty = speedRating,
|
||||||
FlashlightRating = flashlightRating,
|
FlashlightDifficulty = flashlightRating,
|
||||||
SliderFactor = sliderFactor,
|
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,
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
{
|
{
|
||||||
mods = Score.Mods;
|
mods = Score.Mods;
|
||||||
accuracy = Score.Accuracy;
|
accuracy = Score.Accuracy;
|
||||||
@ -72,15 +72,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
Math.Pow(flashlightValue, 1.1), 1.0 / 1.1
|
Math.Pow(flashlightValue, 1.1), 1.0 / 1.1
|
||||||
) * multiplier;
|
) * multiplier;
|
||||||
|
|
||||||
if (categoryRatings != null)
|
if (categoryDifficulty != null)
|
||||||
{
|
{
|
||||||
categoryRatings.Add("Aim", aimValue);
|
categoryDifficulty.Add("Aim", aimValue);
|
||||||
categoryRatings.Add("Speed", speedValue);
|
categoryDifficulty.Add("Speed", speedValue);
|
||||||
categoryRatings.Add("Accuracy", accuracyValue);
|
categoryDifficulty.Add("Accuracy", accuracyValue);
|
||||||
categoryRatings.Add("Flashlight", flashlightValue);
|
categoryDifficulty.Add("Flashlight", flashlightValue);
|
||||||
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
categoryDifficulty.Add("OD", Attributes.OverallDifficulty);
|
||||||
categoryRatings.Add("AR", Attributes.ApproachRate);
|
categoryDifficulty.Add("AR", Attributes.ApproachRate);
|
||||||
categoryRatings.Add("Max Combo", Attributes.MaxCombo);
|
categoryDifficulty.Add("Max Combo", Attributes.MaxCombo);
|
||||||
|
categoryDifficulty.Add("Effective Miss Count", effectiveMissCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
@ -88,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
private double computeAimValue()
|
private double computeAimValue()
|
||||||
{
|
{
|
||||||
double rawAim = Attributes.AimStrain;
|
double rawAim = Attributes.AimDifficulty;
|
||||||
|
|
||||||
if (mods.Any(m => m is OsuModTouchDevice))
|
if (mods.Any(m => m is OsuModTouchDevice))
|
||||||
rawAim = Math.Pow(rawAim, 0.8);
|
rawAim = Math.Pow(rawAim, 0.8);
|
||||||
@ -144,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
private double computeSpeedValue()
|
private double computeSpeedValue()
|
||||||
{
|
{
|
||||||
double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedStrain / 0.0675) - 4.0, 3.0) / 100000.0;
|
double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedDifficulty / 0.0675) - 4.0, 3.0) / 100000.0;
|
||||||
|
|
||||||
// Longer maps are worth more.
|
// Longer maps are worth more.
|
||||||
double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) +
|
double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) +
|
||||||
@ -227,7 +228,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
if (!mods.Any(h => h is OsuModFlashlight))
|
if (!mods.Any(h => h is OsuModFlashlight))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
double rawFlashlight = Attributes.FlashlightRating;
|
double rawFlashlight = Attributes.FlashlightDifficulty;
|
||||||
|
|
||||||
if (mods.Any(m => m is OsuModTouchDevice))
|
if (mods.Any(m => m is OsuModTouchDevice))
|
||||||
rawFlashlight = Math.Pow(rawFlashlight, 0.8);
|
rawFlashlight = Math.Pow(rawFlashlight, 0.8);
|
||||||
|
@ -9,14 +9,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
public class TaikoDifficultyAttributes : DifficultyAttributes
|
public class TaikoDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
[JsonProperty("stamina_strain")]
|
[JsonProperty("stamina_difficulty")]
|
||||||
public double StaminaStrain { get; set; }
|
public double StaminaDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonProperty("rhythm_strain")]
|
[JsonProperty("rhythm_difficulty")]
|
||||||
public double RhythmStrain { get; set; }
|
public double RhythmDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonProperty("colour_strain")]
|
[JsonProperty("colour_difficulty")]
|
||||||
public double ColourStrain { get; set; }
|
public double ColourDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonProperty("approach_rate")]
|
[JsonProperty("approach_rate")]
|
||||||
public double ApproachRate { get; set; }
|
public double ApproachRate { get; set; }
|
||||||
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
yield return v;
|
yield return v;
|
||||||
|
|
||||||
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
yield return (ATTRIB_ID_STRAIN, StarRating);
|
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
||||||
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
base.FromDatabaseAttributes(values);
|
base.FromDatabaseAttributes(values);
|
||||||
|
|
||||||
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
||||||
StarRating = values[ATTRIB_ID_STRAIN];
|
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
||||||
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,9 +91,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
StaminaStrain = staminaRating,
|
StaminaDifficulty = staminaRating,
|
||||||
RhythmStrain = rhythmRating,
|
RhythmDifficulty = rhythmRating,
|
||||||
ColourStrain = colourRating,
|
ColourDifficulty = colourRating,
|
||||||
GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate,
|
GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate,
|
||||||
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
|
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
|
||||||
};
|
};
|
||||||
|
@ -44,43 +44,46 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
if (mods.Any(m => m is ModHidden))
|
if (mods.Any(m => m is ModHidden))
|
||||||
multiplier *= 1.10;
|
multiplier *= 1.10;
|
||||||
|
|
||||||
double strainValue = computeStrainValue();
|
double difficultyValue = computeDifficultyValue();
|
||||||
double accuracyValue = computeAccuracyValue();
|
double accuracyValue = computeAccuracyValue();
|
||||||
double totalValue =
|
double totalValue =
|
||||||
Math.Pow(
|
Math.Pow(
|
||||||
Math.Pow(strainValue, 1.1) +
|
Math.Pow(difficultyValue, 1.1) +
|
||||||
Math.Pow(accuracyValue, 1.1), 1.0 / 1.1
|
Math.Pow(accuracyValue, 1.1), 1.0 / 1.1
|
||||||
) * multiplier;
|
) * multiplier;
|
||||||
|
|
||||||
if (categoryDifficulty != null)
|
if (categoryDifficulty != null)
|
||||||
{
|
{
|
||||||
categoryDifficulty["Strain"] = strainValue;
|
categoryDifficulty.Add("Difficulty", difficultyValue);
|
||||||
categoryDifficulty["Accuracy"] = accuracyValue;
|
categoryDifficulty.Add("Accuracy", accuracyValue);
|
||||||
|
categoryDifficulty.Add("AR", Attributes.ApproachRate);
|
||||||
|
categoryDifficulty.Add("Great Hit Window", Attributes.GreatHitWindow);
|
||||||
|
categoryDifficulty.Add("Max Combo", Attributes.MaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeStrainValue()
|
private double computeDifficultyValue()
|
||||||
{
|
{
|
||||||
double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0;
|
double difficultyValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0;
|
||||||
|
|
||||||
// Longer maps are worth more
|
// Longer maps are worth more
|
||||||
double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
||||||
strainValue *= lengthBonus;
|
difficultyValue *= lengthBonus;
|
||||||
|
|
||||||
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||||
strainValue *= Math.Pow(0.985, countMiss);
|
difficultyValue *= Math.Pow(0.985, countMiss);
|
||||||
|
|
||||||
if (mods.Any(m => m is ModHidden))
|
if (mods.Any(m => m is ModHidden))
|
||||||
strainValue *= 1.025;
|
difficultyValue *= 1.025;
|
||||||
|
|
||||||
if (mods.Any(m => m is ModFlashlight<TaikoHitObject>))
|
if (mods.Any(m => m is ModFlashlight<TaikoHitObject>))
|
||||||
// Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
|
// Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
|
||||||
strainValue *= 1.05 * lengthBonus;
|
difficultyValue *= 1.05 * lengthBonus;
|
||||||
|
|
||||||
// Scale the speed value with accuracy _slightly_
|
// Scale the speed value with accuracy _slightly_
|
||||||
return strainValue * Score.Accuracy;
|
return difficultyValue * Score.Accuracy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeAccuracyValue()
|
private double computeAccuracyValue()
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5;
|
protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5;
|
||||||
protected const int ATTRIB_ID_APPROACH_RATE = 7;
|
protected const int ATTRIB_ID_APPROACH_RATE = 7;
|
||||||
protected const int ATTRIB_ID_MAX_COMBO = 9;
|
protected const int ATTRIB_ID_MAX_COMBO = 9;
|
||||||
protected const int ATTRIB_ID_STRAIN = 11;
|
protected const int ATTRIB_ID_DIFFICULTY = 11;
|
||||||
protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13;
|
protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13;
|
||||||
protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15;
|
protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15;
|
||||||
protected const int ATTRIB_ID_FLASHLIGHT = 17;
|
protected const int ATTRIB_ID_FLASHLIGHT = 17;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user