diff --git a/osu-framework b/osu-framework index e5f0cf73c1..925bbe42ba 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e5f0cf73c1e0bbcbd04194bf175d73af47fc850a +Subproject commit 925bbe42bab95078b9d33189205b5b1b76bf8e01 diff --git a/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs new file mode 100644 index 0000000000..fb5be719c1 --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Testing; +using osu.Game.Screens.Play; + +namespace osu.Desktop.VisualTests.Tests +{ + internal class TestCaseSkipButton : TestCase + { + public override string Description => @"Skip skip skippediskip"; + + public override void Reset() + { + base.Reset(); + Add(new SkipButton(Clock.CurrentTime + 5000)); + } + } +} diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTooltip.cs b/osu.Desktop.VisualTests/Tests/TestCaseTooltip.cs deleted file mode 100644 index c536672314..0000000000 --- a/osu.Desktop.VisualTests/Tests/TestCaseTooltip.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Testing; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Configuration; -using OpenTK; -using osu.Game.Graphics; - -namespace osu.Desktop.VisualTests.Tests -{ - internal class TestCaseTooltip : TestCase - { - public override string Description => "tests tooltips on various elements"; - - public override void Reset() - { - base.Reset(); - OsuSliderBar slider; - OsuSliderBar sliderDouble; - - const float width = 400; - - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 10), - Children = new Drawable[] - { - new TooltipTextContainer("text with a tooltip"), - new TooltipTextContainer("more text with another tooltip"), - new TooltipTextbox - { - Text = "a textbox with a tooltip", - Size = new Vector2(width,30), - }, - slider = new OsuSliderBar - { - Width = width, - }, - sliderDouble = new OsuSliderBar - { - Width = width, - }, - }, - }, - }; - - slider.Current.BindTo(new BindableInt(5) - { - MaxValue = 10, - MinValue = 0 - }); - - sliderDouble.Current.BindTo(new BindableDouble(0.5) - { - MaxValue = 1, - MinValue = 0 - }); - } - - private class TooltipTextContainer : Container, IHasTooltip - { - private readonly OsuSpriteText text; - - public string TooltipText => text.Text; - - public TooltipTextContainer(string tooltipText) - { - AutoSizeAxes = Axes.Both; - Children = new[] - { - text = new OsuSpriteText - { - Text = tooltipText, - } - }; - } - } - - private class TooltipTextbox : OsuTextBox, IHasTooltip - { - public string TooltipText => Text; - } - } -} diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs index ba17cfc3d8..2decb4c469 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs @@ -3,20 +3,18 @@ using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Play; namespace osu.Desktop.VisualTests.Tests { internal class TestCaseTwoLayerButton : TestCase { - public override string Description => @"Back and skip and what not"; + public override string Description => @"Mostly back button"; public override void Reset() { base.Reset(); Add(new BackButton()); - Add(new SkipButton(Clock.CurrentTime + 5000)); } } } diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 81979a739e..f72b08adde 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -204,12 +204,12 @@ + - diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 53449fd5f5..df212f7df7 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -28,7 +28,14 @@ namespace osu.Game.Rulesets.Catch { new CatchModEasy(), new CatchModNoFail(), - new CatchModHalfTime(), + new MultiMod + { + Mods = new Mod[] + { + new CatchModHalfTime(), + new CatchModDaycore(), + }, + }, }; case ModType.DifficultyIncrease: diff --git a/osu.Game.Rulesets.Catch/Mods/CatchMod.cs b/osu.Game.Rulesets.Catch/Mods/CatchMod.cs index 64a0c51b72..b0880d7e1d 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchMod.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchMod.cs @@ -32,6 +32,11 @@ namespace osu.Game.Rulesets.Catch.Mods } + public class CatchModDaycore : ModDaycore + { + public override double ScoreMultiplier => 0.5; + } + public class CatchModDoubleTime : ModDoubleTime { public override double ScoreMultiplier => 1.06; diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 30d1846746..0af8825208 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -27,7 +27,14 @@ namespace osu.Game.Rulesets.Mania { new ManiaModEasy(), new ManiaModNoFail(), - new ManiaModHalfTime(), + new MultiMod + { + Mods = new Mod[] + { + new ManiaModHalfTime(), + new ManiaModDaycore(), + }, + }, }; case ModType.DifficultyIncrease: diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs index b402d3a010..f44ad6fd60 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs @@ -34,6 +34,11 @@ namespace osu.Game.Rulesets.Mania.Mods } + public class ManiaModDaycore : ModDaycore + { + public override double ScoreMultiplier => 0.3; + } + public class ManiaModDoubleTime : ModDoubleTime { public override double ScoreMultiplier => 1.0; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs index cc06946d38..3b0cfc1ef1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs @@ -39,6 +39,11 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray(); } + public class OsuModDaycore : ModDaycore + { + public override double ScoreMultiplier => 0.5; + } + public class OsuModDoubleTime : ModDoubleTime { public override double ScoreMultiplier => 1.12; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index af4a099e0d..bfed889b36 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -46,7 +46,14 @@ namespace osu.Game.Rulesets.Osu { new OsuModEasy(), new OsuModNoFail(), - new OsuModHalfTime(), + new MultiMod + { + Mods = new Mod[] + { + new OsuModHalfTime(), + new OsuModDaycore(), + }, + }, }; case ModType.DifficultyIncrease: diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs index 8b7a099b9a..abaa8c1bc1 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs @@ -37,6 +37,11 @@ namespace osu.Game.Rulesets.Taiko.Mods } + public class TaikoModDaycore : ModDaycore + { + public override double ScoreMultiplier => 0.5; + } + public class TaikoModDoubleTime : ModDoubleTime { public override double ScoreMultiplier => 1.12; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 7c169f820b..303d936fb9 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -28,7 +28,14 @@ namespace osu.Game.Rulesets.Taiko { new TaikoModEasy(), new TaikoModNoFail(), - new TaikoModHalfTime(), + new MultiMod + { + Mods = new Mod[] + { + new TaikoModHalfTime(), + new TaikoModDaycore(), + }, + }, }; case ModType.DifficultyIncrease: diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 0e456941a1..7fb01cedc0 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO Assert.IsTrue(File.Exists(temp)); var importer = new BeatmapIPCChannel(client); - if (!importer.ImportAsync(temp).Wait(5000)) + if (!importer.ImportAsync(temp).Wait(10000)) Assert.Fail(@"IPC took too long to send"); ensureLoaded(host); diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index c6aac3bb71..4c540fa8cf 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using OpenTK.Graphics; @@ -31,6 +32,8 @@ namespace osu.Game.Beatmaps.Formats private ConvertHitObjectParser parser; + private readonly Dictionary variables = new Dictionary(); + private LegacySampleBank defaultSampleBank; private int defaultSampleVolume = 100; @@ -56,36 +59,39 @@ namespace osu.Game.Beatmaps.Formats TimingPoints, Colours, HitObjects, + Variables, } - private void handleGeneral(Beatmap beatmap, string key, string val) + private void handleGeneral(Beatmap beatmap, string line) { + var pair = splitKeyVal(line, ':'); + var metadata = beatmap.BeatmapInfo.Metadata; - switch (key) + switch (pair.Key) { case @"AudioFilename": - metadata.AudioFile = val; + metadata.AudioFile = pair.Value; break; case @"AudioLeadIn": - beatmap.BeatmapInfo.AudioLeadIn = int.Parse(val); + beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); break; case @"PreviewTime": - metadata.PreviewTime = int.Parse(val); + metadata.PreviewTime = int.Parse(pair.Value); break; case @"Countdown": - beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1; + beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; break; case @"SampleSet": - defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), val); + defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); break; case @"SampleVolume": - defaultSampleVolume = int.Parse(val); + defaultSampleVolume = int.Parse(pair.Value); break; case @"StackLeniency": - beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"Mode": - beatmap.BeatmapInfo.RulesetID = int.Parse(val); + beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); switch (beatmap.BeatmapInfo.RulesetID) { @@ -104,107 +110,135 @@ namespace osu.Game.Beatmaps.Formats } break; case @"LetterboxInBreaks": - beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(val) == 1; + beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; break; case @"SpecialStyle": - beatmap.BeatmapInfo.SpecialStyle = int.Parse(val) == 1; + beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; break; case @"WidescreenStoryboard": - beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(val) == 1; + beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; break; } } - private void handleEditor(Beatmap beatmap, string key, string val) + private void handleEditor(Beatmap beatmap, string line) { - switch (key) + var pair = splitKeyVal(line, ':'); + + switch (pair.Key) { case @"Bookmarks": - beatmap.BeatmapInfo.StoredBookmarks = val; + beatmap.BeatmapInfo.StoredBookmarks = pair.Value; break; case @"DistanceSpacing": - beatmap.BeatmapInfo.DistanceSpacing = double.Parse(val, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"BeatDivisor": - beatmap.BeatmapInfo.BeatDivisor = int.Parse(val); + beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); break; case @"GridSize": - beatmap.BeatmapInfo.GridSize = int.Parse(val); + beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); break; case @"TimelineZoom": - beatmap.BeatmapInfo.TimelineZoom = double.Parse(val, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; } } - private void handleMetadata(Beatmap beatmap, string key, string val) + private void handleMetadata(Beatmap beatmap, string line) { + var pair = splitKeyVal(line, ':'); + var metadata = beatmap.BeatmapInfo.Metadata; - switch (key) + switch (pair.Key) { case @"Title": - metadata.Title = val; + metadata.Title = pair.Value; break; case @"TitleUnicode": - metadata.TitleUnicode = val; + metadata.TitleUnicode = pair.Value; break; case @"Artist": - metadata.Artist = val; + metadata.Artist = pair.Value; break; case @"ArtistUnicode": - metadata.ArtistUnicode = val; + metadata.ArtistUnicode = pair.Value; break; case @"Creator": - metadata.Author = val; + metadata.Author = pair.Value; break; case @"Version": - beatmap.BeatmapInfo.Version = val; + beatmap.BeatmapInfo.Version = pair.Value; break; case @"Source": - beatmap.BeatmapInfo.Metadata.Source = val; + beatmap.BeatmapInfo.Metadata.Source = pair.Value; break; case @"Tags": - beatmap.BeatmapInfo.Metadata.Tags = val; + beatmap.BeatmapInfo.Metadata.Tags = pair.Value; break; case @"BeatmapID": - beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(val); + beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(val); - metadata.OnlineBeatmapSetID = int.Parse(val); + beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); + metadata.OnlineBeatmapSetID = int.Parse(pair.Value); break; } } - private void handleDifficulty(Beatmap beatmap, string key, string val) + private void handleDifficulty(Beatmap beatmap, string line) { + var pair = splitKeyVal(line, ':'); + var difficulty = beatmap.BeatmapInfo.Difficulty; - switch (key) + switch (pair.Key) { case @"HPDrainRate": - difficulty.DrainRate = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.DrainRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"CircleSize": - difficulty.CircleSize = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.CircleSize = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"OverallDifficulty": - difficulty.OverallDifficulty = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.OverallDifficulty = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"ApproachRate": - difficulty.ApproachRate = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"SliderMultiplier": - difficulty.SliderMultiplier = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.SliderMultiplier = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"SliderTickRate": - difficulty.SliderTickRate = float.Parse(val, NumberFormatInfo.InvariantInfo); + difficulty.SliderTickRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; } } - private void handleEvents(Beatmap beatmap, string val) + /// + /// Decodes any beatmap variables present in a line into their real values. + /// + /// The line which may contains variables. + private void decodeVariables(ref string line) { - string[] split = val.Split(','); + while (line.IndexOf('$') >= 0) + { + string[] split = line.Split(','); + for (int i = 0; i < split.Length; i++) + { + var item = split[i]; + if (item.StartsWith("$") && variables.ContainsKey(item)) + split[i] = variables[item]; + } + + line = string.Join(",", split); + } + } + + private void handleEvents(Beatmap beatmap, string line) + { + decodeVariables(ref line); + + string[] split = line.Split(','); EventType type; if (!Enum.TryParse(split[0], out type)) @@ -236,9 +270,9 @@ namespace osu.Game.Beatmaps.Formats } } - private void handleTimingPoints(Beatmap beatmap, string val) + private void handleTimingPoints(Beatmap beatmap, string line) { - string[] split = val.Split(','); + string[] split = line.Split(','); double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo); double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo); @@ -321,12 +355,14 @@ namespace osu.Game.Beatmaps.Formats } } - private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours) + private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours) { - string[] split = val.Split(','); + var pair = splitKeyVal(line, ':'); + + string[] split = pair.Value.Split(','); if (split.Length != 3) - throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {val}"); + throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}"); byte r, g, b; if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b)) @@ -339,7 +375,7 @@ namespace osu.Game.Beatmaps.Formats } // Note: the combo index specified in the beatmap is discarded - if (key.StartsWith(@"Combo")) + if (pair.Key.StartsWith(@"Combo")) { beatmap.ComboColors.Add(new Color4 { @@ -351,6 +387,12 @@ namespace osu.Game.Beatmaps.Formats } } + private void handleVariables(string line) + { + var pair = splitKeyVal(line, '='); + variables[pair.Key] = pair.Value; + } + protected override Beatmap ParseFile(StreamReader stream) { return new LegacyBeatmap(base.ParseFile(stream)); @@ -390,42 +432,39 @@ namespace osu.Game.Beatmaps.Formats continue; } - string val = line, key = null; - if (section != Section.Events && section != Section.TimingPoints && section != Section.HitObjects) - { - key = val.Remove(val.IndexOf(':')).Trim(); - val = val.Substring(val.IndexOf(':') + 1).Trim(); - } switch (section) { case Section.General: - handleGeneral(beatmap, key, val); + handleGeneral(beatmap, line); break; case Section.Editor: - handleEditor(beatmap, key, val); + handleEditor(beatmap, line); break; case Section.Metadata: - handleMetadata(beatmap, key, val); + handleMetadata(beatmap, line); break; case Section.Difficulty: - handleDifficulty(beatmap, key, val); + handleDifficulty(beatmap, line); break; case Section.Events: - handleEvents(beatmap, val); + handleEvents(beatmap, line); break; case Section.TimingPoints: - handleTimingPoints(beatmap, val); + handleTimingPoints(beatmap, line); break; case Section.Colours: - handleColours(beatmap, key, val, ref hasCustomColours); + handleColours(beatmap, line, ref hasCustomColours); break; case Section.HitObjects: - var obj = parser.Parse(val); + var obj = parser.Parse(line); if (obj != null) beatmap.HitObjects.Add(obj); break; + case Section.Variables: + handleVariables(line); + break; } } @@ -433,6 +472,15 @@ namespace osu.Game.Beatmaps.Formats hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty); } + private KeyValuePair splitKeyVal(string line, char separator) + { + return new KeyValuePair + ( + line.Remove(line.IndexOf(separator)).Trim(), + line.Substring(line.IndexOf(separator) + 1).Trim() + ); + } + internal enum LegacySampleBank { None = 0, diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index c3a7870d5a..3f56dc0b79 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -20,6 +20,8 @@ namespace osu.Game.Configuration Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10); Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10); + Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation); + Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1); // Online settings @@ -107,6 +109,7 @@ namespace osu.Game.Configuration SaveUsername, DisplayStarsMinimum, DisplayStarsMaximum, + SelectionRandomType, SnakingInSliders, SnakingOutSliders, ShowFpsDisplay, diff --git a/osu.Game/Configuration/SelectionRandomType.cs b/osu.Game/Configuration/SelectionRandomType.cs new file mode 100644 index 0000000000..298ee71e36 --- /dev/null +++ b/osu.Game/Configuration/SelectionRandomType.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.ComponentModel; + +namespace osu.Game.Configuration +{ + public enum SelectionRandomType + { + [Description("Never repeat")] + RandomPermutation, + [Description("Random")] + Random + } +} \ No newline at end of file diff --git a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs b/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs index 2b52b06abc..89b4a90010 100644 --- a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs +++ b/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs @@ -11,6 +11,6 @@ namespace osu.Game.Graphics.Containers public class ReverseDepthFillFlowContainer : FillFlowContainer where T : Drawable { protected override IComparer DepthComparer => new ReverseCreationOrderDepthComparer(); - protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); + protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); } } diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index b48ab879a6..82ae424ab0 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -93,6 +93,7 @@ namespace osu.Game.Graphics.Cursor { private Container cursorContainer; private Bindable cursorScale; + private const float base_scale = 0.15f; public Sprite AdditiveLayer; @@ -108,17 +109,15 @@ namespace osu.Game.Graphics.Cursor { cursorContainer = new Container { - Size = new Vector2(32), + AutoSizeAxes = Axes.Both, Children = new Drawable[] { new Sprite { - FillMode = FillMode.Fit, Texture = textures.Get(@"Cursor/menu-cursor"), }, AdditiveLayer = new Sprite { - FillMode = FillMode.Fit, BlendingMode = BlendingMode.Additive, Colour = colour.Pink, Alpha = 0, @@ -129,7 +128,7 @@ namespace osu.Game.Graphics.Cursor }; cursorScale = config.GetBindable(OsuSetting.MenuCursorSize); - cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale); + cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale * base_scale); cursorScale.TriggerChange(); } } diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs new file mode 100644 index 0000000000..46addf5ac2 --- /dev/null +++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs @@ -0,0 +1,93 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Allocation; +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.Game.Graphics.Sprites; + +namespace osu.Game.Graphics.Cursor +{ + public class OsuTooltipContainer : TooltipContainer + { + protected override Tooltip CreateTooltip() => new OsuTooltip(); + + public OsuTooltipContainer(CursorContainer cursor) : base(cursor) + { + } + + public class OsuTooltip : Tooltip + { + private readonly Box background; + private readonly OsuSpriteText text; + + public override string TooltipText + { + set + { + if (value == text.Text) return; + + text.Text = value; + if (Alpha > 0) + { + AutoSizeDuration = 250; + background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint); + } + else + AutoSizeDuration = 0; + } + } + + private const float text_size = 16; + + public OsuTooltip() + { + AutoSizeEasing = EasingTypes.OutQuint; + + CornerRadius = 5; + Masking = true; + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(40), + Radius = 5, + }; + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.9f, + }, + text = new OsuSpriteText + { + TextSize = text_size, + Padding = new MarginPadding(5), + Font = @"Exo2.0-Regular", + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + background.Colour = colour.Gray3; + } + + protected override void PopIn() + { + FadeIn(500, EasingTypes.OutQuint); + } + + protected override void PopOut() + { + using (BeginDelayedSequence(150)) + FadeOut(500, EasingTypes.OutQuint); + } + } + } +} diff --git a/osu.Game/Graphics/Cursor/TooltipContainer.cs b/osu.Game/Graphics/Cursor/TooltipContainer.cs deleted file mode 100644 index c5b8382816..0000000000 --- a/osu.Game/Graphics/Cursor/TooltipContainer.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Allocation; -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.Input; -using osu.Framework.Threading; -using osu.Game.Graphics.Sprites; -using System.Linq; - -namespace osu.Game.Graphics.Cursor -{ - public class TooltipContainer : Container - { - private readonly CursorContainer cursor; - private readonly Tooltip tooltip; - - private ScheduledDelegate findTooltipTask; - private UserInputManager inputManager; - - private const int default_appear_delay = 220; - - private IHasTooltip currentlyDisplayed; - - public TooltipContainer(CursorContainer cursor) - { - this.cursor = cursor; - AlwaysPresent = true; - RelativeSizeAxes = Axes.Both; - Add(tooltip = new Tooltip { Alpha = 0 }); - } - - [BackgroundDependencyLoader] - private void load(UserInputManager input) - { - inputManager = input; - } - - protected override void Update() - { - if (tooltip.IsPresent) - { - if (currentlyDisplayed != null) - tooltip.TooltipText = currentlyDisplayed.TooltipText; - - //update the position of the displayed tooltip. - tooltip.Position = ToLocalSpace(cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre) + new Vector2(10); - } - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - updateTooltipState(state); - return base.OnMouseUp(state, args); - } - - protected override bool OnMouseMove(InputState state) - { - updateTooltipState(state); - return base.OnMouseMove(state); - } - - private void updateTooltipState(InputState state) - { - if (currentlyDisplayed?.Hovering != true) - { - if (currentlyDisplayed != null && !state.Mouse.HasMainButtonPressed) - { - tooltip.Delay(150); - tooltip.FadeOut(500, EasingTypes.OutQuint); - currentlyDisplayed = null; - } - - findTooltipTask?.Cancel(); - findTooltipTask = Scheduler.AddDelayed(delegate - { - var tooltipTarget = inputManager.HoveredDrawables.OfType().FirstOrDefault(); - - if (tooltipTarget == null) return; - - tooltip.TooltipText = tooltipTarget.TooltipText; - tooltip.FadeIn(500, EasingTypes.OutQuint); - - currentlyDisplayed = tooltipTarget; - }, (1 - tooltip.Alpha) * default_appear_delay); - } - } - - public class Tooltip : Container - { - private readonly Box background; - private readonly OsuSpriteText text; - - public string TooltipText - { - set - { - if (value == text.Text) return; - - text.Text = value; - if (Alpha > 0) - { - AutoSizeDuration = 250; - background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint); - } - else - AutoSizeDuration = 0; - } - } - - public override bool HandleInput => false; - - private const float text_size = 16; - - public Tooltip() - { - AutoSizeEasing = EasingTypes.OutQuint; - AutoSizeAxes = Axes.Both; - - CornerRadius = 5; - Masking = true; - EdgeEffect = new EdgeEffect - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(40), - Radius = 5, - }; - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.9f, - }, - text = new OsuSpriteText - { - TextSize = text_size, - Padding = new MarginPadding(5), - Font = @"Exo2.0-Regular", - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - background.Colour = colour.Gray3; - } - } - } -} diff --git a/osu.Game/Graphics/IHasTooltip.cs b/osu.Game/Graphics/IHasTooltip.cs deleted file mode 100644 index dd51d68c41..0000000000 --- a/osu.Game/Graphics/IHasTooltip.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; - -namespace osu.Game.Graphics -{ - public interface IHasTooltip : IDrawable - { - /// - /// Tooltip that shows when hovering the drawable - /// - string TooltipText { get; } - } -} diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 14483f3bfb..6dadd63ac4 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -72,7 +72,7 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, - new OsuSpriteText { + Label = new OsuSpriteText { Text = text, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, @@ -85,6 +85,7 @@ namespace osu.Game.Graphics.UserInterface private Color4? accentColour; protected readonly TextAwesome Chevron; + protected readonly OsuSpriteText Label; protected override void FormatForeground(bool hover = false) { @@ -170,4 +171,4 @@ namespace osu.Game.Graphics.UserInterface } } } -} \ No newline at end of file +} diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index e8b2b49cbf..2dab952204 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Graphics.UserInterface { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 2c39a82245..b228b6485a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -158,7 +158,7 @@ namespace osu.Game Children = new Drawable[] { Cursor = new MenuCursor(), - new TooltipContainer(Cursor) { Depth = -1 }, + new OsuTooltipContainer(Cursor) { Depth = -1 }, } }, } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 50c849f00e..0cd6b8dd3a 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Chat; @@ -43,11 +44,15 @@ namespace osu.Game.Overlays.Chat channel.NewMessagesArrived += newMessagesArrived; } + [BackgroundDependencyLoader] + private void load() + { + newMessagesArrived(Channel.Messages); + } + protected override void LoadComplete() { base.LoadComplete(); - - newMessagesArrived(Channel.Messages); scrollToEnd(); } @@ -59,13 +64,13 @@ namespace osu.Game.Overlays.Chat private void newMessagesArrived(IEnumerable newMessages) { - if (!IsLoaded) return; - var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); //up to last Channel.MAX_HISTORY messages flow.Add(displayMessages.Select(m => new ChatLine(m))); + if (!IsLoaded) return; + if (scroll.IsScrolledToEnd(10) || !flow.Children.Any()) scrollToEnd(); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index a9970e5e95..f81c0ea922 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -266,20 +266,30 @@ namespace osu.Game.Overlays if (channelTabs.ChannelSelectorActive) return; - if (currentChannel != null) - currentChannelContainer.Clear(false); - currentChannel = value; + inputTextBox.Current.Disabled = currentChannel.ReadOnly; + channelTabs.Current.Value = value; + var loaded = loadedChannels.Find(d => d.Channel == value); if (loaded == null) - loadedChannels.Add(loaded = new DrawableChannel(currentChannel)); + { + currentChannelContainer.FadeOut(500, EasingTypes.OutQuint); - inputTextBox.Current.Disabled = currentChannel.ReadOnly; - - currentChannelContainer.Add(loaded); - - channelTabs.Current.Value = value; + loaded = new DrawableChannel(currentChannel); + loadedChannels.Add(loaded); + LoadComponentAsync(loaded, l => + { + currentChannelContainer.Clear(false); + currentChannelContainer.Add(l); + currentChannelContainer.FadeIn(500, EasingTypes.OutQuint); + }); + } + else + { + currentChannelContainer.Clear(false); + currentChannelContainer.Add(loaded); + } } } diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index f7df67b66d..dd135e43ef 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using System; using System.Linq; -using osu.Game.Graphics; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Mods { diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs index 7626911627..62801b2ef6 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs @@ -27,6 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay LabelText = "up to", Bindable = config.GetBindable(OsuSetting.DisplayStarsMaximum) }, + new SettingsEnumDropdown + { + LabelText = "Random beatmap selection", + Bindable = config.GetBindable(OsuSetting.SelectionRandomType), + }, }; } diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 1e22b26f1b..11a964d179 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -345,8 +345,8 @@ namespace osu.Game.Overlays.Settings.Sections.General { public UserDropdownMenuItem(string text, UserAction current) : base(text, current) { - Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = UserDropdownHeader.LABEL_LEFT_MARGIN, Right = 5 }; - Chevron.Margin = new MarginPadding { Left = 2, Right = 3 }; + Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 }; + Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 }; CornerRadius = 5; } } diff --git a/osu.Game/Rulesets/Mods/ModDaycore.cs b/osu.Game/Rulesets/Mods/ModDaycore.cs new file mode 100644 index 0000000000..3e878d7104 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModDaycore.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Audio; +using osu.Framework.Timing; +using osu.Game.Graphics; + +namespace osu.Game.Rulesets.Mods +{ + public abstract class ModDaycore : ModHalfTime + { + public override string Name => "Daycore"; + public override FontAwesome Icon => FontAwesome.fa_question; + public override string Description => "whoaaaaa"; + + public override void ApplyToClock(IAdjustableClock clock) + { + var pitchAdjust = clock as IHasPitchAdjust; + if (pitchAdjust != null) + pitchAdjust.PitchAdjust = 0.75; + else + base.ApplyToClock(clock); + } + } +} \ No newline at end of file diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs index 207a6ec2a1..14aede0809 100644 --- a/osu.Game/Rulesets/Mods/ModHalfTime.cs +++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1.12; - public void ApplyToClock(IAdjustableClock clock) + public virtual void ApplyToClock(IAdjustableClock clock) { clock.Rate = 0.75; } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 130642b9c7..26820fc388 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps.Drawables; +using osu.Game.Configuration; using osu.Framework.Input; using OpenTK.Input; using System.Collections; @@ -17,6 +18,7 @@ using System.Diagnostics; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Threading; +using osu.Framework.Configuration; namespace osu.Game.Screens.Select { @@ -70,6 +72,9 @@ namespace osu.Game.Screens.Select private readonly List groups = new List(); + private Bindable randomType; + private readonly List seenGroups = new List(); + private readonly List panels = new List(); private BeatmapGroup selectedGroup; @@ -167,11 +172,26 @@ namespace osu.Game.Screens.Select public void SelectRandom() { - List visibleGroups = groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden).ToList(); - if (visibleGroups.Count < 1) + IEnumerable visibleGroups = groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden); + if (!visibleGroups.Any()) return; - BeatmapGroup group = visibleGroups[RNG.Next(visibleGroups.Count)]; + BeatmapGroup group; + if (randomType == SelectionRandomType.RandomPermutation) + { + IEnumerable notSeenGroups = visibleGroups.Except(seenGroups); + if (!notSeenGroups.Any()) + { + seenGroups.Clear(); + notSeenGroups = visibleGroups; + } + + group = notSeenGroups.ElementAt(RNG.Next(notSeenGroups.Count())); + seenGroups.Add(group); + } + else + group = visibleGroups.ElementAt(RNG.Next(visibleGroups.Count())); + BeatmapPanel panel = group.BeatmapPanels[RNG.Next(group.BeatmapPanels.Count)]; selectGroup(group, panel); @@ -239,9 +259,10 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapDatabase database) + private void load(BeatmapDatabase database, OsuConfigManager config) { this.database = database; + randomType = config.GetBindable(OsuSetting.SelectionRandomType); } private void addGroup(BeatmapGroup group) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 02bcac6778..6f4e301641 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -75,6 +75,7 @@ + @@ -106,7 +107,6 @@ - @@ -119,7 +119,7 @@ - + @@ -127,6 +127,7 @@ +