diff --git a/osu-framework b/osu-framework index 66421b8944..6134dafccb 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 66421b894444cb9c4b792f9b93a786dcff5589dd +Subproject commit 6134dafccb3368dac96d837537325c04b89fb8ee diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs index dfc9993bde..61e11f7610 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs @@ -105,6 +105,8 @@ namespace osu.Game.Rulesets.Mania.Mods public abstract class ManiaKeyMod : Mod { + // TODO: implement using the IApplicable interface. Haven't done so yet because KeyCount isn't even hooked up at the moment. + public override string ShortenedName => Name; public abstract int KeyCount { get; } public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index e535da3fcc..c78d3b1f9f 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -15,6 +15,8 @@ using System.Collections.Generic; using osu.Game.Rulesets.Osu; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Mania.Mods; using OpenTK.Graphics; namespace osu.Game.Tests.Visual @@ -68,6 +70,9 @@ namespace osu.Game.Tests.Visual case OsuRuleset or: testOsuMods(or); break; + case ManiaRuleset mr: + testManiaMods(mr); + break; } } } @@ -80,16 +85,27 @@ namespace osu.Game.Tests.Visual var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail); var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden); + var doubleTimeMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime)); + var autoPilotMod = assistMods.FirstOrDefault(m => m is OsuModAutopilot); + var easy = easierMods.FirstOrDefault(m => m is OsuModEasy); + var hardRock = harderMods.FirstOrDefault(m => m is OsuModHardRock); + testSingleMod(noFailMod); testMultiMod(doubleTimeMod); - testIncompatibleMods(noFailMod, autoPilotMod); + testIncompatibleMods(easy, hardRock); testDeselectAll(easierMods.Where(m => !(m is MultiMod))); testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour); testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour); - testMultiplierTextUnranked(autoPilotMod); + + testUnimplmentedMod(autoPilotMod); + } + + private void testManiaMods(ManiaRuleset ruleset) + { + testMultiplierTextUnranked(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom)); } private void testSingleMod(Mod mod) @@ -124,6 +140,12 @@ namespace osu.Game.Tests.Visual checkNotSelected(mod); } + private void testUnimplmentedMod(Mod mod) + { + selectNext(mod); + checkNotSelected(mod); + } + private void testIncompatibleMods(Mod modA, Mod modB) { selectNext(modA); @@ -169,9 +191,9 @@ namespace osu.Game.Tests.Visual AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix)); } - private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext()); + private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); - private void selectPrevious(Mod mod) => AddStep($"right click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectPrevious()); + private void selectPrevious(Mod mod) => AddStep($"right click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(-1)); private void checkSelected(Mod mod) { diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index c86860f7b0..ceeac516e1 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -19,6 +19,7 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.IO; using osu.Game.Database; using osu.Game.Graphics; +using osu.Game.Graphics.Textures; using osu.Game.IO; using osu.Game.IPC; using osu.Game.Online.API; @@ -651,7 +652,7 @@ namespace osu.Game.Beatmaps try { - return new TextureStore(new RawTextureLoaderStore(store), false).Get(getPathForFile(Metadata.BackgroundFile)); + return new LargeTextureStore(new RawTextureLoaderStore(store)).Get(getPathForFile(Metadata.BackgroundFile)); } catch { diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs index 8eb2ddc0ab..4fb08a41f3 100644 --- a/osu.Game/Graphics/Backgrounds/Background.cs +++ b/osu.Game/Graphics/Backgrounds/Background.cs @@ -5,8 +5,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; using OpenTK.Graphics; +using osu.Game.Graphics.Textures; namespace osu.Game.Graphics.Backgrounds { @@ -22,7 +22,6 @@ namespace osu.Game.Graphics.Backgrounds this.textureName = textureName; RelativeSizeAxes = Axes.Both; - Depth = float.MaxValue; Add(Sprite = new Sprite { @@ -35,7 +34,7 @@ namespace osu.Game.Graphics.Backgrounds } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load(LargeTextureStore textures) { if (!string.IsNullOrEmpty(textureName)) Sprite.Texture = textures.Get(textureName); diff --git a/osu.Game/Graphics/Textures/LargeTextureStore.cs b/osu.Game/Graphics/Textures/LargeTextureStore.cs new file mode 100644 index 0000000000..166364c8dd --- /dev/null +++ b/osu.Game/Graphics/Textures/LargeTextureStore.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; + +namespace osu.Game.Graphics.Textures +{ + /// + /// A texture store that bypasses atlasing. + /// + public class LargeTextureStore : TextureStore + { + public LargeTextureStore(IResourceStore store = null) : base(store, false) + { + } + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index ea0bf22112..e311aea8e4 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -18,8 +18,10 @@ using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Framework.Graphics.Performance; +using osu.Framework.Graphics.Textures; using osu.Framework.Logging; using osu.Game.Database; +using osu.Game.Graphics.Textures; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; @@ -89,6 +91,8 @@ namespace osu.Game { dependencies.Cache(contextFactory = new DatabaseContextFactory(Host)); + dependencies.Cache(new LargeTextureStore(new RawTextureLoaderStore(new NamespacedResourceStore(Resources, @"Textures")))); + dependencies.Cache(this); dependencies.Cache(LocalConfig); diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 35c2e9234d..21f07bb0a4 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -32,7 +32,10 @@ namespace osu.Game.Overlays.Mods private readonly Container iconsContainer; private SampleChannel sampleOn, sampleOff; - public Action Action; // Passed the selected mod or null if none + /// + /// Fired when the selection changes. + /// + public Action SelectionChanged; public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty; @@ -42,71 +45,73 @@ namespace osu.Game.Overlays.Mods // A selected index of -1 means not selected. private int selectedIndex = -1; - protected int SelectedIndex + /// + /// Change the selected mod index of this button. + /// + /// The new index. + /// Whether the selection changed. + private bool changeSelectedIndex(int newIndex) { - get + if (newIndex == selectedIndex) return false; + + int direction = newIndex < selectedIndex ? -1 : 1; + bool beforeSelected = Selected; + + Mod modBefore = SelectedMod ?? Mods[0]; + + if (newIndex >= Mods.Length) + newIndex = -1; + else if (newIndex < -1) + newIndex = Mods.Length - 1; + + if (newIndex >= 0 && !Mods[newIndex].HasImplementation) + return false; + + selectedIndex = newIndex; + Mod modAfter = SelectedMod ?? Mods[0]; + + if (beforeSelected != Selected) { - return selectedIndex; + iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); + iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); } - set + + if (modBefore != modAfter) { - if (value == selectedIndex) return; + const float rotate_angle = 16; - int direction = value < selectedIndex ? -1 : 1; - bool beforeSelected = Selected; + foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); + backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); - Mod modBefore = SelectedMod ?? Mods[0]; - - if (value >= Mods.Length) - selectedIndex = -1; - else if (value < -1) - selectedIndex = Mods.Length - 1; - else - selectedIndex = value; - - Mod modAfter = SelectedMod ?? Mods[0]; - - if (beforeSelected != Selected) + backgroundIcon.Icon = modAfter.Icon; + using (BeginDelayedSequence(mod_switch_duration, true)) { - iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); - iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); + foregroundIcon + .RotateTo(-rotate_angle * direction) + .RotateTo(0f, mod_switch_duration, mod_switch_easing); + + backgroundIcon + .RotateTo(rotate_angle * direction) + .RotateTo(0f, mod_switch_duration, mod_switch_easing); + + Schedule(() => displayMod(modAfter)); } - - if (modBefore != modAfter) - { - const float rotate_angle = 16; - - foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); - backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); - - backgroundIcon.Icon = modAfter.Icon; - using (BeginDelayedSequence(mod_switch_duration, true)) - { - foregroundIcon - .RotateTo(-rotate_angle * direction) - .RotateTo(0f, mod_switch_duration, mod_switch_easing); - - backgroundIcon - .RotateTo(rotate_angle * direction) - .RotateTo(0f, mod_switch_duration, mod_switch_easing); - - Schedule(() => displayMod(modAfter)); - } - } - - foregroundIcon.Highlighted = Selected; } + + foregroundIcon.Highlighted = Selected; + + (selectedIndex == -1 ? sampleOff : sampleOn).Play(); + SelectionChanged?.Invoke(SelectedMod); + return true; } - public bool Selected => SelectedIndex != -1; + public bool Selected => selectedIndex != -1; private Color4 selectedColour; + public Color4 SelectedColour { - get - { - return selectedColour; - } + get { return selectedColour; } set { if (value == selectedColour) return; @@ -116,12 +121,10 @@ namespace osu.Game.Overlays.Mods } private Mod mod; + public Mod Mod { - get - { - return mod; - } + get { return mod; } set { mod = value; @@ -147,9 +150,7 @@ namespace osu.Game.Overlays.Mods public Mod[] Mods { get; private set; } - // the mods from Mod, only multiple if Mod is a MultiMod - - public virtual Mod SelectedMod => Mods.ElementAtOrDefault(SelectedIndex); + public virtual Mod SelectedMod => Mods.ElementAtOrDefault(selectedIndex); [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -163,31 +164,42 @@ namespace osu.Game.Overlays.Mods switch (args.Button) { case MouseButton.Left: - SelectNext(); + SelectNext(1); break; case MouseButton.Right: - SelectPrevious(); + SelectNext(-1); break; } + return true; } - public void SelectNext() + /// + /// Select the next available mod in a specified direction. + /// + /// 1 for forwards, -1 for backwards. + public void SelectNext(int direction) { - (++SelectedIndex == Mods.Length ? sampleOff : sampleOn).Play(); - Action?.Invoke(SelectedMod); + int start = selectedIndex + direction; + // wrap around if we are at an extremity. + if (start >= Mods.Length) + start = -1; + else if (start < -1) + start = Mods.Length - 1; + + for (int i = start; i < Mods.Length && i >= 0; i += direction) + { + if (Mods[i].HasImplementation) + { + changeSelectedIndex(i); + return; + } + } + + Deselect(); } - public void SelectPrevious() - { - (--SelectedIndex == -1 ? sampleOff : sampleOn).Play(); - Action?.Invoke(SelectedMod); - } - - public void Deselect() - { - SelectedIndex = -1; - } + public void Deselect() => changeSelectedIndex(-1); private void displayMod(Mod mod) { @@ -195,6 +207,7 @@ namespace osu.Game.Overlays.Mods backgroundIcon.Icon = foregroundIcon.Icon; foregroundIcon.Icon = mod.Icon; text.Text = mod.Name; + Colour = mod.HasImplementation ? Color4.White : Color4.Gray; } private void createIcons() @@ -264,7 +277,8 @@ namespace osu.Game.Overlays.Mods { public override string TooltipText => null; - public PassThroughTooltipModIcon(Mod mod) : base(mod) + public PassThroughTooltipModIcon(Mod mod) + : base(mod) { } } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index aac8a72dd7..50310d1b27 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Mods return new ModButton(m) { SelectedColour = selectedColour, - Action = Action, + SelectionChanged = Action, }; }).ToArray(); @@ -83,26 +83,33 @@ namespace osu.Game.Overlays.Mods { var index = Array.IndexOf(ToggleKeys, args.Key); if (index > -1 && index < buttons.Length) - buttons[index].SelectNext(); + buttons[index].SelectNext(state.Keyboard.ShiftPressed ? -1 : 1); return base.OnKeyDown(state, args); } - public void DeselectAll() - { - foreach (ModButton button in buttons) - button.Deselect(); - } + public void DeselectAll() => DeselectTypes(buttons.Select(b => b.SelectedMod?.GetType()).Where(t => t != null)); - public void DeselectTypes(Type[] modTypes) + /// + /// Deselect one or more mods in this section. + /// + /// The types of s which should be deselected. + /// Set to true to bypass animations and update selections immediately. + public void DeselectTypes(IEnumerable modTypes, bool immediate = false) { + int delay = 0; foreach (var button in buttons) { Mod selected = button.SelectedMod; if (selected == null) continue; foreach (Type type in modTypes) if (type.IsInstanceOfType(selected)) - button.Deselect(); + { + if (immediate) + button.Deselect(); + else + Scheduler.AddDelayed(() => button.Deselect(), delay += 50); + } } } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 9639907914..cc5a17358d 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -100,17 +100,22 @@ namespace osu.Game.Overlays.Mods refreshSelectedMods(); } - public void DeselectTypes(Type[] modTypes) + /// + /// Deselect one or more mods. + /// + /// The types of s which should be deselected. + /// Set to true to bypass animations and update selections immediately. + public void DeselectTypes(Type[] modTypes, bool immediate = false) { if (modTypes.Length == 0) return; foreach (ModSection section in ModSectionsContainer.Children) - section.DeselectTypes(modTypes); + section.DeselectTypes(modTypes, immediate); } private void modButtonPressed(Mod selectedMod) { if (selectedMod != null) - DeselectTypes(selectedMod.IncompatibleMods); + DeselectTypes(selectedMod.IncompatibleMods, true); refreshSelectedMods(); } @@ -127,10 +132,6 @@ namespace osu.Game.Overlays.Mods ranked &= mod.Ranked; } - // 1.00x - // 1.05x - // 1.20x - MultiplierLabel.Text = $"{multiplier:N2}x"; if (!ranked) MultiplierLabel.Text += " (Unranked)"; diff --git a/osu.Game/Rulesets/Mods/IApplicableFailOverride.cs b/osu.Game/Rulesets/Mods/IApplicableFailOverride.cs new file mode 100644 index 0000000000..2d7cda5f1f --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableFailOverride.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Mods +{ + /// + /// Represents a mod which can override (and block) a fail. + /// + public interface IApplicableFailOverride : IApplicableMod + { + /// + /// Whether we should allow failing at the current point in time. + /// + bool AllowFail { get; } + } +} diff --git a/osu.Game/Rulesets/Mods/IApplicableMod.cs b/osu.Game/Rulesets/Mods/IApplicableMod.cs new file mode 100644 index 0000000000..ed2b652598 --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableMod.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Mods +{ + /// + /// The base interface for a mod which can be applied in some way. + /// If this is not implemented by a mod, it will not be available for use in-game. + /// + public interface IApplicableMod + { + } +} diff --git a/osu.Game/Rulesets/Mods/IApplicableToClock.cs b/osu.Game/Rulesets/Mods/IApplicableToClock.cs index f0502cf346..8bb4e2b97d 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToClock.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToClock.cs @@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for mods that make adjustments to the track. /// - public interface IApplicableToClock + public interface IApplicableToClock : IApplicableMod { void ApplyToClock(IAdjustableClock clock); } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/Mods/IApplicableToDifficulty.cs b/osu.Game/Rulesets/Mods/IApplicableToDifficulty.cs index 58f5defb5e..a95aa4370c 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToDifficulty.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToDifficulty.cs @@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for mods that make general adjustments to difficulty. /// - public interface IApplicableToDifficulty + public interface IApplicableToDifficulty : IApplicableMod { void ApplyToDifficulty(BeatmapDifficulty difficulty); } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs b/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs index 1024d5686d..66dbc85095 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for s that can be applied to s. /// - public interface IApplicableToDrawableHitObjects + public interface IApplicableToDrawableHitObjects : IApplicableMod { /// /// Applies this to a list of s. diff --git a/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs b/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs index 7f39def343..1964ad728f 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for s that can be applied to s. /// - public interface IApplicableToHitObject + public interface IApplicableToHitObject : IApplicableMod where TObject : HitObject { /// diff --git a/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs b/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs index 9b23dd58f9..eae8c9d15c 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for s that can be applied to s. /// - public interface IApplicableToRulesetContainer + public interface IApplicableToRulesetContainer : IApplicableMod where TObject : HitObject { /// diff --git a/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs b/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs index db9b713c59..2314999d4f 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for mods that make general adjustments to score processor. /// - public interface IApplicableToScoreProcessor + public interface IApplicableToScoreProcessor : IApplicableMod { void ApplyToScoreProcessor(ScoreProcessor scoreProcessor); } diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 7b0034863e..68ed545701 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -41,6 +41,11 @@ namespace osu.Game.Rulesets.Mods /// public abstract double ScoreMultiplier { get; } + /// + /// Returns true if this mod is implemented (and playable). + /// + public virtual bool HasImplementation => this is IApplicableMod; + /// /// Returns if this mod is ranked. /// @@ -50,10 +55,5 @@ namespace osu.Game.Rulesets.Mods /// The mods this mod cannot be enabled with. /// public virtual Type[] IncompatibleMods => new Type[] { }; - - /// - /// Whether we should allow failing at the current point in time. - /// - public virtual bool AllowFail => true; } } diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index 5963c5cf82..bddb97f374 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mods } } - public class ModAutoplay : Mod + public class ModAutoplay : Mod, IApplicableFailOverride { public override string Name => "Autoplay"; public override string ShortenedName => "AT"; @@ -29,6 +29,6 @@ namespace osu.Game.Rulesets.Mods public override string Description => "Watch a perfect automated play through the song"; public override double ScoreMultiplier => 0; public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) }; - public override bool AllowFail => false; + public bool AllowFail => false; } } diff --git a/osu.Game/Rulesets/Mods/ModNoFail.cs b/osu.Game/Rulesets/Mods/ModNoFail.cs index 3a3878d77e..8aefd1b88e 100644 --- a/osu.Game/Rulesets/Mods/ModNoFail.cs +++ b/osu.Game/Rulesets/Mods/ModNoFail.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics; namespace osu.Game.Rulesets.Mods { - public abstract class ModNoFail : Mod + public abstract class ModNoFail : Mod, IApplicableFailOverride { public override string Name => "NoFail"; public override string ShortenedName => "NF"; @@ -20,6 +20,6 @@ namespace osu.Game.Rulesets.Mods /// /// We never fail, 'yo. /// - public override bool AllowFail => false; + public bool AllowFail => false; } -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index de84e90baf..36867a84d5 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Threading; using osu.Game.Graphics.Backgrounds; namespace osu.Game.Screens.Backgrounds @@ -24,16 +25,22 @@ namespace osu.Game.Screens.Backgrounds private void display(Background newBackground) { - current?.FadeOut(800, Easing.OutQuint); + current?.FadeOut(800, Easing.InOutSine); current?.Expire(); Add(current = newBackground); + currentDisplay++; } + private ScheduledDelegate nextTask; + public void Next() { - currentDisplay++; - LoadComponentAsync(new Background(backgroundName) { Depth = currentDisplay }, display); + nextTask?.Cancel(); + nextTask = Scheduler.AddDelayed(() => + { + LoadComponentAsync(new Background(backgroundName) { Depth = currentDisplay }, display); + }, 100); } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 35f39e940f..d4cfa0b3d4 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -298,7 +298,7 @@ namespace osu.Game.Screens.Play private bool onFail() { - if (Beatmap.Value.Mods.Value.Any(m => !m.AllowFail)) + if (Beatmap.Value.Mods.Value.OfType().Any(m => !m.AllowFail)) return false; decoupledClock.Stop(); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 82b9f41567..519e214495 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -267,6 +267,7 @@ + @@ -310,6 +311,8 @@ + +