From c1ea472dcf86f2b0f78e2c73aeb77164f8f138da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 31 Jul 2025 14:48:26 +0200 Subject: [PATCH] Show effect of beatmap attributes on gameplay metrics in catch --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 27 ++++++++++++++++--- .../Objects/CatchHitObject.cs | 4 ++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index b927f958c0..db14618a4e 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -26,6 +27,7 @@ using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring.Legacy; @@ -283,11 +285,28 @@ namespace osu.Game.Rulesets.Catch public override IEnumerable GetBeatmapAttributesForDisplay(IBeatmapInfo beatmapInfo, IReadOnlyCollection mods) { var originalDifficulty = beatmapInfo.Difficulty; - var adjustedDifficulty = GetAdjustedDisplayDifficulty(beatmapInfo, mods); + var effectiveDifficulty = GetAdjustedDisplayDifficulty(beatmapInfo, mods); - yield return new RulesetBeatmapAttribute(SongSelectStrings.CircleSize, @"CS", originalDifficulty.CircleSize, adjustedDifficulty.CircleSize, 10); - yield return new RulesetBeatmapAttribute(SongSelectStrings.ApproachRate, @"AR", originalDifficulty.ApproachRate, adjustedDifficulty.ApproachRate, 10); - yield return new RulesetBeatmapAttribute(SongSelectStrings.HPDrain, @"HP", originalDifficulty.DrainRate, adjustedDifficulty.DrainRate, 10); + yield return new RulesetBeatmapAttribute(SongSelectStrings.CircleSize, @"CS", originalDifficulty.CircleSize, effectiveDifficulty.CircleSize, 10) + { + Description = "Affects the size of fruits.", + AdditionalMetrics = + [ + new RulesetBeatmapAttribute.AdditionalMetric("Hit circle radius", (CatchHitObject.OBJECT_RADIUS * LegacyRulesetExtensions.CalculateScaleFromCircleSize(effectiveDifficulty.CircleSize)).ToLocalisableString("N1")) + ] + }; + yield return new RulesetBeatmapAttribute(SongSelectStrings.ApproachRate, @"AR", originalDifficulty.ApproachRate, effectiveDifficulty.ApproachRate, 10) + { + Description = "Affects how early fruits fade in on the screen.", + AdditionalMetrics = + [ + new RulesetBeatmapAttribute.AdditionalMetric("Fade-in time", LocalisableString.Interpolate($@"{IBeatmapDifficultyInfo.DifficultyRange(effectiveDifficulty.ApproachRate, CatchHitObject.PREEMPT_RANGE):N0}ms")) + ] + }; + yield return new RulesetBeatmapAttribute(SongSelectStrings.HPDrain, @"HP", originalDifficulty.DrainRate, effectiveDifficulty.DrainRate, 10) + { + Description = "Affects the harshness of health drain and the health penalties for missing." + }; } public override bool EditorShowScrollSpeed => false; diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index deaa566864..41deaa0d82 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -150,7 +150,7 @@ namespace osu.Game.Rulesets.Catch.Objects { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - TimePreempt = (float)IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, PREEMPT_MAX, PREEMPT_MID, PREEMPT_MIN); + TimePreempt = (float)IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, PREEMPT_RANGE); Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize); } @@ -203,6 +203,8 @@ namespace osu.Game.Rulesets.Catch.Objects /// public const double PREEMPT_MAX = 1800; + public static readonly DifficultyRange PREEMPT_RANGE = new DifficultyRange(PREEMPT_MAX, PREEMPT_MID, PREEMPT_MIN); + /// /// The Y position of the hit object is not used in the normal osu!catch gameplay. /// It is preserved to maximize the backward compatibility with the legacy editor, in which the mappers use the Y position to organize the patterns.