Skip to content

Commit

Permalink
Merge pull request #26934 from bdach/which-mods-for-pp
Browse files Browse the repository at this point in the history
Display which mods grant pp
  • Loading branch information
peppy authored Feb 4, 2024
2 parents ef2e230 + 865f4d7 commit c64d414
Show file tree
Hide file tree
Showing 30 changed files with 200 additions and 70 deletions.
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public abstract class ManiaKeyMod : Mod, IApplicableToBeatmapConverter
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
public override bool Ranked => UsesDefaultConfiguration;

public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
{
Expand Down
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModHardRock : ModHardRock
{
public override double ScoreMultiplier => 1;
public override bool Ranked => false;
}
}
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public class ManiaModKey1 : ManiaKeyMod
public override string Name => "One Key";
public override string Acronym => "1K";
public override LocalisableString Description => @"Play with one key.";
public override bool Ranked => false;
}
}
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public class ManiaModKey10 : ManiaKeyMod
public override string Name => "Ten Keys";
public override string Acronym => "10K";
public override LocalisableString Description => @"Play with ten keys.";
public override bool Ranked => false;
}
}
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public class ManiaModKey2 : ManiaKeyMod
public override string Name => "Two Keys";
public override string Acronym => "2K";
public override LocalisableString Description => @"Play with two keys.";
public override bool Ranked => false;
}
}
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public class ManiaModKey3 : ManiaKeyMod
public override string Name => "Three Keys";
public override string Acronym => "3K";
public override LocalisableString Description => @"Play with three keys.";
public override bool Ranked => false;
}
}
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModMirror : ModMirror, IApplicableToBeatmap
{
public override LocalisableString Description => "Notes are flipped horizontally.";
public override bool Ranked => UsesDefaultConfiguration;

public void ApplyToBeatmap(IBeatmap beatmap)
{
Expand Down
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class OsuModSpunOut : Mod, IApplicableToDrawableHitObject
public override LocalisableString Description => @"Spinners will be automatically completed.";
public override double ScoreMultiplier => 0.9;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTargetPractice) };
public override bool Ranked => UsesDefaultConfiguration;

public void ApplyToDrawableHitObject(DrawableHitObject hitObject)
{
Expand Down
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModTouchDevice : ModTouchDevice
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
public override bool Ranked => UsesDefaultConfiguration;
}
}
11 changes: 11 additions & 0 deletions osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
Expand Down Expand Up @@ -67,6 +68,15 @@ public void TestClearMultiplier()
AddAssert(@"Check empty multiplier", () => assertModsMultiplier(Array.Empty<Mod>()));
}

[Test]
public void TestUnrankedBadge()
{
AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModDeflate() }));
AddAssert("Unranked badge shown", () => footerButtonMods.UnrankedBadge.Alpha == 1);
AddStep(@"Clear selected mod", () => changeMods(Array.Empty<Mod>()));
AddAssert("Unranked badge not shown", () => footerButtonMods.UnrankedBadge.Alpha == 0);
}

private void changeMods(IReadOnlyList<Mod> mods)
{
footerButtonMods.Current.Value = mods;
Expand All @@ -83,6 +93,7 @@ private bool assertModsMultiplier(IEnumerable<Mod> mods)
private partial class TestFooterButtonMods : FooterButtonMods
{
public new OsuSpriteText MultiplierText => base.MultiplierText;
public new Drawable UnrankedBadge => base.UnrankedBadge;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public void TestPreexistingSelection()
AddAssert("mod multiplier correct", () =>
{
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType<ScoreMultiplierDisplay>().Single().Current.Value);
return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
});
assertCustomisationToggleState(disabled: false, active: false);
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType<ISettingsItem>().Any());
Expand All @@ -134,7 +134,7 @@ public void TestExternalSelection()
AddAssert("mod multiplier correct", () =>
{
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType<ScoreMultiplierDisplay>().Single().Current.Value);
return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
});
assertCustomisationToggleState(disabled: false, active: false);
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType<ISettingsItem>().Any());
Expand Down Expand Up @@ -846,7 +846,7 @@ public void TestModMultiplierUpdates()
InputManager.Click(MouseButton.Left);
});
AddAssert("difficulty multiplier display shows correct value",
() => modSelectOverlay.ChildrenOfType<ScoreMultiplierDisplay>().Single().Current.Value, () => Is.EqualTo(0.1).Within(Precision.DOUBLE_EPSILON));
() => modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(0.1).Within(Precision.DOUBLE_EPSILON));

// this is highly unorthodox in a test, but because the `ModSettingChangeTracker` machinery heavily leans on events and object disposal and re-creation,
// it is instrumental in the reproduction of the failure scenario that this test is supposed to cover.
Expand All @@ -856,7 +856,7 @@ public void TestModMultiplierUpdates()
AddStep("reset half time speed to default", () => modSelectOverlay.ChildrenOfType<ModSettingsArea>().Single()
.ChildrenOfType<RevertToDefaultButton<double>>().Single().TriggerClick());
AddUntilStep("difficulty multiplier display shows correct value",
() => modSelectOverlay.ChildrenOfType<ScoreMultiplierDisplay>().Single().Current.Value, () => Is.EqualTo(0.3).Within(Precision.DOUBLE_EPSILON));
() => modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(0.3).Within(Precision.DOUBLE_EPSILON));
}

