From e04727afb13d5478608987e1080270a54bee66ed Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Mon, 20 Jan 2025 07:55:34 +1000 Subject: [PATCH] Improve convert considerations in osu!taiko (#31546) * return a higher finger count * implement isConvert * diffcalc cleanup * harshen monostaminafactor accuracy curve * readd comment * adjusts tests --- .../TaikoDifficultyCalculatorTest.cs | 8 ++--- .../Difficulty/Evaluators/StaminaEvaluator.cs | 2 +- .../Difficulty/Skills/Stamina.cs | 7 +++-- .../Difficulty/TaikoDifficultyCalculator.cs | 31 ++++++------------- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index d760b9aef6..6f5c26816f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Taiko.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(3.3167800835687551d, 200, "diffcalc-test")] - [TestCase(3.3167800835687551d, 200, "diffcalc-test-strong")] + [TestCase(3.3056113401782845d, 200, "diffcalc-test")] + [TestCase(3.3056113401782845d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(4.4631326105105122d, 200, "diffcalc-test")] - [TestCase(4.4631326105105122d, 200, "diffcalc-test-strong")] + [TestCase(4.4473902679506896d, 200, "diffcalc-test")] + [TestCase(4.4473902679506896d, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index a273d91a38..b39ad953a4 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 2; } - return 4; + return 8; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 29f9f16033..aea491aca3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills private double strainDecayBase => 0.4; private readonly bool singleColourStamina; + private readonly bool isConvert; private double currentStrain; @@ -28,10 +29,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// /// Mods for use in skill calculations. /// Reads when Stamina is from a single coloured pattern. - public Stamina(Mod[] mods, bool singleColourStamina) + /// Determines if the currently evaluated beatmap is converted. + public Stamina(Mod[] mods, bool singleColourStamina, bool isConvert) : base(mods) { this.singleColourStamina = singleColourStamina; + this.isConvert = isConvert; } private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); @@ -45,7 +48,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills var currentObject = current as TaikoDifficultyHitObject; int index = currentObject?.Colour.MonoStreak?.HitObjects.IndexOf(currentObject) ?? 0; - double monolengthBonus = 1 + Math.Min(Math.Max((index - 5) / 50.0, 0), 0.30); + double monolengthBonus = isConvert ? 1 : 1 + Math.Min(Math.Max((index - 5) / 50.0, 0), 0.30); if (singleColourStamina) return DifficultyCalculationUtils.Logistic(-(index - 10) / 2.0, currentStrain); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 3ad9d17526..efd3001764 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double strainLengthBonus; private double patternMultiplier; + private bool isConvert; + public override int Version => 20241007; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) @@ -44,13 +46,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty HitWindows hitWindows = new HitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); + isConvert = beatmap.BeatmapInfo.Ruleset.OnlineID == 0; + return new Skill[] { new Rhythm(mods, hitWindows.WindowFor(HitResult.Great) / clockRate), new Reading(mods), new Colour(mods), - new Stamina(mods, false), - new Stamina(mods, true) + new Stamina(mods, false, isConvert), + new Stamina(mods, true, isConvert) }; } @@ -130,19 +134,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty + Math.Min(Math.Max((staminaDifficultStrains - 1350) / 5000, 0), 0.15) + Math.Min(Math.Max((staminaRating - 7.0) / 1.0, 0), 0.05); - double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax); + double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert); double starRating = rescale(combinedRating * 1.4); - // 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) - { - starRating *= 0.7; - - // For maps with relax, multiple inputs are more likely to be abused. - if (isRelax) - starRating *= 0.60; - } - HitWindows hitWindows = new TaikoHitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); @@ -173,7 +167,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// For each section, the peak strains of all separate skills are combined into a single peak strain for the section. /// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more). /// - private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax) + private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax, bool isConvert) { List peaks = new List(); @@ -186,14 +180,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { double rhythmPeak = rhythmPeaks[i] * rhythm_skill_multiplier * patternMultiplier; double readingPeak = readingPeaks[i] * reading_skill_multiplier; - double colourPeak = colourPeaks[i] * colour_skill_multiplier; + double colourPeak = isRelax ? 0 : colourPeaks[i] * colour_skill_multiplier; // There is no colour difficulty in relax. double staminaPeak = staminaPeaks[i] * stamina_skill_multiplier * strainLengthBonus; - - if (isRelax) - { - colourPeak = 0; // There is no colour difficulty in relax. - staminaPeak /= 1.5; // Stamina difficulty is decreased with an increased available finger count. - } + staminaPeak /= isConvert || isRelax ? 1.5 : 1.0; // Available finger count is increased by 150%, thus we adjust accordingly. double peak = DifficultyCalculationUtils.Norm(2, DifficultyCalculationUtils.Norm(1.5, colourPeak, staminaPeak), rhythmPeak, readingPeak); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 9e7bf7cb7a..bcd3693119 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // Scale accuracy more harshly on nearly-completely mono (single coloured) speed maps. double accScalingExponent = 2 + attributes.MonoStaminaFactor; - double accScalingShift = 500 - 100 * attributes.MonoStaminaFactor; + double accScalingShift = 500 - 100 * (attributes.MonoStaminaFactor * 3); return difficultyValue * Math.Pow(DifficultyCalculationUtils.Erf(accScalingShift / (Math.Sqrt(2) * estimatedUnstableRate.Value)), accScalingExponent); }