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 14, 2025
1 parent b21c645 commit 07faf63
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 17 deletions.
32 changes: 32 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,16 @@ 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.3;


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

// Indicate a flat multiplier value base only on map length.
private double lengthBonusBase;

public override int Version => 20241007;

public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
Expand Down Expand Up @@ -101,6 +111,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.OnlineInfo!.Ruleset.OnlineID != 1;

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

//We can have a base length bonus based only from the length of the map.
lengthBonusBase = Math.Max((Math.Log(10.0 + beatmap.HitObjects.Count / 1000.0) - 1.35) * 0.45 + 0.5, 1.0);

//Old formula that need to be removed with the reading rework.
lengthBonusBase *= isFlashlight && isHidden || !isConvert ? 1.05 : 1.0;

rhythmRating *= LengthBonusMultiplier(lengthBonusBase, rhythm.DifficultyFactor, bonus_multiplier);
readingRating *= LengthBonusMultiplier(lengthBonusBase, reading.DifficultyFactor, bonus_multiplier);
colourRating *= LengthBonusMultiplier(lengthBonusBase, colour.DifficultyFactor, bonus_multiplier);
staminaRating *= LengthBonusMultiplier(lengthBonusBase, stamina.DifficultyFactor, bonus_multiplier);

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

Expand All @@ -138,6 +163,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes
{
StarRating = starRating,
TotalDifficultyFactor = totalDifficultyFactor,
Mods = mods,
RhythmDifficulty = rhythmRating,
ReadingDifficulty = readingRating,
Expand Down Expand Up @@ -192,6 +218,10 @@ private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour co
peaks.Add(peak);
}

// 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.
totalDifficultyFactor = peaks.Average() / peaks.Max();

double difficulty = 0;
double weight = 1;

Expand All @@ -201,6 +231,8 @@ private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour co
weight *= 0.9;
}

difficulty *= LengthBonusMultiplier(lengthBonusBase, totalDifficultyFactor, bonus_multiplier);

return difficulty;
}

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.TotalDifficultyFactor;

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 difficulty corresponding to every skills.
/// </summary>
[JsonProperty("total_difficulty_factor")]
public double TotalDifficultyFactor { get; set; }

/// <summary>
/// The maximum achievable combo.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ namespace osu.Game.Rulesets.Difficulty
{
public abstract class DifficultyCalculator
{
/// <summary>
/// Calculating the length bonus as a multiplier considering also the Difficulty Factor.
/// </summary>
protected virtual double LengthBonusMultiplier(double offsetLengthBonus, double difficultyFactor, double multiplierDifficultyFactor) => offsetLengthBonus + difficultyFactor * multiplierDifficultyFactor;

/// <summary>
/// The beatmap for which difficulty will be calculated.
/// </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 DifficultyFactor;

/// <summary>
/// Process a <see cref="DifficultyHitObject"/>.
/// </summary>
Expand Down
4 changes: 4 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,10 @@ public override double DifficultyValue()
// These sections will not contribute to the difficulty.
var peaks = GetCurrentStrainPeaks().Where(p => p > 0);

// 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.
DifficultyFactor = peaks.Average() / peaks.Max();

// 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 07faf63

Please sign in to comment.