private void waitForColumnLoad() => AddUntilStep("all column content loaded", () =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,32 @@
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
public partial class TestSceneScoreMultiplierDisplay : OsuTestScene
public partial class TestSceneRankingInformationDisplay : OsuTestScene
{
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);

[Test]
public void TestBasic()
{
ScoreMultiplierDisplay multiplierDisplay = null!;
RankingInformationDisplay onlinePropertiesDisplay = null!;

AddStep("create content", () => Child = multiplierDisplay = new ScoreMultiplierDisplay
AddStep("create content", () => Child = onlinePropertiesDisplay = new RankingInformationDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});

AddStep("set multiplier below 1", () => multiplierDisplay.Current.Value = 0.5);
AddStep("set multiplier to 1", () => multiplierDisplay.Current.Value = 1);
AddStep("set multiplier above 1", () => multiplierDisplay.Current.Value = 1.5);
AddToggleStep("toggle ranked", ranked => onlinePropertiesDisplay.Ranked.Value = ranked);

AddStep("set multiplier below 1", () => onlinePropertiesDisplay.ModMultiplier.Value = 0.5);
AddStep("set multiplier to 1", () => onlinePropertiesDisplay.ModMultiplier.Value = 1);
AddStep("set multiplier above 1", () => onlinePropertiesDisplay.ModMultiplier.Value = 1.5);

AddSliderStep("set multiplier", 0, 2, 1d, multiplier =>
{
if (multiplierDisplay.IsNotNull())
multiplierDisplay.Current.Value = multiplier;
if (onlinePropertiesDisplay.IsNotNull())
onlinePropertiesDisplay.ModMultiplier.Value = multiplier;
});
}
}
Expand Down
20 changes: 20 additions & 0 deletions osu.Game/Localisation/ModSelectOverlayStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ public static class ModSelectOverlayStrings
/// </summary>
public static LocalisableString ScoreMultiplier => new TranslatableString(getKey(@"score_multiplier"), @"Score Multiplier");

/// <summary>
/// "Ranked"
/// </summary>
public static LocalisableString Ranked => new TranslatableString(getKey(@"ranked"), @"Ranked");

/// <summary>
/// "Performance points can be granted for the active mods."
/// </summary>
public static LocalisableString RankedExplanation => new TranslatableString(getKey(@"ranked_explanation"), @"Performance points can be granted for the active mods.");

/// <summary>
/// "Unranked"
/// </summary>
public static LocalisableString Unranked => new TranslatableString(getKey(@"unranked"), @"Unranked");

/// <summary>
/// "Performance points will not be granted due to active mods."
/// </summary>
public static LocalisableString UnrankedExplanation => new TranslatableString(getKey(@"ranked_explanation"), @"Performance points will not be granted due to active mods.");

private static string getKey(string key) => $@"{prefix}:{key}";
}
}
19 changes: 10 additions & 9 deletions osu.Game/Overlays/Mods/ModSelectOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ protected virtual IEnumerable<ShearedButton> CreateFooterButtons()
private DeselectAllModsButton deselectAllModsButton = null!;

private Container aboveColumnsContent = null!;
private ScoreMultiplierDisplay? multiplierDisplay;
private RankingInformationDisplay? rankingInformationDisplay;
private BeatmapAttributesDisplay? beatmapAttributesDisplay;

protected ShearedButton BackButton { get; private set; } = null!;
Expand Down Expand Up @@ -185,7 +185,7 @@ private void load(OsuGameBase game, OsuColour colours, AudioManager audio, OsuCo
aboveColumnsContent = new Container
{
RelativeSizeAxes = Axes.X,
Height = ScoreMultiplierDisplay.HEIGHT,
Height = RankingInformationDisplay.HEIGHT,
Padding = new MarginPadding { Horizontal = 100 },
Child = SearchTextBox = new ShearedSearchTextBox
{
Expand All @@ -200,7 +200,7 @@ private void load(OsuGameBase game, OsuColour colours, AudioManager audio, OsuCo
{
Padding = new MarginPadding
{
Top = ScoreMultiplierDisplay.HEIGHT + PADDING,
Top = RankingInformationDisplay.HEIGHT + PADDING,
Bottom = PADDING
},
RelativeSizeAxes = Axes.Both,
Expand Down Expand Up @@ -269,7 +269,7 @@ private void load(OsuGameBase game, OsuColour colours, AudioManager audio, OsuCo
},
Children = new Drawable[]
{
multiplierDisplay = new ScoreMultiplierDisplay
rankingInformationDisplay = new RankingInformationDisplay
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight
Expand Down Expand Up @@ -315,7 +315,7 @@ protected override void LoadComplete()

SelectedMods.BindValueChanged(_ =>
{
updateMultiplier();
updateRankingInformation();
updateFromExternalSelection();
updateCustomisation();
Expand All @@ -328,7 +328,7 @@ protected override void LoadComplete()
//
// See https://github.com/ppy/osu/pull/23284#issuecomment-1529056988
modSettingChangeTracker = new ModSettingChangeTracker(SelectedMods.Value);
modSettingChangeTracker.SettingChanged += _ => updateMultiplier();
modSettingChangeTracker.SettingChanged += _ => updateRankingInformation();
}
}, true);

Expand Down Expand Up @@ -450,17 +450,18 @@ private void filterMods()
modState.ValidForSelection.Value = modState.Mod.Type != ModType.System && modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
}

private void updateMultiplier()
private void updateRankingInformation()
{
if (multiplierDisplay == null)
if (rankingInformationDisplay == null)
return;

double multiplier = 1.0;

foreach (var mod in SelectedMods.Value)
multiplier *= mod.ScoreMultiplier;

multiplierDisplay.Current.Value = multiplier;
rankingInformationDisplay.ModMultiplier.Value = multiplier;
rankingInformationDisplay.Ranked.Value = SelectedMods.Value.All(m => m.Ranked);
}

private void updateCustomisation()
Expand Down
Loading

0 comments on commit c64d414

Please sign in to comment.