mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 20:22:55 +08:00
Merge branch 'master' into mods-stable-ordering
This commit is contained in:
commit
8215c4cb0e
@ -45,9 +45,9 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
[TestCase(ScoringMode.Standardised, HitResult.Meh, 116_667)]
|
||||
[TestCase(ScoringMode.Standardised, HitResult.Ok, 233_338)]
|
||||
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Meh, 0)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Ok, 2)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Great, 36)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Meh, 11_670)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Ok, 23_341)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Great, 100_033)]
|
||||
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
||||
{
|
||||
scoreProcessor.ApplyBeatmap(beatmap);
|
||||
@ -84,17 +84,17 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
||||
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)]
|
||||
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 4)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 15)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 53)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 140)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 140)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 7_975)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 15_949)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 30_398)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 49_546)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 49_546)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 0)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 11)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 54_189)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 9)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 36)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 36)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 49_289)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 100_003)]
|
||||
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 100_015)]
|
||||
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
|
||||
{
|
||||
var minResult = new TestJudgement(hitResult).MinResult;
|
||||
|
@ -312,7 +312,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
createSongSelect();
|
||||
|
||||
addRulesetImportStep(0);
|
||||
// We need to use one real beatmap to trigger the "same-track-transfer" logic that we're looking to test here.
|
||||
// See `SongSelect.ensurePlayingSelected` and `WorkingBeatmap.TryTransferTrack`.
|
||||
AddStep("import test beatmap", () => manager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).WaitSafely());
|
||||
addRulesetImportStep(0);
|
||||
|
||||
checkMusicPlaying(true);
|
||||
@ -321,6 +323,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("manual pause", () => music.TogglePause());
|
||||
checkMusicPlaying(false);
|
||||
|
||||
// Track should not have changed, so music should still not be playing.
|
||||
AddStep("select next difficulty", () => songSelect!.Carousel.SelectNext(skipDifficulties: false));
|
||||
checkMusicPlaying(false);
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
@ -25,6 +29,53 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
ChildrenEnumerable = Ruleset.Value.CreateInstance().CreateAllMods().Select(m => new ModIcon(m)),
|
||||
};
|
||||
});
|
||||
|
||||
AddStep("toggle selected", () =>
|
||||
{
|
||||
foreach (var icon in this.ChildrenOfType<ModIcon>())
|
||||
icon.Selected.Toggle();
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestShowRateAdjusts()
|
||||
{
|
||||
AddStep("create mod icons", () =>
|
||||
{
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Full,
|
||||
ChildrenEnumerable = Ruleset.Value.CreateInstance().CreateAllMods()
|
||||
.OfType<ModRateAdjust>()
|
||||
.SelectMany(m =>
|
||||
{
|
||||
List<ModIcon> icons = new List<ModIcon> { new ModIcon(m) };
|
||||
|
||||
for (double i = m.SpeedChange.MinValue; i < m.SpeedChange.MaxValue; i += m.SpeedChange.Precision * 10)
|
||||
{
|
||||
m = (ModRateAdjust)m.DeepClone();
|
||||
m.SpeedChange.Value = i;
|
||||
icons.Add(new ModIcon(m));
|
||||
}
|
||||
|
||||
return icons;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
AddStep("adjust rates", () =>
|
||||
{
|
||||
foreach (var icon in this.ChildrenOfType<ModIcon>())
|
||||
{
|
||||
if (icon.Mod is ModRateAdjust rateAdjust)
|
||||
{
|
||||
rateAdjust.SpeedChange.Value = RNG.NextDouble() > 0.9
|
||||
? rateAdjust.SpeedChange.Default
|
||||
: RNG.NextDouble(rateAdjust.SpeedChange.MinValue, rateAdjust.SpeedChange.MaxValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -89,6 +89,8 @@ namespace osu.Game.Graphics
|
||||
public static IconUsage ModSpunOut => Get(0xe046);
|
||||
public static IconUsage ModSuddenDeath => Get(0xe047);
|
||||
public static IconUsage ModTarget => Get(0xe048);
|
||||
public static IconUsage ModBg => Get(0xe04a);
|
||||
|
||||
// Use "Icons/BeatmapDetails/mod-icon" instead
|
||||
// public static IconUsage ModBg => Get(0xe04a);
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
Spacing = new Vector2(2f, 0f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ModIcon(mod, showTooltip: false).With(icon =>
|
||||
new ModIcon(mod, showTooltip: false, showExtendedInformation: false).With(icon =>
|
||||
{
|
||||
icon.Origin = Anchor.CentreLeft;
|
||||
icon.Anchor = Anchor.CentreLeft;
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -28,6 +31,9 @@ namespace osu.Game.Overlays.Dialog
|
||||
private readonly Vector2 ringMinifiedSize = new Vector2(20f);
|
||||
private readonly Vector2 buttonsEnterSpacing = new Vector2(0f, 50f);
|
||||
|
||||
private readonly Box flashLayer;
|
||||
private Sample flashSample = null!;
|
||||
|
||||
private readonly Container content;
|
||||
private readonly Container ring;
|
||||
private readonly FillFlowContainer<PopupDialogButton> buttonsContainer;
|
||||
@ -208,6 +214,13 @@ namespace osu.Game.Overlays.Dialog
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
flashLayer = new Box
|
||||
{
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Colour = Color4Extensions.FromHex(@"221a21"),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -217,6 +230,12 @@ namespace osu.Game.Overlays.Dialog
|
||||
Show();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
flashSample = audio.Samples.Get(@"UI/default-select-disabled");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Programmatically clicks the first <see cref="PopupDialogOkButton"/>.
|
||||
/// </summary>
|
||||
@ -232,6 +251,14 @@ namespace osu.Game.Overlays.Dialog
|
||||
Scheduler.AddOnce(() => Buttons.OfType<T>().FirstOrDefault()?.TriggerClick());
|
||||
}
|
||||
|
||||
public void Flash()
|
||||
{
|
||||
flashLayer.FadeInFromZero(80, Easing.OutQuint)
|
||||
.Then()
|
||||
.FadeOutFromOne(1500, Easing.OutQuint);
|
||||
flashSample.Play();
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
if (e.Repeat) return false;
|
||||
|
@ -19,6 +19,13 @@ namespace osu.Game.Rulesets.Mods
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Short important information to display on the mod icon. For example, a rate adjust mod's rate
|
||||
/// or similarly important setting.
|
||||
/// Use <see cref="string.Empty"/> if the icon should not display any additional info.
|
||||
/// </summary>
|
||||
string ExtendedIconInformation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The user readable description of this mod.
|
||||
/// </summary>
|
||||
|
@ -27,6 +27,9 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public abstract string Acronym { get; }
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual string ExtendedIconInformation => string.Empty;
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual IconUsage? Icon => null;
|
||||
|
||||
|
@ -28,5 +28,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModTimeRamp), typeof(ModAdaptiveSpeed), typeof(ModRateAdjust) };
|
||||
|
||||
public override string SettingDescription => SpeedChange.IsDefault ? string.Empty : $"{SpeedChange.Value:N2}x";
|
||||
|
||||
public override string ExtendedIconInformation => SettingDescription;
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Localisation;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -27,22 +27,27 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
public readonly BindableBool Selected = new BindableBool();
|
||||
|
||||
private readonly SpriteIcon modIcon;
|
||||
private readonly SpriteText modAcronym;
|
||||
private readonly SpriteIcon background;
|
||||
private SpriteIcon modIcon = null!;
|
||||
private SpriteText modAcronym = null!;
|
||||
private Sprite background = null!;
|
||||
|
||||
private const float size = 80;
|
||||
public static readonly Vector2 MOD_ICON_SIZE = new Vector2(80);
|
||||
|
||||
public virtual LocalisableString TooltipText => showTooltip ? ((mod as Mod)?.IconTooltip ?? mod.Name) : null;
|
||||
public virtual LocalisableString TooltipText => showTooltip ? ((mod as Mod)?.IconTooltip ?? mod.Name) : string.Empty;
|
||||
|
||||
private IMod mod;
|
||||
|
||||
private readonly bool showTooltip;
|
||||
private readonly bool showExtendedInformation;
|
||||
|
||||
public IMod Mod
|
||||
{
|
||||
get => mod;
|
||||
set
|
||||
{
|
||||
if (mod == value)
|
||||
return;
|
||||
|
||||
mod = value;
|
||||
|
||||
if (IsLoaded)
|
||||
@ -51,49 +56,103 @@ namespace osu.Game.Rulesets.UI
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
private Color4 backgroundColour;
|
||||
|
||||
private Sprite extendedBackground = null!;
|
||||
|
||||
private OsuSpriteText extendedText = null!;
|
||||
|
||||
private Container extendedContent = null!;
|
||||
|
||||
private ModSettingChangeTracker? modSettingsChangeTracker;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new instance.
|
||||
/// </summary>
|
||||
/// <param name="mod">The mod to be displayed</param>
|
||||
/// <param name="showTooltip">Whether a tooltip describing the mod should display on hover.</param>
|
||||
public ModIcon(IMod mod, bool showTooltip = true)
|
||||
/// <param name="showExtendedInformation">Whether to display a mod's extended information, if available.</param>
|
||||
public ModIcon(IMod mod, bool showTooltip = true, bool showExtendedInformation = true)
|
||||
{
|
||||
// May expand due to expanded content, so autosize here.
|
||||
AutoSizeAxes = Axes.X;
|
||||
Height = MOD_ICON_SIZE.Y;
|
||||
|
||||
this.mod = mod ?? throw new ArgumentNullException(nameof(mod));
|
||||
this.showTooltip = showTooltip;
|
||||
this.showExtendedInformation = showExtendedInformation;
|
||||
}
|
||||
|
||||
Size = new Vector2(size);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new SpriteIcon
|
||||
extendedContent = new Container
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Size = new Vector2(size),
|
||||
Icon = OsuIcon.ModBg,
|
||||
Shadow = true,
|
||||
Name = "extended content",
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(116, MOD_ICON_SIZE.Y),
|
||||
X = MOD_ICON_SIZE.X - 22,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
extendedBackground = new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Texture = textures.Get("Icons/BeatmapDetails/mod-icon-extender"),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
extendedText = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.Default.With(size: 34f, weight: FontWeight.Bold),
|
||||
UseFullGlyphHeight = false,
|
||||
Text = mod.ExtendedIconInformation,
|
||||
X = 6,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
}
|
||||
},
|
||||
modAcronym = new OsuSpriteText
|
||||
new Container
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Colour = OsuColour.Gray(84),
|
||||
Alpha = 0,
|
||||
Font = OsuFont.Numeric.With(null, 22f),
|
||||
UseFullGlyphHeight = false,
|
||||
Text = mod.Acronym
|
||||
},
|
||||
modIcon = new SpriteIcon
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Colour = OsuColour.Gray(84),
|
||||
Size = new Vector2(45),
|
||||
Icon = FontAwesome.Solid.Question
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Name = "main content",
|
||||
Size = MOD_ICON_SIZE,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Texture = textures.Get("Icons/BeatmapDetails/mod-icon"),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
modAcronym = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Colour = OsuColour.Gray(84),
|
||||
Alpha = 0,
|
||||
Font = OsuFont.Numeric.With(null, 22f),
|
||||
UseFullGlyphHeight = false,
|
||||
Text = mod.Acronym
|
||||
},
|
||||
modIcon = new SpriteIcon
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Colour = OsuColour.Gray(84),
|
||||
Size = new Vector2(45),
|
||||
Icon = FontAwesome.Solid.Question
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -109,6 +168,14 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
private void updateMod(IMod value)
|
||||
{
|
||||
modSettingsChangeTracker?.Dispose();
|
||||
|
||||
if (value is Mod actualMod)
|
||||
{
|
||||
modSettingsChangeTracker = new ModSettingChangeTracker(new[] { actualMod });
|
||||
modSettingsChangeTracker.SettingChanged = _ => updateExtendedInformation();
|
||||
}
|
||||
|
||||
modAcronym.Text = value.Acronym;
|
||||
modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question;
|
||||
|
||||
@ -125,11 +192,28 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
backgroundColour = colours.ForModType(value.Type);
|
||||
updateColour();
|
||||
|
||||
updateExtendedInformation();
|
||||
}
|
||||
|
||||
private void updateExtendedInformation()
|
||||
{
|
||||
bool showExtended = showExtendedInformation && !string.IsNullOrEmpty(mod.ExtendedIconInformation);
|
||||
|
||||
extendedContent.Alpha = showExtended ? 1 : 0;
|
||||
extendedText.Text = mod.ExtendedIconInformation;
|
||||
}
|
||||
|
||||
private void updateColour()
|
||||
{
|
||||
background.Colour = Selected.Value ? backgroundColour.Lighten(0.2f) : backgroundColour;
|
||||
extendedText.Colour = background.Colour = Selected.Value ? backgroundColour.Lighten(0.2f) : backgroundColour;
|
||||
extendedBackground.Colour = Selected.Value ? backgroundColour.Darken(2.4f) : backgroundColour.Darken(2.8f);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
modSettingsChangeTracker?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
@ -23,8 +24,8 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
private readonly IMod mod;
|
||||
|
||||
private readonly SpriteIcon background;
|
||||
private readonly SpriteIcon? modIcon;
|
||||
private Drawable background = null!;
|
||||
private SpriteIcon? modIcon;
|
||||
|
||||
private Color4 activeForegroundColour;
|
||||
private Color4 inactiveForegroundColour;
|
||||
@ -36,19 +37,24 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
this.mod = mod;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Size = new Vector2(DEFAULT_SIZE);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures, OsuColour colours, OverlayColourProvider? colourProvider)
|
||||
{
|
||||
FillFlowContainer contentFlow;
|
||||
ModSwitchTiny tinySwitch;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChildren = new[]
|
||||
{
|
||||
background = new SpriteIcon
|
||||
background = new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Texture = textures.Get("Icons/BeatmapDetails/mod-icon"),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(DEFAULT_SIZE),
|
||||
Icon = OsuIcon.ModBg
|
||||
},
|
||||
contentFlow = new FillFlowContainer
|
||||
{
|
||||
@ -78,11 +84,7 @@ namespace osu.Game.Rulesets.UI
|
||||
});
|
||||
tinySwitch.Scale = new Vector2(0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, OverlayColourProvider? colourProvider)
|
||||
{
|
||||
inactiveForegroundColour = colourProvider?.Background5 ?? colours.Gray3;
|
||||
activeForegroundColour = colours.ForModType(mod.Type);
|
||||
|
||||
|
@ -27,44 +27,37 @@ namespace osu.Game.Scoring.Legacy
|
||||
.DefaultIfEmpty(0)
|
||||
.Sum();
|
||||
|
||||
// This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring.
|
||||
// The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes.
|
||||
double scaledRawScore = score / ScoreProcessor.MAX_SCORE;
|
||||
|
||||
return (long)Math.Round(Math.Pow(scaledRawScore * Math.Max(1, maxBasicJudgements), 2) * getStandardisedToClassicMultiplier(rulesetId));
|
||||
return convertStandardisedToClassic(rulesetId, score, maxBasicJudgements);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a ballpark multiplier which gives a similar "feel" for how large scores should get when displayed in "classic" mode.
|
||||
/// Returns a ballpark "classic" score which gives a similar "feel" to stable.
|
||||
/// This is different per ruleset to match the different algorithms used in the scoring implementation.
|
||||
/// </summary>
|
||||
private static double getStandardisedToClassicMultiplier(int rulesetId)
|
||||
/// <remarks>
|
||||
/// The coefficients chosen here were determined by a least-squares fit performed over all beatmaps
|
||||
/// with the goal of minimising the relative error of maximum possible base score (without bonus).
|
||||
/// The constant coefficients (100000, 1 / 10d) - while being detrimental to the least-squares fit - are forced,
|
||||
/// so that every 10 points in standardised mode converts to at least 1 point in classic mode.
|
||||
/// This is done to account for bonus judgements in a way that does not reorder scores.
|
||||
/// </remarks>
|
||||
private static long convertStandardisedToClassic(int rulesetId, long standardisedTotalScore, int objectCount)
|
||||
{
|
||||
double multiplier;
|
||||
|
||||
switch (rulesetId)
|
||||
{
|
||||
// For non-legacy rulesets, just go with the same as the osu! ruleset.
|
||||
// This is arbitrary, but at least allows the setting to do something to the score.
|
||||
default:
|
||||
case 0:
|
||||
multiplier = 36;
|
||||
break;
|
||||
return (long)Math.Round((objectCount * objectCount * 32.57 + 100000) * standardisedTotalScore / ScoreProcessor.MAX_SCORE);
|
||||
|
||||
case 1:
|
||||
multiplier = 22;
|
||||
break;
|
||||
return (long)Math.Round((objectCount * 1109 + 100000) * standardisedTotalScore / ScoreProcessor.MAX_SCORE);
|
||||
|
||||
case 2:
|
||||
multiplier = 28;
|
||||
break;
|
||||
return (long)Math.Round(Math.Pow(standardisedTotalScore / ScoreProcessor.MAX_SCORE * objectCount, 2) * 21.62 + standardisedTotalScore / 10d);
|
||||
|
||||
case 3:
|
||||
multiplier = 16;
|
||||
break;
|
||||
default:
|
||||
return standardisedTotalScore;
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
public static int? GetCountGeki(this ScoreInfo scoreInfo)
|
||||
|
@ -714,8 +714,11 @@ namespace osu.Game.Screens.Edit
|
||||
}
|
||||
|
||||
// if the dialog is already displayed, block exiting until the user explicitly makes a decision.
|
||||
if (dialogOverlay.CurrentDialog is PromptForSaveDialog)
|
||||
if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog)
|
||||
{
|
||||
saveDialog.Flash();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isNewBeatmap || HasUnsavedChanges)
|
||||
{
|
||||
|
@ -247,7 +247,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
contentIn();
|
||||
|
||||
MetadataInfo.Delay(750).FadeIn(500);
|
||||
MetadataInfo.Delay(750).FadeIn(500, Easing.OutQuint);
|
||||
|
||||
// after an initial delay, start the debounced load check.
|
||||
// this will continue to execute even after resuming back on restart.
|
||||
@ -420,7 +420,7 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
MetadataInfo.Loading = true;
|
||||
|
||||
content.FadeInFromZero(400);
|
||||
content.FadeInFromZero(500, Easing.OutQuint);
|
||||
content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer);
|
||||
|
||||
settingsScroll.FadeInFromZero(500, Easing.Out)
|
||||
|
@ -525,7 +525,11 @@ namespace osu.Game.Screens.Select
|
||||
if (beatmapInfoNoDebounce == null)
|
||||
run();
|
||||
else
|
||||
selectionChangedDebounce = Scheduler.AddDelayed(run, 200);
|
||||
{
|
||||
// Intentionally slightly higher than repeat_tick_rate to avoid loading songs when holding left / right arrows.
|
||||
// See https://github.com/ppy/osu-framework/blob/master/osu.Framework/Input/InputManager.cs#L44
|
||||
selectionChangedDebounce = Scheduler.AddDelayed(run, 80);
|
||||
}
|
||||
|
||||
if (beatmap?.Equals(beatmapInfoPrevious) != true)
|
||||
{
|
||||
|
@ -37,7 +37,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="11.5.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2023.922.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.914.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.928.0" />
|
||||
<PackageReference Include="Sentry" Version="3.39.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.33.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
|
Loading…
Reference in New Issue
Block a user