diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 8a8c41bb8a..beba29b8bb 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -43,14 +43,11 @@ namespace osu.Game.Rulesets.Mania.Difficulty countMeh = Score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = Score.Statistics.GetValueOrDefault(HitResult.Miss); - IEnumerable scoreIncreaseMods = Ruleset.GetModsFor(ModType.DifficultyIncrease); - - double scoreMultiplier = 1.0; - foreach (var m in mods.Where(m => !scoreIncreaseMods.Contains(m))) - scoreMultiplier *= m.ScoreMultiplier; - - // Scale score up, so it's comparable to other keymods - scaledScore *= 1.0 / scoreMultiplier; + if (Attributes.ScoreMultiplier > 0) + { + // Scale score up, so it's comparable to other keymods + scaledScore *= 1.0 / Attributes.ScoreMultiplier; + } // Arbitrary initial value for scaling pp in order to standardize distributions across game modes. // The specific number has no intrinsic meaning and can be adjusted as needed. @@ -80,6 +77,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty private double computeDifficultyValue() { + if (Attributes.ScoreMultiplier <= 0) + return 0; + double difficultyValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0; difficultyValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index de795241bf..0b9db8e20a 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -147,8 +147,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("player score matching expected bonus score", () => { - // multipled by 2 to nullify the score multiplier. (autoplay mod selected) - double totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2; + double totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value; return totalScore == (int)(drawableSpinner.Result.RateAdjustedRotation / 360) * new SpinnerTick().CreateJudgement().MaxNumericResult; }); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs index 0631059d1a..e9014c0941 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; -using System.Linq; using NUnit.Framework; -using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Select; @@ -14,11 +12,11 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneFooterButtonMods : OsuTestScene { - private readonly TestFooterButtonMods footerButtonMods; + private readonly FooterButtonMods footerButtonMods; public TestSceneFooterButtonMods() { - Add(footerButtonMods = new TestFooterButtonMods()); + Add(footerButtonMods = new FooterButtonMods()); } [Test] @@ -26,19 +24,15 @@ namespace osu.Game.Tests.Visual.UserInterface { var hiddenMod = new Mod[] { new OsuModHidden() }; AddStep(@"Add Hidden", () => changeMods(hiddenMod)); - AddAssert(@"Check Hidden multiplier", () => assertModsMultiplier(hiddenMod)); var hardRockMod = new Mod[] { new OsuModHardRock() }; AddStep(@"Add HardRock", () => changeMods(hardRockMod)); - AddAssert(@"Check HardRock multiplier", () => assertModsMultiplier(hardRockMod)); var doubleTimeMod = new Mod[] { new OsuModDoubleTime() }; AddStep(@"Add DoubleTime", () => changeMods(doubleTimeMod)); - AddAssert(@"Check DoubleTime multiplier", () => assertModsMultiplier(doubleTimeMod)); var multipleIncrementMods = new Mod[] { new OsuModDoubleTime(), new OsuModHidden(), new OsuModHardRock() }; AddStep(@"Add multiple Mods", () => changeMods(multipleIncrementMods)); - AddAssert(@"Check multiple mod multiplier", () => assertModsMultiplier(multipleIncrementMods)); } [Test] @@ -46,15 +40,12 @@ namespace osu.Game.Tests.Visual.UserInterface { var easyMod = new Mod[] { new OsuModEasy() }; AddStep(@"Add Easy", () => changeMods(easyMod)); - AddAssert(@"Check Easy multiplier", () => assertModsMultiplier(easyMod)); var noFailMod = new Mod[] { new OsuModNoFail() }; AddStep(@"Add NoFail", () => changeMods(noFailMod)); - AddAssert(@"Check NoFail multiplier", () => assertModsMultiplier(noFailMod)); var multipleDecrementMods = new Mod[] { new OsuModEasy(), new OsuModNoFail() }; AddStep(@"Add Multiple Mods", () => changeMods(multipleDecrementMods)); - AddAssert(@"Check multiple mod multiplier", () => assertModsMultiplier(multipleDecrementMods)); } [Test] @@ -63,25 +54,11 @@ namespace osu.Game.Tests.Visual.UserInterface var multipleMods = new Mod[] { new OsuModDoubleTime(), new OsuModFlashlight() }; AddStep(@"Add mods", () => changeMods(multipleMods)); AddStep(@"Clear selected mod", () => changeMods(Array.Empty())); - AddAssert(@"Check empty multiplier", () => assertModsMultiplier(Array.Empty())); } private void changeMods(IReadOnlyList mods) { footerButtonMods.Current.Value = mods; } - - private bool assertModsMultiplier(IEnumerable mods) - { - double multiplier = mods.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier); - string expectedValue = multiplier.Equals(1.0) ? string.Empty : $"{multiplier:N2}x"; - - return expectedValue == footerButtonMods.MultiplierText.Current.Value; - } - - private class TestFooterButtonMods : FooterButtonMods - { - public new OsuSpriteText MultiplierText => base.MultiplierText; - } } } diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 7136795461..9a45e2458d 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -80,10 +80,13 @@ namespace osu.Game.Rulesets.Mods } /// - /// The score multiplier of this mod. + /// The (legacy) score multiplier of this mod. /// + /// + /// This is not applied for newly set scores, but may be required for display purposes when showing legacy scores. + /// [JsonIgnore] - public abstract double ScoreMultiplier { get; } + public virtual double ScoreMultiplier => 1; /// /// Returns true if this mod is implemented (and playable). diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 79861c0ecc..ce1486b02f 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -92,8 +92,6 @@ namespace osu.Game.Rulesets.Scoring private readonly List hitEvents = new List(); private HitObject lastHitObject; - private double scoreMultiplier = 1; - public ScoreProcessor() { accuracyPortion = DefaultAccuracyPortion; @@ -111,15 +109,6 @@ namespace osu.Game.Rulesets.Scoring }; Mode.ValueChanged += _ => updateScore(); - Mods.ValueChanged += mods => - { - scoreMultiplier = 1; - - foreach (var m in mods.NewValue) - scoreMultiplier *= m.ScoreMultiplier; - - updateScore(); - }; } private readonly Dictionary scoreResultCounts = new Dictionary(); @@ -235,7 +224,7 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Standardised: double accuracyScore = accuracyPortion * accuracyRatio; double comboScore = comboPortion * comboRatio; - return (max_score * (accuracyScore + comboScore) + getBonusScore(statistics)) * scoreMultiplier; + return (max_score * (accuracyScore + comboScore) + getBonusScore(statistics)); case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs index 5bbca5ca1a..1f1aa4c4b3 100644 --- a/osu.Game/Screens/Select/FooterButtonMods.cs +++ b/osu.Game/Screens/Select/FooterButtonMods.cs @@ -6,14 +6,11 @@ using osu.Framework.Graphics; using osu.Game.Screens.Play.HUD; using osu.Game.Rulesets.Mods; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osuTK; -using osuTK.Graphics; using osu.Game.Input.Bindings; namespace osu.Game.Screens.Select @@ -26,10 +23,7 @@ namespace osu.Game.Screens.Select set => modDisplay.Current = value; } - protected readonly OsuSpriteText MultiplierText; private readonly ModDisplay modDisplay; - private Color4 lowMultiplierColour; - private Color4 highMultiplierColour; public FooterButtonMods() { @@ -40,12 +34,6 @@ namespace osu.Game.Screens.Select Scale = new Vector2(0.8f), ExpansionMode = ExpansionMode.AlwaysContracted, }); - ButtonContentContainer.Add(MultiplierText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - }); } [BackgroundDependencyLoader] @@ -53,8 +41,6 @@ namespace osu.Game.Screens.Select { SelectedColour = colours.Yellow; DeselectedColour = SelectedColour.Opacity(0.5f); - lowMultiplierColour = colours.Red; - highMultiplierColour = colours.Green; Text = @"mods"; Hotkey = GlobalAction.ToggleModSelection; } @@ -68,17 +54,6 @@ namespace osu.Game.Screens.Select private void updateMultiplierText() { - double multiplier = Current.Value?.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier) ?? 1; - - MultiplierText.Text = multiplier.Equals(1.0) ? string.Empty : $"{multiplier:N2}x"; - - if (multiplier > 1.0) - MultiplierText.FadeColour(highMultiplierColour, 200); - else if (multiplier < 1.0) - MultiplierText.FadeColour(lowMultiplierColour, 200); - else - MultiplierText.FadeColour(Color4.White, 200); - if (Current.Value?.Count > 0) modDisplay.FadeIn(); else