diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index d0d623178e..808faa511b 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Catch.Tests { - public class CatchBeatmapConversionTest : BeatmapConversionTest + internal class CatchBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Tests protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); } - public struct ConvertValue : IEquatable + internal struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. @@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Tests && Precision.AlmostEquals(Position, other.Position, conversion_lenience); } - public class TestCatchRuleset : CatchRuleset + internal class TestCatchRuleset : CatchRuleset { } } diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs index f1ee874b88..bd67a7d96a 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Mania.Tests { - public class ManiaBeatmapConversionTest : BeatmapConversionTest + internal class ManiaBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Mania"; @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Tests protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); } - public struct ConvertValue : IEquatable + internal struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Tests && Column == other.Column; } - public class TestManiaRuleset : ManiaRuleset + internal class TestManiaRuleset : ManiaRuleset { } } diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index aa7de4ed01..3d54043027 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -15,7 +15,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class OsuBeatmapConversionTest : BeatmapConversionTest + internal class OsuBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Tests protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap); } - public struct ConvertValue : IEquatable + internal struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Tests && Precision.AlmostEquals(EndY, other.EndY, conversion_lenience); } - public class TestOsuRuleset : OsuRuleset + internal class TestOsuRuleset : OsuRuleset { } } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index a12bdf7f20..793060197d 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -18,7 +18,17 @@ namespace osu.Game.Rulesets.Osu.Scoring private readonly int beatmapMaxCombo; private Mod[] mods; + + /// + /// Approach rate adjusted by mods. + /// private double realApproachRate; + + /// + /// Overall difficulty adjusted by mods. + /// + private double realOverallDifficulty; + private double accuracy; private int scoreMaxCombo; private int count300; @@ -58,8 +68,12 @@ namespace osu.Game.Rulesets.Osu.Scoring ar = Math.Min(10, ar * 1.4); if (mods.Any(m => m is OsuModEasy)) ar = Math.Max(0, ar / 2); - double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450); + + double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; + double hitWindow300 = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate; + realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5; + realOverallDifficulty = (80 - 0.5 - hitWindow300) / 6; // Custom multipliers for NoFail and SpunOut. double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things @@ -85,6 +99,9 @@ namespace osu.Game.Rulesets.Osu.Scoring categoryRatings.Add("Aim", aimValue); categoryRatings.Add("Speed", speedValue); categoryRatings.Add("Accuracy", accuracyValue); + categoryRatings.Add("OD", realOverallDifficulty); + categoryRatings.Add("AR", realApproachRate); + categoryRatings.Add("Max Combo", beatmapMaxCombo); } return totalValue; @@ -121,8 +138,9 @@ namespace osu.Game.Rulesets.Osu.Scoring aimValue *= approachRateFactor; + // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. if (mods.Any(h => h is OsuModHidden)) - aimValue *= 1.03f; + aimValue *= 1.02 + (11.0f - realApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11. if (mods.Any(h => h is OsuModFlashlight)) { @@ -133,7 +151,7 @@ namespace osu.Game.Rulesets.Osu.Scoring // Scale the aim value with accuracy _slightly_ aimValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that - aimValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500; + aimValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500; return aimValue; } @@ -159,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Scoring // Scale the speed value with accuracy _slightly_ speedValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that - speedValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500; + speedValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500; return speedValue; } @@ -181,7 +199,7 @@ namespace osu.Game.Rulesets.Osu.Scoring // Lots of arbitrary values from testing. // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution - double accuracyValue = Math.Pow(1.52163f, Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f; + double accuracyValue = Math.Pow(1.52163f, realOverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f; // Bonus for many hitcircles - it's harder to keep good accuracy up for longer accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f)); diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs index 33a5e1772e..ca4fc3ec57 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Taiko.Tests { - public class TaikoBeatmapConversionTest : BeatmapConversionTest + internal class TaikoBeatmapConversionTest : BeatmapConversionTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Tests protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap); } - public struct ConvertValue : IEquatable + internal struct ConvertValue : IEquatable { /// /// A sane value to account for osu!stable using ints everwhere. @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Tests && IsStrong == other.IsStrong; } - public class TestTaikoRuleset : TaikoRuleset + internal class TestTaikoRuleset : TaikoRuleset { } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 64219c7b52..4c9ec5473b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Taiko.Objects /// private double tickSpacing = 100; + private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY; + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); @@ -47,9 +49,7 @@ namespace osu.Game.Rulesets.Taiko.Objects TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / TickRate; - - RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); - RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); + overallDifficulty = difficulty.OverallDifficulty; } protected override void CreateNestedHitObjects() @@ -57,6 +57,9 @@ namespace osu.Game.Rulesets.Taiko.Objects base.CreateNestedHitObjects(); createTicks(); + + RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty); + RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty); } private void createTicks() diff --git a/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs new file mode 100644 index 0000000000..6fa49c4edb --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseHoldToConfirmOverlay : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(ExitConfirmOverlay) }; + + public TestCaseHoldToConfirmOverlay() + { + bool fired = false; + + var firedText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Fired!", + TextSize = 50, + Alpha = 0, + }; + + var overlay = new TestHoldToConfirmOverlay + { + Action = () => + { + fired = true; + firedText.FadeTo(1).Then().FadeOut(1000); + } + }; + + Children = new Drawable[] + { + overlay, + firedText + }; + + AddStep("start confirming", () => overlay.Begin()); + AddStep("abort confirming", () => overlay.Abort()); + + AddAssert("ensure aborted", () => !fired); + + AddStep("start confirming", () => overlay.Begin()); + + AddUntilStep(() => fired, "wait until confirmed"); + } + + private class TestHoldToConfirmOverlay : ExitConfirmOverlay + { + protected override bool AllowMultipleFires => true; + + public void Begin() => BeginConfirm(); + public void Abort() => AbortConfirm(); + } + } +} diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 37155c09cd..5cac9ed923 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps protected readonly IBeatmap Beatmap; protected readonly Mod[] Mods; - protected double TimeRate = 1; + protected double TimeRate { get; private set; } = 1; protected DifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) { diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 2a30e0d032..f657c0cae5 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -44,19 +44,6 @@ namespace osu.Game.Graphics.Containers return base.OnClick(state); } - protected override bool OnDragStart(InputState state) - { - if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position)) - { - State = Visibility.Hidden; - return true; - } - - return base.OnDragStart(state); - } - - protected override bool OnDrag(InputState state) => State == Visibility.Hidden; - private void onStateChanged(Visibility visibility) { switch (visibility) diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs new file mode 100644 index 0000000000..a0e4bf1a39 --- /dev/null +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; + +namespace osu.Game.Overlays +{ + /// + /// An overlay which will display a black screen that dims over a period before confirming an exit action. + /// Action is BYO (derived class will need to call and from a user event). + /// + public abstract class HoldToConfirmOverlay : Container + { + public Action Action; + + private Box overlay; + + private const int activate_delay = 400; + private const int fadeout_delay = 200; + + private bool fired; + + /// + /// Whether the overlay should be allowed to return from a fired state. + /// + protected virtual bool AllowMultipleFires => false; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; + + Children = new Drawable[] + { + overlay = new Box + { + Alpha = 0, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + } + }; + } + + protected void BeginConfirm() + { + if (!AllowMultipleFires && fired) return; + overlay.FadeIn(activate_delay * (1 - overlay.Alpha), Easing.Out).OnComplete(_ => + { + Action?.Invoke(); + fired = true; + }); + } + + protected void AbortConfirm() + { + if (!AllowMultipleFires && fired) return; + overlay.FadeOut(fadeout_delay, Easing.Out); + } + } +} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 27ce8d5ed4..7406a9ec4f 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Input; using OpenTK.Graphics; @@ -43,7 +44,7 @@ namespace osu.Game.Overlays.KeyBinding } private OsuSpriteText text; - private OsuSpriteText pressAKey; + private OsuTextFlowContainer pressAKey; private FillFlowContainer buttons; @@ -95,10 +96,11 @@ namespace osu.Game.Overlays.KeyBinding Anchor = Anchor.TopRight, Origin = Anchor.TopRight }, - pressAKey = new OsuSpriteText + pressAKey = new OsuTextFlowContainer { - Text = "Press a key to change binding, DEL to delete, ESC to cancel.", - Y = height, + Text = "Press a key to change binding, Shift+Delete to delete, Escape to cancel.", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Margin = new MarginPadding(padding), Alpha = 0, Colour = colours.YellowDark @@ -204,9 +206,16 @@ namespace osu.Game.Overlays.KeyBinding finalise(); return true; case Key.Delete: - bindTarget.UpdateKeyCombination(InputKey.None); - finalise(); - return true; + { + if (state.Keyboard.ShiftPressed) + { + bindTarget.UpdateKeyCombination(InputKey.None); + finalise(); + return true; + } + + break; + } } bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state)); @@ -261,7 +270,7 @@ namespace osu.Game.Overlays.KeyBinding GetContainingInputManager().ChangeFocus(null); pressAKey.FadeOut(300, Easing.OutQuint); - pressAKey.Padding = new MarginPadding { Bottom = -pressAKey.DrawHeight }; + pressAKey.Padding = new MarginPadding { Top = height, Bottom = -pressAKey.DrawHeight }; } protected override void OnFocus(InputState state) @@ -270,7 +279,7 @@ namespace osu.Game.Overlays.KeyBinding AutoSizeEasing = Easing.OutQuint; pressAKey.FadeIn(300, Easing.OutQuint); - pressAKey.Padding = new MarginPadding(); + pressAKey.Padding = new MarginPadding { Top = height }; updateBindTarget(); base.OnFocus(state); diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 67a9a59d4a..1847b63658 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets try { var assembly = Assembly.LoadFrom(file); - loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsSubclassOf(typeof(Ruleset))); + loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); } catch (Exception) { diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs index 5b8f5f0d0f..f2c495fa5d 100644 --- a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs @@ -2,7 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Timing; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Scoring { @@ -14,6 +18,8 @@ namespace osu.Game.Rulesets.Scoring protected readonly IBeatmap Beatmap; protected readonly Score Score; + protected double TimeRate { get; private set; } = 1; + protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) { Score = score; @@ -22,6 +28,15 @@ namespace osu.Game.Rulesets.Scoring var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods); diffCalc.Calculate(attributes); + + ApplyMods(score.Mods); + } + + protected virtual void ApplyMods(Mod[] mods) + { + var clock = new StopwatchClock(); + mods.OfType().ForEach(m => m.ApplyToClock(clock)); + TimeRate = clock.Rate; } public abstract double Calculate(Dictionary categoryDifficulty = null); diff --git a/osu.Game/Screens/Menu/ExitConfirmOverlay.cs b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs new file mode 100644 index 0000000000..62605da5a4 --- /dev/null +++ b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input; +using osu.Game.Overlays; +using OpenTK.Input; + +namespace osu.Game.Screens.Menu +{ + public class ExitConfirmOverlay : HoldToConfirmOverlay + { + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Key == Key.Escape && !args.Repeat) + { + BeginConfirm(); + return true; + } + + return base.OnKeyDown(state, args); + } + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + { + if (args.Key == Key.Escape) + { + AbortConfirm(); + return true; + } + + return base.OnKeyUp(state, args); + } + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 907ad81111..e564ab786d 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -39,6 +39,10 @@ namespace osu.Game.Screens.Menu Children = new Drawable[] { + new ExitConfirmOverlay + { + Action = Exit, + }, new ParallaxContainer { ParallaxAmount = 0.01f, diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index a018a2697a..926a96eb6c 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -1,50 +1,19 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; -using System; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; -using OpenTK.Graphics; +using osu.Game.Overlays; namespace osu.Game.Screens.Play { - public class HotkeyRetryOverlay : Container, IKeyBindingHandler + public class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler { - public Action Action; - - private Box overlay; - - private const int activate_delay = 400; - private const int fadeout_delay = 200; - - private bool fired; - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - AlwaysPresent = true; - - Children = new Drawable[] - { - overlay = new Box - { - Alpha = 0, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Both, - } - }; - } - public bool OnPressed(GlobalAction action) { if (action != GlobalAction.QuickRetry) return false; - overlay.FadeIn(activate_delay, Easing.Out); + BeginConfirm(); return true; } @@ -52,18 +21,8 @@ namespace osu.Game.Screens.Play { if (action != GlobalAction.QuickRetry) return false; - overlay.FadeOut(fadeout_delay, Easing.Out); + AbortConfirm(); return true; } - - protected override void Update() - { - base.Update(); - if (!fired && overlay.Alpha == 1) - { - fired = true; - Action?.Invoke(); - } - } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index f397d0c3d4..4a46279d30 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -162,7 +162,7 @@ namespace osu.Game.Screens.Play hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, OnResume = () => hudOverlay.KeyCounter.IsCounting = true, - Children = new Drawable[] + Children = new[] { storyboardContainer = new Container { @@ -174,12 +174,12 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.Both, Child = RulesetContainer }, - new SkipOverlay(firstObjectTime) + new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor) { - Clock = Clock, // skip button doesn't want to use the audio clock directly + Anchor = Anchor.Centre, + Origin = Anchor.Centre, ProcessCustomClock = false, - AdjustableClock = adjustableClock, - FramedClock = offsetClock, + Breaks = beatmap.Breaks }, hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { @@ -188,13 +188,14 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre }, - new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor) + RulesetContainer.Cursor?.CreateProxy() ?? new Container(), + new SkipOverlay(firstObjectTime) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Clock = Clock, // skip button doesn't want to use the audio clock directly ProcessCustomClock = false, - Breaks = beatmap.Breaks - } + AdjustableClock = adjustableClock, + FramedClock = offsetClock, + }, } }, failOverlay = new FailOverlay