diff --git a/osu-framework b/osu-framework index e793a08417..fac688633b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e793a084177f53920645c4f6f70cfef91e7fd19e +Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4 diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs new file mode 100644 index 0000000000..5b4af6ea8a --- /dev/null +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Catch.Objects; + +namespace osu.Game.Rulesets.Catch.Beatmaps +{ + public class CatchBeatmap : Beatmap + { + public override IEnumerable GetStatistics() + { + int fruits = HitObjects.Count(s => s is Fruit); + int juiceStreams = HitObjects.Count(s => s is JuiceStream); + int bananaShowers = HitObjects.Count(s => s is BananaShower); + + return new[] + { + new BeatmapStatistic + { + Name = @"Fruit Count", + Content = fruits.ToString(), + Icon = FontAwesome.fa_circle_o + }, + new BeatmapStatistic + { + Name = @"Juice Stream Count", + Content = juiceStreams.ToString(), + Icon = FontAwesome.fa_circle + }, + new BeatmapStatistic + { + Name = @"Banana Shower Count", + Content = bananaShowers.ToString(), + Icon = FontAwesome.fa_circle + } + }; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index 4a0b120e47..f40ef67dfb 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -69,5 +69,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps X = positionData.X / CatchPlayfield.BASE_WIDTH }; } + + protected override Beatmap CreateBeatmap() => new CatchBeatmap(); } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs index 6af3719f83..ad5f8e447d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; @@ -29,5 +30,27 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { Stages.Add(defaultStage); } + + public override IEnumerable GetStatistics() + { + int notes = HitObjects.Count(s => s is Note); + int holdnotes = HitObjects.Count(s => s is HoldNote); + + return new[] + { + new BeatmapStatistic + { + Name = @"Note Count", + Content = notes.ToString(), + Icon = FontAwesome.fa_circle_o + }, + new BeatmapStatistic + { + Name = @"Hold Note Count", + Content = holdnotes.ToString(), + Icon = FontAwesome.fa_circle + }, + }; + } } } diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs new file mode 100644 index 0000000000..6d90c2a875 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Beatmaps +{ + public class OsuBeatmap : Beatmap + { + public override IEnumerable GetStatistics() + { + int circles = HitObjects.Count(c => c is HitCircle); + int sliders = HitObjects.Count(s => s is Slider); + int spinners = HitObjects.Count(s => s is Spinner); + + return new[] + { + new BeatmapStatistic + { + Name = @"Circle Count", + Content = circles.ToString(), + Icon = FontAwesome.fa_circle_o + }, + new BeatmapStatistic + { + Name = @"Slider Count", + Content = sliders.ToString(), + Icon = FontAwesome.fa_circle + }, + new BeatmapStatistic + { + Name = @"Spinner Count", + Content = spinners.ToString(), + Icon = FontAwesome.fa_circle + } + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 54720548b4..4369a31b2c 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -67,5 +67,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps }; } } + + protected override Beatmap CreateBeatmap() => new OsuBeatmap(); } } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 927ffa2146..69a54fb533 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Osu.OsuDifficulty; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; using System.Collections.Generic; -using System.Linq; using osu.Framework.Graphics; using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; @@ -17,8 +16,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; @@ -40,36 +37,6 @@ namespace osu.Game.Rulesets.Osu new KeyBinding(InputKey.MouseRight, OsuAction.RightButton), }; - public override IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) - { - IEnumerable hitObjects = beatmap.Beatmap.HitObjects; - IEnumerable circles = hitObjects.Where(c => !(c is IHasEndTime)); - IEnumerable sliders = hitObjects.Where(s => s is IHasCurve); - IEnumerable spinners = hitObjects.Where(s => s is IHasEndTime && !(s is IHasCurve)); - - return new[] - { - new BeatmapStatistic - { - Name = @"Circle Count", - Content = circles.Count().ToString(), - Icon = FontAwesome.fa_circle_o - }, - new BeatmapStatistic - { - Name = @"Slider Count", - Content = sliders.Count().ToString(), - Icon = FontAwesome.fa_circle - }, - new BeatmapStatistic - { - Name = @"Spinner Count", - Content = spinners.Count().ToString(), - Icon = FontAwesome.fa_circle - } - }; - } - public override IEnumerable ConvertLegacyMods(LegacyMods mods) { if (mods.HasFlag(LegacyMods.Nightcore)) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index 6b9214d9dc..a12bdf7f20 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -32,7 +32,8 @@ namespace osu.Game.Rulesets.Osu.Scoring countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); beatmapMaxCombo = Beatmap.HitObjects.Count(); - beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count) + 1; + // Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above) + beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1); } public override double Calculate(Dictionary categoryRatings = null) @@ -121,7 +122,7 @@ namespace osu.Game.Rulesets.Osu.Scoring aimValue *= approachRateFactor; if (mods.Any(h => h is OsuModHidden)) - aimValue *= 1.18f; + aimValue *= 1.03f; if (mods.Any(h => h is OsuModFlashlight)) { @@ -152,6 +153,9 @@ namespace osu.Game.Rulesets.Osu.Scoring if (beatmapMaxCombo > 0) speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f); + if (mods.Any(m => m is OsuModHidden)) + speedValue *= 1.18f; + // Scale the speed value with accuracy _slightly_ speedValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmap.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmap.cs new file mode 100644 index 0000000000..36f6df7869 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmap.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Beatmaps +{ + public class TaikoBeatmap : Beatmap + { + public override IEnumerable GetStatistics() + { + int hits = HitObjects.Count(s => s is Hit); + int drumrolls = HitObjects.Count(s => s is DrumRoll); + int swells = HitObjects.Count(s => s is Swell); + + return new[] + { + new BeatmapStatistic + { + Name = @"Hit Count", + Content = hits.ToString(), + Icon = FontAwesome.fa_circle_o + }, + new BeatmapStatistic + { + Name = @"Drumroll Count", + Content = drumrolls.ToString(), + Icon = FontAwesome.fa_circle + }, + new BeatmapStatistic + { + Name = @"Swell Count", + Content = swells.ToString(), + Icon = FontAwesome.fa_circle + } + }; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 58efc3336d..b450e4d26c 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -203,5 +203,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps } } } + + protected override Beatmap CreateBeatmap() => new TaikoBeatmap(); } } diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index efd6c36ce2..0d3e08154f 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -12,8 +12,12 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Taiko; using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps; @@ -72,13 +76,23 @@ namespace osu.Game.Tests.Visual selectBeatmap(testBeatmap); + testBeatmapLabels(ruleset); + // TODO: adjust cases once more info is shown for other gamemodes switch (ruleset) { - case OsuRuleset osu: - testOsuBeatmap(osu); + case OsuRuleset _: testInfoLabels(5); break; + case TaikoRuleset _: + testInfoLabels(5); + break; + case CatchRuleset _: + testInfoLabels(5); + break; + case ManiaRuleset _: + testInfoLabels(4); + break; default: testInfoLabels(2); break; @@ -88,7 +102,7 @@ namespace osu.Game.Tests.Visual testNullBeatmap(); } - private void testOsuBeatmap(OsuRuleset ruleset) + private void testBeatmapLabels(Ruleset ruleset) { AddAssert("check version", () => infoWedge.Info.VersionLabel.Text == $"{ruleset.ShortName}Version"); AddAssert("check title", () => infoWedge.Info.TitleLabel.Text == $"{ruleset.ShortName}Source — {ruleset.ShortName}Title"); @@ -138,7 +152,7 @@ namespace osu.Game.Tests.Visual { List objects = new List(); for (double i = 0; i < 50000; i += 1000) - objects.Add(new HitObject { StartTime = i }); + objects.Add(new TestHitObject { StartTime = i }); return new Beatmap { @@ -153,7 +167,8 @@ namespace osu.Game.Tests.Visual }, Ruleset = ruleset, StarDifficulty = 6, - Version = $"{ruleset.ShortName}Version" + Version = $"{ruleset.ShortName}Version", + BaseDifficulty = new BeatmapDifficulty() }, HitObjects = objects }; @@ -163,5 +178,12 @@ namespace osu.Game.Tests.Visual { public new BufferedWedgeInfo Info => base.Info; } + + private class TestHitObject : HitObject, IHasPosition + { + public float X { get; } = 0; + public float Y { get; } = 0; + public Vector2 Position { get; } = Vector2.Zero; + } } } diff --git a/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs b/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs index 25f8ba06c4..bb5bf93a69 100644 --- a/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs +++ b/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; -using osu.Game.Screens.Multiplayer; +using osu.Game.Screens.Multi.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index dad8fb8fed..d3d21509fd 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -17,6 +18,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.UI; using OpenTK.Graphics; namespace osu.Game.Tests.Visual @@ -24,6 +26,19 @@ namespace osu.Game.Tests.Visual [Description("mod select and icon display")] public class TestCaseMods : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ModSelectOverlay), + typeof(ModDisplay), + typeof(ModSection), + typeof(ModIcon), + typeof(ModButton), + typeof(ModButtonEmpty), + typeof(DifficultyReductionSection), + typeof(DifficultyIncreaseSection), + typeof(SpecialSection), + }; + private const string unranked_suffix = " (Unranked)"; private RulesetStore rulesets; @@ -66,7 +81,8 @@ namespace osu.Game.Tests.Visual Ruleset ruleset = rulesetInfo.CreateInstance(); AddStep($"switch to {ruleset.Description}", () => modSelect.Ruleset.Value = rulesetInfo); - switch (ruleset) { + switch (ruleset) + { case OsuRuleset or: testOsuMods(or); break; diff --git a/osu.Game.Tests/Visual/TestCaseRoomInspector.cs b/osu.Game.Tests/Visual/TestCaseRoomInspector.cs index 88059d2dcf..cb1425ca69 100644 --- a/osu.Game.Tests/Visual/TestCaseRoomInspector.cs +++ b/osu.Game.Tests/Visual/TestCaseRoomInspector.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; -using osu.Game.Screens.Multiplayer; +using osu.Game.Screens.Multi.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 2df0547175..84897853d8 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -51,6 +51,8 @@ namespace osu.Game.Beatmaps IEnumerable IBeatmap.HitObjects => HitObjects; + public virtual IEnumerable GetStatistics() => Enumerable.Empty(); + IBeatmap IBeatmap.Clone() => Clone(); public Beatmap Clone() diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index 4676f056fa..fe20bce98a 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -41,6 +41,12 @@ namespace osu.Game.Beatmaps /// IEnumerable HitObjects { get; } + /// + /// Returns statistics for the contained in this beatmap. + /// + /// + IEnumerable GetStatistics(); + /// /// Creates a shallow-clone of this beatmap and returns it. /// diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index 3f59eeca97..f5017de639 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -14,14 +14,18 @@ namespace osu.Game.Graphics.UserInterface public class BreadcrumbControl : OsuTabControl { private const float padding = 10; + private const float item_chevron_size = 10; - protected override TabItem CreateTabItem(T value) => new BreadcrumbTabItem(value); + protected override TabItem CreateTabItem(T value) => new BreadcrumbTabItem(value) + { + AccentColour = AccentColour, + }; - protected override float StripWidth() => base.StripWidth() - (padding + 8); + protected override float StripWidth() => base.StripWidth() - (padding + item_chevron_size); public BreadcrumbControl() { - Height = 26; + Height = 32; TabContainer.Spacing = new Vector2(padding, 0f); Current.ValueChanged += tab => { @@ -47,6 +51,7 @@ namespace osu.Game.Graphics.UserInterface public override bool HandleKeyboardInput => State == Visibility.Visible; public override bool HandleMouseInput => State == Visibility.Visible; + public override bool IsRemovable => true; private Visibility state; @@ -77,13 +82,14 @@ namespace osu.Game.Graphics.UserInterface public BreadcrumbTabItem(T value) : base(value) { - Text.TextSize = 16; - Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width + Text.TextSize = 18; + Text.Margin = new MarginPadding { Vertical = 8 }; + Padding = new MarginPadding { Right = padding + item_chevron_size }; Add(Chevron = new SpriteIcon { Anchor = Anchor.CentreRight, Origin = Anchor.CentreLeft, - Size = new Vector2(12), + Size = new Vector2(item_chevron_size), Icon = FontAwesome.fa_chevron_right, Margin = new MarginPadding { Left = padding }, Alpha = 0f, diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index e80a469f91..27ce8d5ed4 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -223,6 +223,26 @@ namespace osu.Game.Overlays.KeyBinding return true; } + protected override bool OnJoystickPress(InputState state, Framework.Input.JoystickEventArgs args) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state)); + finalise(); + + return true; + } + + protected override bool OnJoystickRelease(InputState state, Framework.Input.JoystickEventArgs args) + { + if (!HasFocus) + return base.OnJoystickRelease(state, args); + + finalise(); + return true; + } + private void finalise() { if (bindTarget != null) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 2a4f243606..f4e0e3db04 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -116,6 +116,7 @@ namespace osu.Game.Overlays.Mods } private Mod mod; + private readonly Container scaleContainer; public Mod Mod { @@ -149,14 +150,26 @@ namespace osu.Game.Overlays.Mods protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - switch (args.Button) + scaleContainer.ScaleTo(0.9f, 800, Easing.Out); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + scaleContainer.ScaleTo(1, 500, Easing.OutElastic); + + // only trigger the event if we are inside the area of the button + if (Contains(ToScreenSpace(state.Mouse.Position - Position))) { - case MouseButton.Left: - SelectNext(1); - break; - case MouseButton.Right: - SelectNext(-1); - break; + switch (args.Button) + { + case MouseButton.Left: + SelectNext(1); + break; + case MouseButton.Right: + SelectNext(-1); + break; + } } return true; @@ -176,7 +189,8 @@ namespace osu.Game.Overlays.Mods start = Mods.Length - 1; for (int i = start; i < Mods.Length && i >= 0; i += direction) - if (SelectAt(i)) return; + if (SelectAt(i)) + return; Deselect(); } @@ -242,8 +256,14 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Children = new Drawable[] { - iconsContainer = new Container + scaleContainer = new Container { + Child = iconsContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + }, RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index d6d1d19628..6883d319f4 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -22,8 +22,6 @@ namespace osu.Game.Rulesets { public readonly RulesetInfo RulesetInfo; - public virtual IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { }; - public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).Cast() // Confine all mods of each mod type into a single IEnumerable .SelectMany(GetModsFor) diff --git a/osu.Game/Rulesets/Scoring/Legacy/LegacyScoreParser.cs b/osu.Game/Rulesets/Scoring/Legacy/LegacyScoreParser.cs index d5ab856697..38873c4df1 100644 --- a/osu.Game/Rulesets/Scoring/Legacy/LegacyScoreParser.cs +++ b/osu.Game/Rulesets/Scoring/Legacy/LegacyScoreParser.cs @@ -49,18 +49,21 @@ namespace osu.Game.Rulesets.Scoring.Legacy score.User = new User { Username = sr.ReadString() }; /* var localScoreChecksum = */ sr.ReadString(); - /* score.Count300 = */ - sr.ReadUInt16(); - /* score.Count100 = */ - sr.ReadUInt16(); - /* score.Count50 = */ - sr.ReadUInt16(); - /* score.CountGeki = */ - sr.ReadUInt16(); - /* score.CountKatu = */ - sr.ReadUInt16(); - /* score.CountMiss = */ - sr.ReadUInt16(); + + var count300 = sr.ReadUInt16(); + var count100 = sr.ReadUInt16(); + var count50 = sr.ReadUInt16(); + var countGeki = sr.ReadUInt16(); + var countKatu = sr.ReadUInt16(); + var countMiss = sr.ReadUInt16(); + + score.Statistics[HitResult.Great] = count300; + score.Statistics[HitResult.Good] = count100; + score.Statistics[HitResult.Meh] = count50; + score.Statistics[HitResult.Perfect] = countGeki; + score.Statistics[HitResult.Ok] = countKatu; + score.Statistics[HitResult.Miss] = countMiss; + score.TotalScore = sr.ReadInt32(); score.MaxCombo = sr.ReadUInt16(); /* score.Perfect = */ @@ -81,6 +84,34 @@ namespace osu.Game.Rulesets.Scoring.Legacy /*OnlineId =*/ sr.ReadInt32(); + switch (score.Ruleset.ID) + { + case 0: + { + int totalHits = count50 + count100 + count300 + countMiss; + score.Accuracy = totalHits > 0 ? (double)(count50 * 50 + count100 * 100 + count300 * 300) / (totalHits * 300) : 1; + break; + } + case 1: + { + int totalHits = count50 + count100 + count300 + countMiss; + score.Accuracy = totalHits > 0 ? (double)(count100 * 150 + count300 * 300) / (totalHits * 300) : 1; + break; + } + case 2: + { + int totalHits = count50 + count100 + count300 + countMiss + countKatu; + score.Accuracy = totalHits > 0 ? (double)(count50 + count100 + count300 ) / totalHits : 1; + break; + } + case 3: + { + int totalHits = count50 + count100 + count300 + countMiss + countGeki + countKatu; + score.Accuracy = totalHits > 0 ? (double)(count50 * 50 + count100 * 100 + countKatu * 200 + (count300 + countGeki) * 300) / (totalHits * 300) : 1; + break; + } + } + using (var replayInStream = new MemoryStream(compressedReplay)) { byte[] properties = new byte[5]; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index f2ea6d85a8..907ad81111 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Charts; using osu.Game.Screens.Direct; using osu.Game.Screens.Edit; -using osu.Game.Screens.Multiplayer; +using osu.Game.Screens.Multi.Screens; using osu.Game.Screens.Select; using osu.Game.Screens.Tournament; diff --git a/osu.Game/Screens/Multiplayer/DrawableGameType.cs b/osu.Game/Screens/Multi/Components/DrawableGameType.cs similarity index 96% rename from osu.Game/Screens/Multiplayer/DrawableGameType.cs rename to osu.Game/Screens/Multi/Components/DrawableGameType.cs index 5790008f76..3406e179d4 100644 --- a/osu.Game/Screens/Multiplayer/DrawableGameType.cs +++ b/osu.Game/Screens/Multi/Components/DrawableGameType.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Components { public class DrawableGameType : CircularContainer, IHasTooltip { diff --git a/osu.Game/Screens/Multiplayer/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs similarity index 99% rename from osu.Game/Screens/Multiplayer/DrawableRoom.cs rename to osu.Game/Screens/Multi/Components/DrawableRoom.cs index d53100526f..040fbaf593 100644 --- a/osu.Game/Screens/Multiplayer/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -1,8 +1,6 @@ // Copyright (c) 2007-2018 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.Configuration; using osu.Framework.Extensions.Color4Extensions; @@ -17,8 +15,10 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Multiplayer; using osu.Game.Users; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Components { public class DrawableRoom : OsuClickableContainer { diff --git a/osu.Game/Screens/Multiplayer/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs similarity index 98% rename from osu.Game/Screens/Multiplayer/ModeTypeInfo.cs rename to osu.Game/Screens/Multi/Components/ModeTypeInfo.cs index 08e96ba55d..e3aba685a7 100644 --- a/osu.Game/Screens/Multiplayer/ModeTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs @@ -1,14 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Online.Multiplayer; +using OpenTK; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Components { public class ModeTypeInfo : Container { diff --git a/osu.Game/Screens/Multiplayer/ParticipantInfo.cs b/osu.Game/Screens/Multi/Components/ParticipantInfo.cs similarity index 99% rename from osu.Game/Screens/Multiplayer/ParticipantInfo.cs rename to osu.Game/Screens/Multi/Components/ParticipantInfo.cs index ff1887fa17..ab404488f1 100644 --- a/osu.Game/Screens/Multiplayer/ParticipantInfo.cs +++ b/osu.Game/Screens/Multi/Components/ParticipantInfo.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using OpenTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,8 +10,9 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Users; +using OpenTK; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Components { public class ParticipantInfo : Container { diff --git a/osu.Game/Screens/Multiplayer/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs similarity index 99% rename from osu.Game/Screens/Multiplayer/RoomInspector.cs rename to osu.Game/Screens/Multi/Components/RoomInspector.cs index bfc4a44ed5..92910e8301 100644 --- a/osu.Game/Screens/Multiplayer/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; @@ -20,8 +18,10 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Multiplayer; using osu.Game.Users; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Components { public class RoomInspector : Container { diff --git a/osu.Game/Screens/Multiplayer/Lobby.cs b/osu.Game/Screens/Multi/Screens/Lobby.cs similarity index 90% rename from osu.Game/Screens/Multiplayer/Lobby.cs rename to osu.Game/Screens/Multi/Screens/Lobby.cs index 65fa5fbb16..dcda40e0d7 100644 --- a/osu.Game/Screens/Multiplayer/Lobby.cs +++ b/osu.Game/Screens/Multi/Screens/Lobby.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Screens { public class Lobby : ScreenWhiteBox { diff --git a/osu.Game/Screens/Multiplayer/Match.cs b/osu.Game/Screens/Multi/Screens/Match.cs similarity index 96% rename from osu.Game/Screens/Multiplayer/Match.cs rename to osu.Game/Screens/Multi/Screens/Match.cs index 5402e70ea5..4ba7fe9f6a 100644 --- a/osu.Game/Screens/Multiplayer/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match.cs @@ -3,14 +3,14 @@ using System; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Play; -using OpenTK.Graphics; using osu.Game.Screens.Select; -using osu.Framework.Graphics; +using OpenTK.Graphics; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Screens { public class Match : ScreenWhiteBox { diff --git a/osu.Game/Screens/Multiplayer/MatchCreate.cs b/osu.Game/Screens/Multi/Screens/MatchCreate.cs similarity index 91% rename from osu.Game/Screens/Multiplayer/MatchCreate.cs rename to osu.Game/Screens/Multi/Screens/MatchCreate.cs index ca6b814cb9..6b4e26d5e5 100644 --- a/osu.Game/Screens/Multiplayer/MatchCreate.cs +++ b/osu.Game/Screens/Multi/Screens/MatchCreate.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Multi.Screens { public class MatchCreate : ScreenWhiteBox { diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index da82a49f51..236b1310e1 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -4,9 +4,11 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -21,6 +23,8 @@ using osu.Game.Rulesets.Objects.Types; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; +using osu.Game.Rulesets; +using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Select { @@ -28,6 +32,8 @@ namespace osu.Game.Screens.Select { private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); + private readonly IBindable ruleset = new Bindable(); + protected BufferedWedgeInfo Info; public BeatmapInfoWedge() @@ -46,6 +52,14 @@ namespace osu.Game.Screens.Select }; } + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] OsuGame osuGame) + { + if (osuGame != null) + ruleset.BindTo(osuGame.Ruleset); + ruleset.ValueChanged += updateRuleset; + } + protected override bool BlockPassThroughMouse => false; protected override void PopIn() @@ -62,9 +76,19 @@ namespace osu.Game.Screens.Select this.FadeOut(500, Easing.In); } + private WorkingBeatmap beatmap; + public void UpdateBeatmap(WorkingBeatmap beatmap) { - LoadComponentAsync(new BufferedWedgeInfo(beatmap) + this.beatmap = beatmap; + loadBeatmap(); + } + + private void updateRuleset(RulesetInfo ruleset) => loadBeatmap(); + + private void loadBeatmap() + { + LoadComponentAsync(new BufferedWedgeInfo(beatmap, ruleset.Value) { Shear = -Shear, Depth = Info?.Depth + 1 ?? 0, @@ -90,9 +114,13 @@ namespace osu.Game.Screens.Select private UnicodeBindableString titleBinding; private UnicodeBindableString artistBinding; - public BufferedWedgeInfo(WorkingBeatmap working) + private readonly RulesetInfo ruleset; + + public BufferedWedgeInfo(WorkingBeatmap working, RulesetInfo userRuleset) { this.working = working; + + ruleset = userRuleset ?? working.BeatmapInfo.Ruleset; } [BackgroundDependencyLoader] @@ -211,7 +239,6 @@ namespace osu.Game.Screens.Select private InfoLabel[] getInfoLabels() { var beatmap = working.Beatmap; - var info = working.BeatmapInfo; List labels = new List(); @@ -234,8 +261,20 @@ namespace osu.Game.Screens.Select Content = getBPMRange(beatmap), })); - //get statistics from the current ruleset. - labels.AddRange(info.Ruleset.CreateInstance().GetBeatmapStatistics(working).Select(s => new InfoLabel(s))); + IBeatmap playableBeatmap; + + try + { + // Try to get the beatmap with the user's ruleset + playableBeatmap = working.GetPlayableBeatmap(ruleset); + } + catch (BeatmapInvalidForRulesetException) + { + // Can't be converted to the user's ruleset, so use the beatmap's own ruleset + playableBeatmap = working.GetPlayableBeatmap(working.BeatmapInfo.Ruleset); + } + + labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s))); } return labels.ToArray();