Skip to content

Commit

Permalink
Difficulty factor added + Length bonus rework
Browse files Browse the repository at this point in the history
  • Loading branch information
TheDark98 committed Jan 15, 2025
1 parent 0a21183 commit 6fde2da
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 17 deletions.
29 changes: 29 additions & 0 deletions osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ public class TaikoDifficultyCalculator : DifficultyCalculator
private const double colour_skill_multiplier = 0.375 * difficulty_multiplier;
private const double stamina_skill_multiplier = 0.375 * difficulty_multiplier;

//The bonus multiplier is a basic multiplier that indicate how strong the impact of Difficulty Factor is.
private const double bonus_multiplier = 0.5;


// The difficulty factor for all the skills interpolated.
private double totalConsistencyFactor;

public override int Version => 20241007;

public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
Expand Down Expand Up @@ -101,6 +108,10 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
return new TaikoDifficultyAttributes { Mods = mods };

bool isRelax = mods.Any(h => h is TaikoModRelax);
bool isFlashlight = mods.Any(h => h is TaikoModFlashlight);
bool isHidden = mods.Any(h => h is TaikoModHidden);

bool isConvert = beatmap.BeatmapInfo.OnlineID != 1;

Rhythm rhythm = (Rhythm)skills.First(x => x is Rhythm);
Reading reading = (Reading)skills.First(x => x is Reading);
Expand All @@ -119,9 +130,16 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
double readingDifficultStrains = reading.CountTopWeightedStrains();
double staminaDifficultStrains = stamina.CountTopWeightedStrains();

rhythmRating *= Math.Pow(beatmap.HitObjects.Count * (0.75 + rhythm.ConsistencyFactor * bonus_multiplier), 0.57) / 1500 + 1.07;
readingRating *= Math.Pow(beatmap.HitObjects.Count * (0.75 + reading.ConsistencyFactor * bonus_multiplier), 0.57) / 1500 + 1.07;
colourRating *= Math.Pow(beatmap.HitObjects.Count * (0.75 + colour.ConsistencyFactor * bonus_multiplier), 0.57) / 1500 + 1.07;
staminaRating *= Math.Pow(beatmap.HitObjects.Count * (0.75 + stamina.ConsistencyFactor * bonus_multiplier), 0.57) / 1500 + 1.07;

double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax);
double starRating = rescale(combinedRating * 1.4);

starRating *= Math.Pow(beatmap.HitObjects.Count * (0.75 + totalConsistencyFactor * bonus_multiplier), 0.57) / 1500 + 1.07;

// Converts are penalised outside the scope of difficulty calculation, as our assumptions surrounding standard play-styles becomes out-of-scope.
if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0)
{
Expand All @@ -138,6 +156,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes
{
StarRating = starRating,
TotalConsistencyFactor = totalConsistencyFactor,
Mods = mods,
RhythmDifficulty = rhythmRating,
ReadingDifficulty = readingRating,
Expand Down Expand Up @@ -192,6 +211,16 @@ private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour co
peaks.Add(peak);
}

// We select only the hardest 20% of picks in strains to ensure greater value in the most difficult sections of the map.
List<double> hardStrains = peaks.OrderDescending().ToList().GetRange(0, peaks.Count / 10 * 2);

//We select only the moderate 20% of picks in strains to provide greater value in the more moderate sections of the map.
List<double> midStrains = peaks.OrderDescending().ToList().GetRange(peaks.Count / 10 * 4, peaks.Count / 10 * 6);

// We can calculate the difficulty factor by doing average pick difficulty / max peak difficulty.
// It resoult in a value that rappresent the consistency for all peaks (0 excluded) in a range number from 0 to 1.
totalConsistencyFactor = midStrains.Average() / hardStrains.Average();

double difficulty = 0;
double weight = 1;

Expand Down
24 changes: 7 additions & 17 deletions osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes
double baseDifficulty = 5 * Math.Max(1.0, attributes.StarRating / 0.115) - 4.0;
double difficultyValue = Math.Min(Math.Pow(baseDifficulty, 3) / 69052.51, Math.Pow(baseDifficulty, 2.25) / 1150.0);

double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
difficultyValue *= lengthBonus;

if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>))
difficultyValue *= Math.Max(1, 1.050 - Math.Min(attributes.MonoStaminaFactor / 50, 1));

// We need to divide the effectiveMissCount by 1 + DifficultyFactor to account for the miss count while considering map consistency.
effectiveMissCount /= 1.0 + attributes.TotalConsistencyFactor;

difficultyValue *= Math.Pow(0.986, effectiveMissCount);

Expand All @@ -87,9 +91,6 @@ private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes
if (score.Mods.Any(m => m is ModHidden))
difficultyValue *= 1.025;

if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>))
difficultyValue *= Math.Max(1, 1.050 - Math.Min(attributes.MonoStaminaFactor / 50, 1) * lengthBonus);

if (estimatedUnstableRate == null)
return 0;

Expand All @@ -102,18 +103,7 @@ private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes

private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert)
{
if (attributes.GreatHitWindow <= 0 || estimatedUnstableRate == null)
return 0;

double accuracyValue = Math.Pow(70 / estimatedUnstableRate.Value, 1.1) * Math.Pow(attributes.StarRating, 0.4) * 100.0;

double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));

// Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values.
if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>) && score.Mods.Any(m => m is ModHidden) && !isConvert)
accuracyValue *= Math.Max(1.0, 1.05 * lengthBonus);

return accuracyValue;
return attributes.GreatHitWindow <= 0 || estimatedUnstableRate == null ? 0.0 : Math.Pow(70 / estimatedUnstableRate.Value, 1.1) * Math.Pow(attributes.StarRating, 0.4) * 100.0;
}

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public class DifficultyAttributes
[JsonProperty("star_rating", Order = -3)]
public double StarRating { get; set; }

/// <summary>
/// The factor corresponding to the consistency of each skill.
/// </summary>
[JsonProperty("total_consistency_factor")]
public double TotalConsistencyFactor { get; set; }

/// <summary>
/// The maximum achievable combo.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions osu.Game/Rulesets/Difficulty/Skills/Skill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ protected Skill(Mod[] mods)
this.mods = mods;
}

/// <summary>
/// Value that rappresent the consistency for all <see cref="DifficultyHitObject"/>s (0 excluded) that have been processed up to this point in a range number from 0 to 1.
/// </summary>
public double ConsistencyFactor;

/// <summary>
/// Process a <see cref="DifficultyHitObject"/>.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ public override double DifficultyValue()
// These sections will not contribute to the difficulty.
var peaks = GetCurrentStrainPeaks().Where(p => p > 0);

// We select only the hardest 20% of picks in strains to ensure greater value in the most difficult sections of the map.
List<double> hardStrains = peaks.OrderDescending().ToList().GetRange(0, peaks.Count() / 10 * 2);

//We select only the moderate 20% of picks in strains to provide greater value in the more moderate sections of the map.
List<double> midStrains = peaks.OrderDescending().ToList().GetRange(peaks.Count() / 10 * 4, peaks.Count() / 10 * 6);

// We can calculate the difficulty factor by doing average pick difficulty / max peak difficulty.
// It resoult in a value that rappresent the consistency for all peaks (0 excluded) in a range number from 0 to 1.
ConsistencyFactor = midStrains.Average() / hardStrains.Average();

// Difficulty is the weighted sum of the highest strains from every section.
// We're sorting from highest to lowest strain.
foreach (double strain in peaks.OrderDescending())
Expand Down

0 comments on commit 6fde2da

Please sign in to comment.