diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
index 2ecef3690b..01410af459 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs
@@ -6,6 +6,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
{
public class ColourEvaluator
{
+ // TODO - Share this sigmoid
private static double sigmoid(double val, double center, double width)
{
return Math.Tanh(Math.E * -(val - center) / width);
@@ -16,7 +17,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current;
TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour;
if (colour == null) return 0;
+
double objectStrain = 1.8;
+
if (colour.Delta)
{
objectStrain *= sigmoid(colour.DeltaRunLength, 6, 4) * 0.5 + 0.5;
@@ -25,9 +28,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
{
objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5;
}
+
objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8) * 0.5 + 0.5;
- // Console.WriteLine($"{current.StartTime},{colour.GetHashCode()},{colour.Delta},{colour.DeltaRunLength},{colour.RepetitionInterval},{objectStrain}");
return objectStrain;
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
index 0c33a952a5..6c0c01cb2d 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs
@@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
// Find the previous hit object hit by the current key, which is two notes of the same colour prior.
TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current;
TaikoDifficultyHitObject keyPrevious = taikoCurrent.PreviousMono(1);
+
if (keyPrevious == null)
{
// There is no previous hit object hit by the current key
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs
index 537eafe396..54e314f722 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs
@@ -53,8 +53,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
/// TODO: This argument list is getting long, we might want to refactor this into a static method that create
/// all s from a .
public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate,
- List objects, List centreHitObjects, List rimHitObjects,
- List noteObjects, int position)
+ List objects,
+ List centreHitObjects,
+ List rimHitObjects,
+ List noteObjects, int position)
: base(hitObject, lastObject, clockRate, objects, position)
{
var currentHit = hitObject as Hit;
@@ -65,26 +67,25 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
if (HitType == Objects.HitType.Centre)
{
- MonoPosition = centreHitObjects.Count();
+ MonoPosition = centreHitObjects.Count;
centreHitObjects.Add(this);
monoDifficultyHitObjects = centreHitObjects;
}
else if (HitType == Objects.HitType.Rim)
{
- MonoPosition = rimHitObjects.Count();
+ MonoPosition = rimHitObjects.Count;
rimHitObjects.Add(this);
monoDifficultyHitObjects = rimHitObjects;
}
// Need to be done after HitType is set.
- if (HitType != null)
- {
- this.NotePosition = noteObjects.Count();
- noteObjects.Add(this);
+ if (HitType == null) return;
- // Need to be done after NotePosition is set.
- Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this);
- }
+ NotePosition = noteObjects.Count;
+ noteObjects.Add(this);
+
+ // Need to be done after NotePosition is set.
+ Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this);
}
///
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs
index f9a586f877..a5ca0964df 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs
@@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
///
public class TaikoDifficultyHitObjectColour
{
- const int max_repetition_interval = 16;
+ private const int max_repetition_interval = 16;
private TaikoDifficultyHitObjectColour previous;
@@ -38,54 +38,54 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0);
TaikoDifficultyHitObjectColour previous = lastObject?.Colour;
bool delta = lastObject == null || hitObject.HitType != lastObject.HitType;
+
if (previous != null && delta == previous.Delta)
{
previous.DeltaRunLength += 1;
return previous;
}
- else
- {
- // Calculate RepetitionInterval for previous
- previous?.FindRepetitionInterval();
- return new TaikoDifficultyHitObjectColour()
- {
- Delta = delta,
- DeltaRunLength = 1,
- RepetitionInterval = max_repetition_interval + 1,
- previous = previous
- };
- }
+ // Calculate RepetitionInterval for previous
+ previous?.FindRepetitionInterval();
+
+ return new TaikoDifficultyHitObjectColour()
+ {
+ Delta = delta,
+ DeltaRunLength = 1,
+ RepetitionInterval = max_repetition_interval + 1,
+ previous = previous
+ };
}
///
- /// Finds the closest previous that has the identical delta value
+ /// Finds the closest previous that has the identical delta value
/// and run length with the current instance, and returns the amount of notes between them.
///
public void FindRepetitionInterval()
{
- if (this.previous == null || this.previous.previous == null)
+ if (previous?.previous == null)
{
- this.RepetitionInterval = max_repetition_interval + 1;
+ RepetitionInterval = max_repetition_interval + 1;
return;
}
+ int interval = previous.DeltaRunLength;
+ TaikoDifficultyHitObjectColour other = previous.previous;
- int interval = this.previous.DeltaRunLength;
- TaikoDifficultyHitObjectColour other = this.previous.previous;
while (other != null && interval < max_repetition_interval)
{
interval += other.DeltaRunLength;
- if (other.Delta == this.Delta && other.DeltaRunLength == this.DeltaRunLength)
+
+ if (other.Delta == Delta && other.DeltaRunLength == DeltaRunLength)
{
- this.RepetitionInterval = Math.Min(interval, max_repetition_interval);
+ RepetitionInterval = Math.Min(interval, max_repetition_interval);
return;
}
other = other.previous;
}
- this.RepetitionInterval = max_repetition_interval + 1;
+ RepetitionInterval = max_repetition_interval + 1;
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
index 9a8b350e22..1c992df179 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
@@ -1,13 +1,10 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
-using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
-using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs
similarity index 94%
rename from osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs
rename to osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs
index bf62cb1fbd..4d4089cba7 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs
@@ -7,22 +7,24 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
- public class CombinedStrain : Skill
+ public class Peaks : Skill
{
- private const double final_multiplier = 0.00925;
private const double rhythm_skill_multiplier = 1.6 * final_multiplier;
private const double colour_skill_multiplier = 1.85 * final_multiplier;
private const double stamina_skill_multiplier = 1.85 * final_multiplier;
- private Rhythm rhythm;
- private Colour colour;
- private Stamina stamina;
+ private const double final_multiplier = 0.00925;
+
+ private readonly Rhythm rhythm;
+ private readonly Colour colour;
+ private readonly Stamina stamina;
public double ColourDifficultyValue => colour.DifficultyValue() * colour_skill_multiplier;
public double RhythmDifficultyValue => rhythm.DifficultyValue() * rhythm_skill_multiplier;
public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier;
- public CombinedStrain(Mod[] mods) : base(mods)
+ public Peaks(Mod[] mods)
+ : base(mods)
{
rhythm = new Rhythm(mods);
colour = new Colour(mods);
@@ -85,4 +87,4 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
return difficulty;
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
index ee5e257811..57c82bf97b 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
@@ -5,8 +5,6 @@ using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
-using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
-using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs
index 3dc5438072..c7342554da 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs
@@ -28,13 +28,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
public double ColourDifficulty { get; set; }
///
- /// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
+ /// The difficulty corresponding to the hardest parts of the map.
///
- ///
- /// Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing.
- ///
- [JsonProperty("approach_rate")]
- public double ApproachRate { get; set; }
+ [JsonProperty("peak_difficulty")]
+ public double PeakDifficulty { get; set; }
///
/// The perceived hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc).
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
index f4a23930b3..91ae1c4ed2 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
public class TaikoDifficultyCalculator : DifficultyCalculator
{
+ private const double difficulty_multiplier = 1.9;
+
public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
: base(ruleset, beatmap)
{
@@ -29,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
return new Skill[]
{
- new CombinedStrain(mods)
+ new Peaks(mods)
};
}
@@ -68,13 +70,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (beatmap.HitObjects.Count == 0)
return new TaikoDifficultyAttributes { Mods = mods };
- var combined = (CombinedStrain)skills[0];
+ var combined = (Peaks)skills[0];
- double colourRating = combined.ColourDifficultyValue;
- double rhythmRating = combined.RhythmDifficultyValue;
- double staminaRating = combined.StaminaDifficultyValue;
+ double colourRating = Math.Sqrt(combined.ColourDifficultyValue * difficulty_multiplier);
+ double rhythmRating = Math.Sqrt(combined.RhythmDifficultyValue * difficulty_multiplier);
+ double staminaRating = Math.Sqrt(combined.StaminaDifficultyValue * difficulty_multiplier);
- double starRating = rescale(1.9 * combined.DifficultyValue());
+ double combinedRating = combined.DifficultyValue();
+ double starRating = rescale(combinedRating * difficulty_multiplier);
HitWindows hitWindows = new TaikoHitWindows();
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
@@ -86,6 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
StaminaDifficulty = staminaRating,
RhythmDifficulty = rhythmRating,
ColourDifficulty = colourRating,
+ PeakDifficulty = combinedRating,
GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate,
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
};
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
index 8d99fd3b87..f551d8cd93 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
@@ -33,21 +33,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh);
countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss);
- double multiplier = 1.1; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
-
- if (score.Mods.Any(m => m is ModNoFail))
- multiplier *= 0.90;
-
- if (score.Mods.Any(m => m is ModHidden))
- multiplier *= 1.10;
-
double difficultyValue = computeDifficultyValue(score, taikoAttributes);
double accuracyValue = computeAccuracyValue(score, taikoAttributes);
double totalValue =
Math.Pow(
Math.Pow(difficultyValue, 1.1) +
Math.Pow(accuracyValue, 1.1), 1.0 / 1.1
- ) * multiplier;
+ ) * 1.1;
return new TaikoPerformanceAttributes
{
@@ -59,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes)
{
- double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.175) - 4.0, 2.25) / 450.0;
+ double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.190) - 4.0, 2.25) / 450.0;
double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
difficultyValue *= lengthBonus;
@@ -67,7 +59,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
difficultyValue *= Math.Pow(0.985, countMiss);
if (score.Mods.Any(m => m is ModHidden))
- difficultyValue *= 1.025;
+ difficultyValue *= 1.125;
if (score.Mods.Any(m => m is ModFlashlight))
difficultyValue *= 1.05 * lengthBonus;
@@ -80,10 +72,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (attributes.GreatHitWindow <= 0)
return 0;
- double accValue = Math.Pow(150.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 15) * 22.0;
+ double accuracyValue = Math.Pow(150.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 15) * 40.0;
- // Bonus for many objects - it's harder to keep good accuracy up for longer
- return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
+ double accuracylengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
+ accuracyValue *= accuracylengthBonus;
+
+ if (score.Mods.Any(m => m is ModHidden))
+ accuracyValue *= 1.225;
+
+ if (score.Mods.Any(m => m is ModFlashlight))
+ accuracyValue *= 1.15 * accuracylengthBonus;
+
+ return accuracyValue;
}
private int totalHits => countGreat + countOk + countMeh + countMiss;