diff --git a/osu-framework b/osu-framework
index 14a33d110e..1a259925b8 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 14a33d110e2ed32e3a875bc2acd2bade244ba045
+Subproject commit 1a259925b82c31ddcebf7b330a6ef9d3a9daf089
diff --git a/osu-resources b/osu-resources
index f6042e1cb3..a4418111f8 160000
--- a/osu-resources
+++ b/osu-resources
@@ -1 +1 @@
-Subproject commit f6042e1cb37cfad6c879d0e1245f7880c7fcd5f5
+Subproject commit a4418111f8ed2350a6fd46fe69258884f0757745
diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
index c6474eae5a..c090342a4b 100644
--- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
+++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
@@ -9,7 +9,7 @@
Properties
osu.Desktop.Deploy
osu.Desktop.Deploy
- v4.5.2
+ v4.6.1
512
true
diff --git a/osu.Desktop.Tests/Visual/TestCaseBeatmapDetails.cs b/osu.Desktop.Tests/Visual/TestCaseBeatmapDetails.cs
index 11a15cf56f..d0f631201a 100644
--- a/osu.Desktop.Tests/Visual/TestCaseBeatmapDetails.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseBeatmapDetails.cs
@@ -12,50 +12,104 @@ namespace osu.Desktop.Tests.Visual
{
public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
- private readonly BeatmapDetails details;
-
public TestCaseBeatmapDetails()
{
+ BeatmapDetails details;
Add(details = new BeatmapDetails
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(150),
- Beatmap = new BeatmapInfo
+ });
+
+ AddStep("beatmap all metrics", () => details.Beatmap = new BeatmapInfo
+ {
+ Version = "All Metrics",
+ Metadata = new BeatmapMetadata
{
- Version = "VisualTest",
- Metadata = new BeatmapMetadata
- {
- Source = "Some guy",
- Tags = "beatmap metadata example with a very very long list of tags and not much creativity",
- },
- Difficulty = new BeatmapDifficulty
- {
- CircleSize = 7,
- ApproachRate = 3.5f,
- OverallDifficulty = 5.7f,
- DrainRate = 1,
- },
- StarDifficulty = 5.3f,
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 10),
- Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6),
- },
+ Source = "osu!lazer",
+ Tags = "this beatmap has all the metrics",
+ },
+ Difficulty = new BeatmapDifficulty
+ {
+ CircleSize = 7,
+ DrainRate = 1,
+ OverallDifficulty = 5.7f,
+ ApproachRate = 3.5f,
+ },
+ StarDifficulty = 5.3f,
+ Metrics = new BeatmapMetrics
+ {
+ Ratings = Enumerable.Range(0, 10),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
});
- AddRepeatStep("fail values", newRetryAndFailValues, 10);
- }
+ AddStep("beatmap ratings", () => details.Beatmap = new BeatmapInfo
+ {
+ Version = "Only Ratings",
+ Metadata = new BeatmapMetadata
+ {
+ Source = "osu!lazer",
+ Tags = "this beatmap has ratings metrics but not retries or fails",
+ },
+ Difficulty = new BeatmapDifficulty
+ {
+ CircleSize = 6,
+ DrainRate = 9,
+ OverallDifficulty = 6,
+ ApproachRate = 6,
+ },
+ StarDifficulty = 4.8f,
+ Metrics = new BeatmapMetrics
+ {
+ Ratings = Enumerable.Range(0, 10),
+ },
+ });
- private int lastRange = 1;
+ AddStep("beatmap fails retries", () => details.Beatmap = new BeatmapInfo
+ {
+ Version = "Only Retries and Fails",
+ Metadata = new BeatmapMetadata
+ {
+ Source = "osu!lazer",
+ Tags = "this beatmap has retries and fails but no ratings",
+ },
+ Difficulty = new BeatmapDifficulty
+ {
+ CircleSize = 3.7f,
+ DrainRate = 6,
+ OverallDifficulty = 6,
+ ApproachRate = 7,
+ },
+ StarDifficulty = 2.91f,
+ Metrics = new BeatmapMetrics
+ {
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ },
+ });
- private void newRetryAndFailValues()
- {
- details.Beatmap.Metrics.Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6);
- details.Beatmap.Metrics.Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6);
- details.Beatmap = details.Beatmap;
- lastRange += 100;
+ AddStep("beatmap no metrics", () => details.Beatmap = new BeatmapInfo
+ {
+ Version = "No Metrics",
+ Metadata = new BeatmapMetadata
+ {
+ Source = "osu!lazer",
+ Tags = "this beatmap has no metrics",
+ },
+ Difficulty = new BeatmapDifficulty
+ {
+ CircleSize = 5,
+ DrainRate = 5,
+ OverallDifficulty = 5.5f,
+ ApproachRate = 6.5f,
+ },
+ StarDifficulty = 1.97f,
+ Metrics = new BeatmapMetrics(),
+ });
+
+ AddStep("null beatmap", () => details.Beatmap = null);
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Desktop.Tests/Visual/TestCaseDirect.cs b/osu.Desktop.Tests/Visual/TestCaseDirect.cs
index b78ea02767..9fd93c3f1e 100644
--- a/osu.Desktop.Tests/Visual/TestCaseDirect.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseDirect.cs
@@ -41,12 +41,14 @@ namespace osu.Desktop.Tests.Visual
{
new BeatmapSetInfo
{
+ OnlineBeatmapSetID = 578332,
Metadata = new BeatmapMetadata
{
Title = @"OrVid",
Artist = @"An",
Author = @"RLC",
Source = @"",
+ Tags = @"acuticnotes an-fillnote revid tear tearvid encrpted encryption axi axivid quad her hervid recoll",
},
OnlineInfo = new BeatmapSetOnlineInfo
{
@@ -71,12 +73,14 @@ namespace osu.Desktop.Tests.Visual
},
new BeatmapSetInfo
{
+ OnlineBeatmapSetID = 599627,
Metadata = new BeatmapMetadata
{
Title = @"tiny lamp",
Artist = @"fhana",
Author = @"Sotarks",
Source = @"ぎんぎつね",
+ Tags = @"lantis junichi sato yuxuki waga kevin mitsunaga towana gingitsune opening op full ver version kalibe collab collaboration",
},
OnlineInfo = new BeatmapSetOnlineInfo
{
@@ -101,12 +105,14 @@ namespace osu.Desktop.Tests.Visual
},
new BeatmapSetInfo
{
+ OnlineBeatmapSetID = 513268,
Metadata = new BeatmapMetadata
{
Title = @"At Gwanghwamun",
Artist = @"KYUHYUN",
Author = @"Cerulean Veyron",
Source = @"",
+ Tags = @"soul ballad kh super junior sj suju 슈퍼주니어 kt뮤직 sm엔터테인먼트 s.m.entertainment kt music 1st mini album ep",
},
OnlineInfo = new BeatmapSetOnlineInfo
{
@@ -146,12 +152,14 @@ namespace osu.Desktop.Tests.Visual
},
new BeatmapSetInfo
{
+ OnlineBeatmapSetID = 586841,
Metadata = new BeatmapMetadata
{
Title = @"RHAPSODY OF BLUE SKY",
Artist = @"fhana",
Author = @"[Kamiya]",
Source = @"小林さんちのメイドラゴン",
+ Tags = @"kobayashi san chi no maidragon aozora no opening anime maid dragon oblivion karen dynamix imoutosan pata-mon gxytcgxytc",
},
OnlineInfo = new BeatmapSetOnlineInfo
{
diff --git a/osu.Desktop.Tests/Visual/TestCaseEditorMenuBar.cs b/osu.Desktop.Tests/Visual/TestCaseEditorMenuBar.cs
new file mode 100644
index 0000000000..9cb3053ff2
--- /dev/null
+++ b/osu.Desktop.Tests/Visual/TestCaseEditorMenuBar.cs
@@ -0,0 +1,84 @@
+// 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.Game.Graphics.UserInterface;
+using osu.Game.Screens.Edit.Menus;
+
+namespace osu.Desktop.Tests.Visual
+{
+ public class TestCaseEditorMenuBar : OsuTestCase
+ {
+ public TestCaseEditorMenuBar()
+ {
+ Add(new EditorMenuBar
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Y = 50,
+ Items = new[]
+ {
+ new EditorMenuBarItem("File")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Clear All Notes"),
+ new EditorMenuItem("Open Difficulty..."),
+ new EditorMenuItem("Save"),
+ new EditorMenuItem("Create a new Difficulty..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Revert to Saved"),
+ new EditorMenuItem("Revert to Saved (Full)"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Test Beatmap"),
+ new EditorMenuItem("Open AiMod"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Upload Beatmap..."),
+ new EditorMenuItem("Export Package"),
+ new EditorMenuItem("Export Map Package"),
+ new EditorMenuItem("Import from..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Open Song Folder"),
+ new EditorMenuItem("Open .osu in Notepad"),
+ new EditorMenuItem("Open .osb in Notepad"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Exit"),
+ }
+ },
+ new EditorMenuBarItem("Timing")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Time Signature"),
+ new EditorMenuItem("Metronome Clicks"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Add Timing Section"),
+ new EditorMenuItem("Add Inheriting Section"),
+ new EditorMenuItem("Reset Current Section"),
+ new EditorMenuItem("Delete Timing Section"),
+ new EditorMenuItem("Resnap Current Section"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Timing Setup"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
+ new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
+ new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
+ new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Set Current Position as Preview Point"),
+ }
+ },
+ new EditorMenuBarItem("Testing")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Item 1"),
+ new EditorMenuItem("Item 2"),
+ new EditorMenuItem("Item 3"),
+ }
+ },
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Desktop.Tests/Visual/TestCaseHitObjects.cs b/osu.Desktop.Tests/Visual/TestCaseHitObjects.cs
index 13e05d6477..cb365962a3 100644
--- a/osu.Desktop.Tests/Visual/TestCaseHitObjects.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseHitObjects.cs
@@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using OpenTK;
@@ -110,10 +109,7 @@ namespace osu.Desktop.Tests.Visual
h.Depth = depth++;
if (auto)
- {
h.State = ArmedState.Hit;
- h.Judgement = new OsuJudgement { Result = HitResult.Hit };
- }
playfieldContainer.Add(h);
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
diff --git a/osu.Desktop.Tests/Visual/TestCaseLeaderboard.cs b/osu.Desktop.Tests/Visual/TestCaseLeaderboard.cs
index 5f8ee8795c..f67db2f41a 100644
--- a/osu.Desktop.Tests/Visual/TestCaseLeaderboard.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseLeaderboard.cs
@@ -1,13 +1,13 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using OpenTK;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
-using OpenTK;
namespace osu.Desktop.Tests.Visual
{
@@ -24,7 +24,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.XH,
- Accuracy = 100,
+ Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -42,7 +42,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.X,
- Accuracy = 100,
+ Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -60,7 +60,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.SH,
- Accuracy = 100,
+ Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -78,7 +78,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.S,
- Accuracy = 100,
+ Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -96,7 +96,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.A,
- Accuracy = 100,
+ Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -114,7 +114,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.B,
- Accuracy = 98.26,
+ Accuracy = 0.9826,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -132,7 +132,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.C,
- Accuracy = 96.54,
+ Accuracy = 0.9654,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -150,7 +150,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.F,
- Accuracy = 60.25,
+ Accuracy = 0.6025,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -168,7 +168,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.F,
- Accuracy = 51.40,
+ Accuracy = 0.5140,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
@@ -186,7 +186,7 @@ namespace osu.Desktop.Tests.Visual
new Score
{
Rank = ScoreRank.F,
- Accuracy = 42.22,
+ Accuracy = 0.4222,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
diff --git a/osu.Desktop.Tests/Visual/TestCaseManiaHitObjects.cs b/osu.Desktop.Tests/Visual/TestCaseManiaHitObjects.cs
index 76235bbf19..d855e86aa0 100644
--- a/osu.Desktop.Tests/Visual/TestCaseManiaHitObjects.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseManiaHitObjects.cs
@@ -41,8 +41,20 @@ namespace osu.Desktop.Tests.Visual
RelativeChildSize = new Vector2(1, 10000),
Children = new[]
{
- new DrawableNote(new Note { StartTime = 5000 }, ManiaAction.Key1) { AccentColour = Color4.Red },
- new DrawableNote(new Note { StartTime = 6000 }, ManiaAction.Key1) { AccentColour = Color4.Red }
+ new DrawableNote(new Note(), ManiaAction.Key1)
+ {
+ Y = 5000,
+ LifetimeStart = double.MinValue,
+ LifetimeEnd = double.MaxValue,
+ AccentColour = Color4.Red
+ },
+ new DrawableNote(new Note(), ManiaAction.Key1)
+ {
+ Y = 6000,
+ LifetimeStart = double.MinValue,
+ LifetimeEnd = double.MaxValue,
+ AccentColour = Color4.Red
+ }
}
}
}
@@ -63,11 +75,14 @@ namespace osu.Desktop.Tests.Visual
RelativeChildSize = new Vector2(1, 10000),
Children = new[]
{
- new DrawableHoldNote(new HoldNote
+ new DrawableHoldNote(new HoldNote(), ManiaAction.Key1)
{
- StartTime = 5000,
- Duration = 1000
- }, ManiaAction.Key1) { AccentColour = Color4.Red }
+ Y = 5000,
+ Height = 1000,
+ LifetimeStart = double.MinValue,
+ LifetimeEnd = double.MaxValue,
+ AccentColour = Color4.Red
+ }
}
}
}
diff --git a/osu.Desktop.Tests/Visual/TestCaseManiaPlayfield.cs b/osu.Desktop.Tests/Visual/TestCaseManiaPlayfield.cs
index fb14bdb3bf..28cc7e5af8 100644
--- a/osu.Desktop.Tests/Visual/TestCaseManiaPlayfield.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseManiaPlayfield.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
@@ -13,6 +14,8 @@ using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mania.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Desktop.Tests.Visual
{
@@ -29,6 +32,8 @@ namespace osu.Desktop.Tests.Visual
public TestCaseManiaPlayfield()
{
+ var rng = new Random(1337);
+
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
@@ -43,6 +48,20 @@ namespace osu.Desktop.Tests.Visual
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(false, true));
AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
AddStep("Notes with gravity (reversed)", () => createPlayfieldWithNotes(true, true));
+
+ AddStep("Hit explosion", () =>
+ {
+ var playfield = createPlayfield(4, SpecialColumnPosition.Normal);
+
+ int col = rng.Next(0, 4);
+
+ var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
+ {
+ AccentColour = playfield.Columns.ElementAt(col).AccentColour
+ };
+
+ playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
+ });
}
[BackgroundDependencyLoader]
@@ -56,7 +75,7 @@ namespace osu.Desktop.Tests.Visual
TimingPoint = { BeatLength = 1000 }
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
- private void createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
+ private ManiaPlayfield createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
{
Clear();
@@ -72,6 +91,8 @@ namespace osu.Desktop.Tests.Visual
});
playfield.Inverted.Value = inverted;
+
+ return playfield;
}
private void createPlayfieldWithNotes(bool gravity, bool inverted = false)
diff --git a/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs
index 379100b543..8d1ae7d913 100644
--- a/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs
+++ b/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs
@@ -32,7 +32,7 @@ namespace osu.Desktop.Tests.Visual
backingDatabase.CreateTable();
rulesets = new RulesetStore(backingDatabase);
- manager = new BeatmapManager(storage, null, backingDatabase, rulesets);
+ manager = new BeatmapManager(storage, null, backingDatabase, rulesets, null);
for (int i = 0; i < 100; i += 10)
manager.Import(createTestBeatmapSet(i));
diff --git a/osu.Desktop.Tests/Visual/TestCasePlayer.cs b/osu.Desktop.Tests/Visual/TestCasePlayer.cs
index f5d02d3f2b..03ee82dc73 100644
--- a/osu.Desktop.Tests/Visual/TestCasePlayer.cs
+++ b/osu.Desktop.Tests/Visual/TestCasePlayer.cs
@@ -1,18 +1,18 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using System.Collections.Generic;
using osu.Desktop.Tests.Beatmaps;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
-using osu.Game.Rulesets.Objects;
-using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Play;
-using OpenTK;
using OpenTK.Graphics;
+using osu.Game.Rulesets.Mods;
+using System.Linq;
+using osu.Game.Beatmaps.Formats;
+using System.Text;
+using System.IO;
namespace osu.Desktop.Tests.Visual
{
@@ -33,55 +33,739 @@ namespace osu.Desktop.Tests.Visual
{
base.LoadComplete();
- var objects = new List();
-
- int time = 1500;
- for (int i = 0; i < 50; i++)
- {
- objects.Add(new HitCircle
- {
- StartTime = time,
- Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : OsuPlayfield.BASE_SIZE.X,
- i % 4 < 2 ? 0 : OsuPlayfield.BASE_SIZE.Y),
- NewCombo = i % 4 == 0
- });
-
- time += 500;
- }
-
- Beatmap b = new Beatmap
- {
- HitObjects = objects,
- BeatmapInfo = new BeatmapInfo
- {
- Difficulty = new BeatmapDifficulty(),
- Ruleset = rulesets.Query().First(),
- Metadata = new BeatmapMetadata
- {
- Artist = @"Unknown",
- Title = @"Sample Beatmap",
- Author = @"peppy",
- }
- }
- };
-
- WorkingBeatmap beatmap = new TestWorkingBeatmap(b);
-
Add(new Box
{
RelativeSizeAxes = Framework.Graphics.Axes.Both,
Colour = Color4.Black,
});
- Add(Player = CreatePlayer(beatmap));
+ foreach (var r in rulesets.Query())
+ AddStep(r.Name, () => loadPlayerFor(r));
+
+ loadPlayerFor(rulesets.Query().First());
}
- protected virtual Player CreatePlayer(WorkingBeatmap beatmap)
+ private void loadPlayerFor(RulesetInfo r)
+ {
+ Beatmap beatmap;
+
+ using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data)))
+ using (var reader = new StreamReader(stream))
+ beatmap = BeatmapDecoder.GetDecoder(reader).Decode(reader);
+
+ beatmap.BeatmapInfo.Ruleset = r;
+
+ var instance = r.CreateInstance();
+
+ WorkingBeatmap working = new TestWorkingBeatmap(beatmap);
+ working.Mods.Value = new[] { instance.GetAllMods().First(m => m is ModNoFail) };
+
+ if (Player != null)
+ Remove(Player);
+
+ Add(Player = CreatePlayer(working, instance));
+ }
+
+ protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
{
return new Player
{
InitialBeatmap = beatmap
};
}
+
+ private const string test_beatmap_data =
+@"osu file format v14
+
+[General]
+AudioLeadIn: 500
+PreviewTime: 53498
+Countdown: 0
+SampleSet: Soft
+StackLeniency: 0.7
+Mode: 0
+LetterboxInBreaks: 0
+WidescreenStoryboard: 1
+
+[Editor]
+DistanceSpacing: 1.2
+BeatDivisor: 4
+GridSize: 4
+TimelineZoom: 1
+
+[Metadata]
+Title:My Love
+TitleUnicode:My Love
+Artist:Kuba Oms
+ArtistUnicode:Kuba Oms
+Creator:W h i t e
+Version:Hard
+Source:ADHD
+Tags:Monthly Beatmapping Contest Electronic folk pop w_h_i_t_e
+BeatmapID:397534
+BeatmapSetID:163112
+
+[Difficulty]
+HPDrainRate:5
+CircleSize:4
+OverallDifficulty:6
+ApproachRate:7
+SliderMultiplier:1.44
+SliderTickRate:2
+
+[Events]
+//Break Periods
+2,69870,83770
+2,152170,158770
+//Storyboard Layer 0 (Background)
+//Storyboard Layer 1 (Fail)
+//Storyboard Layer 2 (Pass)
+//Storyboard Layer 3 (Foreground)
+//Storyboard Sound Samples
+
+[TimingPoints]
+2170,468.75,4,2,0,40,1,0
+4045,-100,4,2,0,30,0,0
+4162,-100,4,2,0,40,0,0
+5920,-100,4,2,0,30,0,0
+6037,-100,4,2,0,40,0,0
+7795,-100,4,2,0,30,0,0
+7912,-100,4,2,0,40,0,0
+9670,-100,4,2,0,40,0,0
+9787,-100,4,2,0,50,0,0
+11545,-100,4,2,0,40,0,0
+11662,-100,4,2,0,50,0,0
+13420,-100,4,2,0,40,0,0
+13537,-100,4,2,0,50,0,0
+15295,-100,4,2,0,40,0,0
+15412,-100,4,2,0,50,0,0
+17170,-100,4,2,0,40,0,0
+17287,-100,4,2,0,50,0,0
+19045,-100,4,2,0,40,0,0
+19162,-100,4,2,0,50,0,0
+20920,-100,4,2,0,40,0,0
+21037,-100,4,2,0,50,0,0
+22795,-100,4,2,0,40,0,0
+22912,-100,4,2,0,50,0,0
+24670,-100,4,2,0,70,0,0
+37560,-200,4,2,0,30,0,0
+38263,-200,4,2,0,5,0,0
+38966,-100,4,2,0,30,0,0
+39670,-100,4,2,0,70,0,0
+53732,-100,4,2,0,40,0,0
+54670,-100,4,2,0,80,0,1
+55138,-100,4,2,0,60,0,1
+55255,-100,4,2,0,80,0,1
+56076,-100,4,2,0,60,0,1
+56193,-100,4,2,0,80,0,1
+57013,-100,4,2,0,60,0,1
+57130,-100,4,2,0,80,0,1
+57951,-100,4,2,0,60,0,1
+58068,-100,4,2,0,80,0,1
+58888,-100,4,2,0,60,0,1
+59005,-100,4,2,0,80,0,1
+59826,-100,4,2,0,60,0,1
+59943,-100,4,2,0,80,0,1
+60763,-100,4,2,0,60,0,1
+60880,-100,4,2,0,80,0,1
+61701,-100,4,2,0,60,0,1
+61818,-100,4,2,0,80,0,1
+62638,-100,4,2,0,60,0,1
+62755,-100,4,2,0,80,0,1
+63576,-100,4,2,0,60,0,1
+63693,-100,4,2,0,80,0,1
+64513,-100,4,2,0,60,0,1
+64630,-100,4,2,0,80,0,1
+65451,-100,4,2,0,60,0,1
+65568,-100,4,2,0,80,0,1
+66388,-100,4,2,0,60,0,1
+66505,-100,4,2,0,80,0,1
+67326,-100,4,2,0,60,0,1
+67443,-100,4,2,0,80,0,1
+68263,-100,4,2,0,60,0,1
+68380,-100,4,2,0,80,0,1
+69201,-100,4,2,0,60,0,1
+69318,-100,4,2,0,80,0,1
+69670,-100,4,2,0,70,0,0
+84670,-100,4,2,0,70,0,0
+97560,-200,4,2,0,70,0,0
+97795,-200,4,2,0,30,0,0
+98966,-100,4,2,0,30,0,0
+99670,-100,4,2,0,70,0,0
+113732,-100,4,2,0,40,0,0
+114670,-100,4,2,0,80,0,1
+115138,-100,4,2,0,60,0,1
+115255,-100,4,2,0,80,0,1
+116076,-100,4,2,0,60,0,1
+116193,-100,4,2,0,80,0,1
+117013,-100,4,2,0,60,0,1
+117130,-100,4,2,0,80,0,1
+117951,-100,4,2,0,60,0,1
+118068,-100,4,2,0,80,0,1
+118888,-100,4,2,0,60,0,1
+119005,-100,4,2,0,80,0,1
+119826,-100,4,2,0,60,0,1
+119943,-100,4,2,0,80,0,1
+120763,-100,4,2,0,60,0,1
+120880,-100,4,2,0,80,0,1
+121701,-100,4,2,0,60,0,1
+121818,-100,4,2,0,80,0,1
+122638,-100,4,2,0,60,0,1
+122755,-100,4,2,0,80,0,1
+123576,-100,4,2,0,60,0,1
+123693,-100,4,2,0,80,0,1
+124513,-100,4,2,0,60,0,1
+124630,-100,4,2,0,80,0,1
+125451,-100,4,2,0,60,0,1
+125568,-100,4,2,0,80,0,1
+126388,-100,4,2,0,60,0,1
+126505,-100,4,2,0,80,0,1
+127326,-100,4,2,0,60,0,1
+127443,-100,4,2,0,80,0,1
+128263,-100,4,2,0,60,0,1
+128380,-100,4,2,0,80,0,1
+129201,-100,4,2,0,60,0,1
+129318,-100,4,2,0,80,0,1
+129670,-200,4,2,0,40,0,0
+144670,-133.333333333333,4,2,0,40,0,0
+159670,-133.333333333333,4,2,0,40,0,0
+163420,-133.333333333333,4,2,0,45,0,0
+163888,-125,4,2,0,50,0,0
+164357,-117.647058823529,4,2,0,55,0,0
+164826,-111.111111111111,4,2,0,60,0,0
+165295,-105.263157894737,4,2,0,65,0,0
+165763,-100,4,2,0,70,0,0
+166232,-100,4,2,0,40,0,0
+167170,-100,4,2,0,80,0,1
+167638,-100,4,2,0,60,0,1
+167755,-100,4,2,0,80,0,1
+168576,-100,4,2,0,60,0,1
+168693,-100,4,2,0,80,0,1
+169513,-100,4,2,0,60,0,1
+169630,-100,4,2,0,80,0,1
+170451,-100,4,2,0,60,0,1
+170568,-100,4,2,0,80,0,1
+171388,-100,4,2,0,60,0,1
+171505,-100,4,2,0,80,0,1
+172326,-100,4,2,0,60,0,1
+172443,-100,4,2,0,80,0,1
+173263,-100,4,2,0,60,0,1
+173380,-100,4,2,0,80,0,1
+174201,-100,4,2,0,60,0,1
+174318,-100,4,2,0,80,0,1
+175138,-100,4,2,0,60,0,1
+175255,-100,4,2,0,80,0,1
+176076,-100,4,2,0,60,0,1
+176193,-100,4,2,0,80,0,1
+177013,-100,4,2,0,60,0,1
+177130,-100,4,2,0,80,0,1
+177951,-100,4,2,0,60,0,1
+178068,-100,4,2,0,80,0,1
+178888,-100,4,2,0,60,0,1
+179005,-100,4,2,0,80,0,1
+179826,-100,4,2,0,60,0,1
+179943,-100,4,2,0,80,0,1
+180763,-100,4,2,0,60,0,1
+180880,-100,4,2,0,80,0,1
+180998,-100,4,2,0,80,0,0
+181466,-100,4,2,0,60,0,0
+181584,-100,4,2,0,80,0,0
+181935,-100,4,2,0,80,0,0
+182170,-100,4,2,0,80,0,1
+182638,-100,4,2,0,60,0,1
+182755,-100,4,2,0,80,0,1
+183576,-100,4,2,0,60,0,1
+183693,-100,4,2,0,80,0,1
+184513,-100,4,2,0,60,0,1
+184630,-100,4,2,0,80,0,1
+185451,-100,4,2,0,60,0,1
+185568,-100,4,2,0,80,0,1
+186388,-100,4,2,0,60,0,1
+186505,-100,4,2,0,80,0,1
+187326,-100,4,2,0,60,0,1
+187443,-100,4,2,0,80,0,1
+188263,-100,4,2,0,60,0,1
+188380,-100,4,2,0,80,0,1
+189201,-100,4,2,0,60,0,1
+189318,-100,4,2,0,80,0,1
+190138,-100,4,2,0,60,0,1
+190255,-100,4,2,0,80,0,1
+191076,-100,4,2,0,60,0,1
+191193,-100,4,2,0,80,0,1
+192013,-100,4,2,0,60,0,1
+192130,-100,4,2,0,80,0,1
+192951,-100,4,2,0,60,0,1
+193068,-100,4,2,0,80,0,1
+193888,-100,4,2,0,60,0,1
+194005,-100,4,2,0,80,0,1
+194826,-100,4,2,0,60,0,1
+194943,-100,4,2,0,80,0,1
+195295,-100,4,2,0,50,0,1
+195529,-100,4,2,0,52,0,1
+195646,-100,4,2,0,54,0,1
+195763,-100,4,2,0,56,0,1
+195880,-100,4,2,0,58,0,1
+195998,-100,4,2,0,60,0,1
+196115,-100,4,2,0,62,0,1
+196232,-100,4,2,0,64,0,1
+196349,-100,4,2,0,68,0,1
+196466,-100,4,2,0,70,0,1
+196584,-100,4,2,0,72,0,1
+196701,-100,4,2,0,74,0,1
+196818,-100,4,2,0,76,0,1
+196935,-100,4,2,0,78,0,1
+197052,-100,4,2,0,80,0,1
+197170,-100,4,2,0,80,0,0
+197873,-100,4,2,0,60,0,0
+197990,-100,4,2,0,80,0,0
+198341,-100,4,2,0,60,0,0
+199045,-100,4,2,0,80,0,0
+199279,-100,4,2,0,60,0,0
+199630,-100,4,2,0,80,0,0
+200216,-100,4,2,0,60,0,0
+200334,-100,4,2,0,80,0,0
+201623,-100,4,2,0,60,0,0
+201740,-100,4,2,0,80,0,0
+202326,-100,4,2,0,60,0,0
+202443,-100,4,2,0,80,0,0
+203029,-100,4,2,0,60,0,0
+203498,-100,4,2,0,80,0,0
+203966,-100,4,2,0,60,0,0
+204201,-100,4,2,0,80,0,0
+205373,-100,4,2,0,60,0,0
+205490,-100,4,2,0,80,0,0
+205841,-100,4,2,0,60,0,0
+206076,-100,4,2,0,60,0,0
+206545,-100,4,2,0,80,0,0
+206779,-100,4,2,0,60,0,0
+207130,-100,4,2,0,80,0,0
+207716,-100,4,2,0,60,0,0
+207951,-100,4,2,0,80,0,0
+209123,-100,4,2,0,60,0,0
+209240,-100,4,2,0,80,0,0
+209826,-100,4,2,0,60,0,0
+209943,-100,4,2,0,80,0,0
+210529,-100,4,2,0,60,0,0
+210880,-100,4,2,0,80,0,0
+211232,-100,4,2,0,60,0,0
+211701,-100,4,2,0,70,0,0
+212170,-100,4,2,0,80,0,0
+212873,-100,4,2,0,60,0,0
+212990,-100,4,2,0,80,0,0
+213341,-100,4,2,0,60,0,0
+213576,-100,4,2,0,60,0,0
+214045,-100,4,2,0,80,0,0
+214279,-100,4,2,0,60,0,0
+214630,-100,4,2,0,80,0,0
+215216,-100,4,2,0,60,0,0
+215451,-100,4,2,0,80,0,0
+216623,-100,4,2,0,60,0,0
+216740,-100,4,2,0,80,0,0
+217326,-100,4,2,0,60,0,0
+217443,-100,4,2,0,80,0,0
+218029,-100,4,2,0,60,0,0
+218498,-100,4,2,0,80,0,0
+218732,-100,4,2,0,50,0,0
+219670,-100,4,2,0,70,0,0
+220138,-100,4,2,0,65,0,0
+220373,-100,4,2,0,45,0,0
+220490,-100,4,2,0,65,0,0
+220607,-100,4,2,0,60,0,0
+220841,-100,4,2,0,35,0,0
+221076,-100,4,2,0,35,0,0
+221545,-100,4,2,0,50,0,0
+221779,-100,4,2,0,30,0,0
+222013,-111.111111111111,4,2,0,25,0,0
+222130,-111.111111111111,4,2,0,40,0,0
+222482,-125,4,2,0,40,0,0
+222716,-125,4,2,0,20,0,0
+222951,-100,4,2,0,15,0,0
+223420,-100,4,2,0,30,0,0
+224357,-100,4,2,0,25,0,0
+225295,-100,4,2,0,20,0,0
+226232,-100,4,2,0,15,0,0
+226701,-100,4,2,0,10,0,0
+227170,-100,4,2,0,5,0,0
+
+
+[Colours]
+ Combo1 : 17,254,176
+Combo2 : 173,255,95
+Combo3 : 255,88,100
+Combo4 : 255,94,55
+
+[HitObjects]
+320,256,2170,6,0,P|256:284|192:256,1,144,4|0,0:0|0:0,0:0:0:0:
+144,184,2873,1,0,0:0:0:0:
+108,260,3107,2,0,P|112:296|100:336,1,72
+28,288,3576,2,0,P|24:252|36:212,1,72,0|0,0:0|0:0,0:0:0:0:
+76,140,4045,6,0,L|220:136,1,144,4|0,0:0|0:0,0:0:0:0:
+292,88,4748,1,0,0:0:0:0:
+292,88,4982,2,0,P|304:120|300:168,1,72
+388,168,5451,2,0,P|396:133|416:103,1,72,0|0,0:0|0:0,0:0:0:0:
+472,172,5920,6,0,B|470:200|457:222|457:222|488:256|476:308,1,144,4|0,0:0|0:0,0:0:0:0:
+396,280,6623,1,0,0:0:0:0:
+324,328,6857,2,0,P|288:332|252:324,1,72
+180,280,7326,2,0,L|108:284,1,72,0|0,0:0|0:0,0:0:0:0:
+256,192,7795,12,0,9670,0:0:0:0:
+428,212,10138,1,0,0:0:0:0:
+292,320,10607,1,0,0:0:0:0:
+184,184,11076,2,0,L|112:180,1,72,0|0,0:0|0:0,0:0:0:0:
+24,172,11545,5,6,0:0:0:0:
+160,280,12013,1,0,0:0:0:0:
+268,144,12482,1,0,0:0:0:0:
+132,36,12951,2,0,L|204:32,1,72,0|0,0:0|0:0,0:0:0:0:
+284,60,13420,6,0,P|340:100|344:180,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0:
+268,144,14591,1,0,0:0:0:0:
+284,228,14826,2,0,P|316:248|364:252,1,72,0|0,0:0|0:0,0:0:0:0:
+436,248,15295,6,0,P|372:272|344:340,1,144,6|2,0:0|0:0,0:0:0:0:
+168,338,16232,2,0,P|141:273|76:248,1,144,2|2,0:0|0:0,0:0:0:0:
+4,296,16935,1,0,0:0:0:0:
+80,336,17170,5,6,0:0:0:0:
+44,168,17638,1,0,0:0:0:0:
+212,128,18107,1,0,0:0:0:0:
+248,296,18576,2,0,P|284:288|320:292,1,72,0|0,0:0|0:0,0:0:0:0:
+400,324,19045,5,6,0:0:0:0:
+280,200,19513,1,0,0:0:0:0:
+368,52,19982,1,0,0:0:0:0:
+488,176,20451,2,0,P|452:168|416:172,1,72,0|0,0:0|0:0,0:0:0:0:
+336,200,20920,6,0,P|284:216|200:192,1,144,6|0,0:0|0:0,0:0:0:0:
+200,192,21857,2,0,L|204:264,1,72,0|0,0:3|0:0,0:0:0:0:
+117,244,22326,2,0,L|120:172,1,72,0|0,0:0|0:0,0:0:0:0:
+40,152,22795,6,0,L|28:296,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0:
+152,24,24201,1,0,0:0:0:0:
+220,76,24435,1,0,3:0:0:0:
+304,56,24670,6,0,P|288:120|296:196,1,144,4|2,0:3|0:3,0:0:0:0:
+344,268,25373,1,0,0:0:0:0:
+416,316,25607,2,0,P|452:312|508:316,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+244,344,26545,6,0,P|176:356|108:328,1,144,4|2,0:3|0:3,0:0:0:0:
+60,256,27248,1,0,0:0:0:0:
+36,172,27482,2,0,L|40:100,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+188,252,28420,6,0,P|192:184|196:100,1,144,4|2,0:3|0:3,0:0:0:0:
+140,40,29123,1,0,0:0:0:0:
+140,40,29357,2,0,B|172:16|220:24|220:24|288:36,1,144,0|2,0:0|0:3,0:0:0:0:
+364,52,30060,1,0,0:0:0:0:
+308,116,30295,6,0,B|300:168|300:168|328:256,1,144,4|2,0:3|0:3,0:0:0:0:
+340,340,30998,1,0,0:0:0:0:
+260,308,31232,2,0,L|188:304,1,72,0|2,0:0|0:3,0:0:0:0:
+100,296,31701,1,2,0:3:0:0:
+136,374,31935,1,0,0:0:0:0:
+152,224,32170,6,0,P|160:152|132:88,1,144,4|2,0:3|0:3,0:0:0:0:
+56,48,32873,1,0,0:0:0:0:
+60,136,33107,2,0,L|56:208,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+224,76,34045,6,0,P|289:104|360:96,1,144,4|2,0:3|0:3,0:0:0:0:
+432,48,34748,1,0,0:0:0:0:
+440,132,34982,2,0,B|432:156|432:156|436:204,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+448,304,35920,6,0,B|412:315|380:292|380:292|348:269|312:280,1,144,4|2,0:3|0:3,0:0:0:0:
+332,364,36623,1,0,0:0:0:0:
+247,339,36857,2,0,P|230:308|225:273,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+312,280,37560,6,0,L|316:172,1,108
+134,35,38966,5,0,0:0:0:0:
+72,96,39201,2,0,P|119:119|171:111,1,108,0|0,0:0|0:0,0:0:0:0:
+192,100,39670,6,0,L|200:172,1,72,4|2,0:0|0:0,0:0:0:0:
+147,240,40138,2,0,P|133:272|132:308,1,72,0|2,1:0|0:0,0:0:0:0:
+216,292,40607,2,0,B|260:308|260:308|356:292,1,144,4|0,2:3|1:0,1:0:0:0:
+356,292,41310,1,2,0:0:0:0:
+436,327,41545,6,0,P|441:292|435:257,1,72,4|2,0:3|0:0,0:0:0:0:
+364,204,42013,2,0,P|336:144|352:68,1,144,0|4,1:0|2:3,1:0:0:0:
+404,0,42716,1,2,0:0:0:0:
+440,80,42951,2,0,B|464:84|464:84|512:80,1,72,0|2,1:0|0:0,0:0:0:0:
+351,71,43420,6,0,B|296:68|296:68|268:76|268:76|196:72,1,144,4|0,2:3|1:0,1:0:0:0:
+120,68,44123,1,2,0:0:0:0:
+160,144,44357,2,0,P|172:180|168:232,1,72,4|2,0:3|0:0,0:0:0:0:
+76,264,44826,2,0,P|76:228|88:194,1,72,0|2,1:0|0:0,0:0:0:0:
+160,144,45295,5,4,0:3:0:0:
+244,164,45529,1,2,0:0:0:0:
+268,248,45763,2,0,L|344:252,1,72,0|2,1:0|0:0,0:0:0:0:
+408,156,46232,2,0,L|336:159,1,72,4|2,0:3|0:0,0:0:0:0:
+212,72,46701,2,0,L|288:76,1,72,0|2,1:0|0:0,0:0:0:0:
+400,72,47170,6,0,P|464:96|488:172,1,144,4|0,2:0|1:0,1:0:0:0:
+476,248,47873,1,2,0:0:0:0:
+436,324,48107,2,0,L|284:320,1,144,4|0,2:3|1:0,1:0:0:0:
+204,316,48810,1,2,0:0:0:0:
+127,355,49045,6,0,P|120:321|124:285,1,72,4|2,0:3|0:0,0:0:0:0:
+192,232,49513,2,0,L|335:228,1,144,0|4,1:0|2:3,1:0:0:0:
+412,188,50216,1,2,0:0:0:0:
+444,108,50451,2,0,P|452:72|448:36,1,72,0|2,1:0|0:0,0:0:0:0:
+368,68,50920,6,0,B|332:79|300:56|300:56|268:33|232:44,1,144,4|0,2:3|1:0,1:0:0:0:
+152,76,51623,1,2,0:0:0:0:
+76,116,51857,2,0,L|80:268,1,144,4|0,2:3|1:0,1:0:0:0:
+80,260,52560,1,2,0:0:0:0:
+8,308,52795,6,0,P|34:334|69:346,1,72,4|2,0:3|0:0,0:0:0:0:
+148,312,53263,2,0,P|163:278|162:241,1,72,0|2,1:0|0:0,0:0:0:0:
+156,156,53732,5,0,3:0:0:0:
+156,156,53966,1,2,0:0:0:0:
+236,196,54201,2,0,L|312:192,1,72,8|0,0:3|0:0,0:0:0:0:
+368,256,54670,6,0,P|392:216|352:116,1,144,4|2,0:0|1:2,0:0:0:0:
+288,92,55373,1,0,0:0:0:0:
+360,40,55607,2,0,L|432:36,1,72,4|0,0:3|3:0,0:0:0:0:
+288,92,56076,2,0,L|216:88,1,72,2|0,1:2|0:0,0:0:0:0:
+132,72,56545,6,0,P|172:88|200:184,1,144,4|2,0:3|1:2,0:0:0:0:
+143,241,57248,1,0,0:0:0:0:
+65,202,57482,2,0,P|87:174|119:157,1,72,4|0,0:3|3:0,0:0:0:0:
+132,324,57951,2,0,P|98:312|72:288,1,72,2|0,1:2|0:0,0:0:0:0:
+143,241,58420,6,0,L|288:240,1,144,4|2,0:3|1:2,0:0:0:0:
+372,240,59123,1,0,0:0:0:0:
+330,314,59357,2,0,P|318:350|322:390,1,72,4|0,0:3|3:0,0:0:0:0:
+452,264,59826,2,0,P|453:228|442:194,1,72,2|0,1:2|0:0,0:0:0:0:
+384,128,60295,6,0,B|336:144|336:144|244:128,1,144,4|2,0:3|1:2,0:0:0:0:
+164,160,60998,2,0,P|160:116|168:88,1,72,0|4,0:0|0:3,0:0:0:0:
+244,128,61466,2,0,P|248:172|240:200,1,72,0|2,3:0|1:2,0:0:0:0:
+168,248,61935,1,0,0:0:0:0:
+120,320,62170,6,0,P|196:328|252:272,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
+80,244,63341,1,0,3:0:0:0:
+100,160,63576,2,0,L|24:156,1,72,2|0,1:2|0:0,0:0:0:0:
+180,128,64045,6,0,P|249:138|304:94,1,144,4|2,0:3|1:2,0:0:0:0:
+226,57,64748,1,0,0:0:0:0:
+304,94,64982,2,0,L|300:166,1,72,4|0,0:3|3:0,0:0:0:0:
+377,203,65451,2,0,L|388:132,1,72,2|0,1:2|0:0,0:0:0:0:
+468,180,65920,6,0,L|432:328,1,144,4|2,0:3|1:2,0:0:0:0:
+276,252,66857,2,0,P|208:248|140:280,1,144,4|2,0:3|1:2,0:0:0:0:
+84,344,67560,1,0,0:0:0:0:
+56,260,67795,6,0,L|52:188,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+168,128,68732,2,0,L|172:56,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+244,168,69435,1,0,0:0:0:0:
+332,164,69670,1,4,0:3:0:0:
+208,328,84670,6,0,P|224:264|216:188,1,144,4|2,0:3|0:3,0:0:0:0:
+168,116,85373,1,0,0:0:0:0:
+96,68,85607,2,0,P|60:72|4:68,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+268,40,86545,6,0,P|336:28|404:56,1,144,4|2,0:3|0:3,0:0:0:0:
+452,128,87248,1,0,0:0:0:0:
+476,212,87482,2,0,L|472:284,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+324,132,88420,6,0,P|320:200|316:284,1,144,4|2,0:3|0:3,0:0:0:0:
+372,344,89123,1,0,0:0:0:0:
+372,344,89357,2,0,B|340:368|292:360|292:360|224:348,1,144,0|2,0:0|0:3,0:0:0:0:
+148,332,90060,1,0,0:0:0:0:
+204,268,90295,6,0,B|212:216|212:216|184:128,1,144,4|2,0:3|0:3,0:0:0:0:
+172,44,90998,1,0,0:0:0:0:
+252,76,91232,2,0,L|324:80,1,72,0|2,0:0|0:3,0:0:0:0:
+412,88,91701,1,2,0:3:0:0:
+377,9,91935,1,0,0:0:0:0:
+360,160,92170,6,0,P|352:232|380:296,1,144,4|2,0:3|0:3,0:0:0:0:
+456,336,92873,1,0,0:0:0:0:
+452,248,93107,2,0,L|456:176,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+288,308,94045,6,0,P|223:280|152:288,1,144,4|2,0:3|0:3,0:0:0:0:
+80,336,94748,1,0,0:0:0:0:
+72,252,94982,2,0,B|80:228|80:228|76:180,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+64,80,95920,6,0,B|100:69|132:92|132:92|164:115|200:104,1,144,4|2,0:3|0:3,0:0:0:0:
+180,20,96623,1,0,0:0:0:0:
+265,45,96857,2,0,P|282:76|287:111,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0:
+200,104,97560,1,0,0:0:0:0:
+200,104,97677,1,0,0:0:0:0:
+200,104,97795,6,0,B|196:142|217:166|217:166|176:180|160:220,1,144,4|0,0:3|0:0,0:0:0:0:
+240,248,98966,5,0,0:0:0:0:
+202,325,99201,2,0,P|254:333|301:309,1,108,0|0,0:0|0:0,0:0:0:0:
+315,292,99670,6,0,L|323:220,1,72,4|2,0:0|0:0,0:0:0:0:
+365,144,100138,2,0,P|379:112|380:76,1,72,0|2,1:0|0:0,0:0:0:0:
+296,92,100607,2,0,B|252:76|252:76|156:92,1,144,4|0,2:3|1:0,1:0:0:0:
+156,92,101310,1,2,0:0:0:0:
+76,57,101545,6,0,P|71:92|77:127,1,72,4|2,0:3|0:0,0:0:0:0:
+148,180,102013,2,0,P|176:240|160:316,1,144,0|4,1:0|2:3,1:0:0:0:
+108,384,102716,1,2,0:0:0:0:
+72,304,102951,2,0,B|48:300|48:300|0:304,1,72,0|2,1:0|0:0,0:0:0:0:
+161,313,103420,6,0,B|216:316|216:316|244:308|244:308|316:312,1,144,4|0,2:3|1:0,1:0:0:0:
+392,316,104123,1,2,0:0:0:0:
+352,240,104357,2,0,P|340:204|344:152,1,72,4|2,0:3|0:0,0:0:0:0:
+436,120,104826,2,0,P|436:156|424:190,1,72,0|2,1:0|0:0,0:0:0:0:
+352,240,105295,5,4,0:3:0:0:
+268,220,105529,1,2,0:0:0:0:
+244,136,105763,2,0,L|168:132,1,72,0|2,1:0|0:0,0:0:0:0:
+104,228,106232,2,0,L|176:225,1,72,4|2,0:3|0:0,0:0:0:0:
+300,312,106701,2,0,L|224:308,1,72,0|2,1:0|0:0,0:0:0:0:
+112,312,107170,6,0,P|48:288|24:212,1,144,4|0,2:0|1:0,1:0:0:0:
+36,136,107873,1,2,0:0:0:0:
+76,60,108107,2,0,L|228:64,1,144,4|0,2:3|1:0,1:0:0:0:
+308,68,108810,1,2,0:0:0:0:
+385,29,109045,6,0,P|392:63|388:99,1,72,4|2,0:3|0:0,0:0:0:0:
+320,152,109513,2,0,L|177:156,1,144,0|4,1:0|2:3,1:0:0:0:
+100,196,110216,1,2,0:0:0:0:
+68,276,110451,2,0,P|60:312|64:348,1,72,0|2,1:0|0:0,0:0:0:0:
+144,316,110920,6,0,B|180:305|212:328|212:328|244:351|280:340,1,144,4|0,2:3|1:0,1:0:0:0:
+360,308,111623,1,2,0:0:0:0:
+436,268,111857,2,0,L|432:116,1,144,4|0,2:3|1:0,1:0:0:0:
+432,124,112560,1,2,0:0:0:0:
+504,76,112795,6,0,P|478:50|443:38,1,72,4|2,0:3|0:0,0:0:0:0:
+364,72,113263,2,0,P|349:106|350:143,1,72,0|2,1:0|0:0,0:0:0:0:
+356,228,113732,5,0,3:0:0:0:
+356,228,113966,1,2,0:0:0:0:
+276,188,114201,2,0,L|200:192,1,72,8|0,0:3|0:0,0:0:0:0:
+144,128,114670,6,0,P|120:168|160:268,1,144,4|2,0:0|1:2,0:0:0:0:
+224,292,115373,1,0,0:0:0:0:
+152,344,115607,2,0,L|80:348,1,72,4|0,0:3|3:0,0:0:0:0:
+224,292,116076,2,0,L|296:296,1,72,2|0,1:2|0:0,0:0:0:0:
+380,312,116545,6,0,P|340:296|312:200,1,144,4|2,0:3|1:2,0:0:0:0:
+369,143,117248,1,0,0:0:0:0:
+447,182,117482,2,0,P|425:210|393:227,1,72,4|0,0:3|3:0,0:0:0:0:
+380,60,117951,2,0,P|414:72|440:96,1,72,2|0,1:2|0:0,0:0:0:0:
+369,143,118420,6,0,L|224:144,1,144,4|2,0:3|1:2,0:0:0:0:
+140,144,119123,1,0,0:0:0:0:
+182,70,119357,2,0,P|194:34|190:-6,1,72,4|0,0:3|3:0,0:0:0:0:
+60,120,119826,2,0,P|59:156|70:190,1,72,2|0,1:2|0:0,0:0:0:0:
+128,256,120295,6,0,B|176:240|176:240|268:256,1,144,4|2,0:3|1:2,0:0:0:0:
+348,224,120998,2,0,P|352:268|344:296,1,72,0|4,0:0|0:3,0:0:0:0:
+268,256,121466,2,0,P|264:212|272:184,1,72,0|2,3:0|1:2,0:0:0:0:
+344,136,121935,1,0,0:0:0:0:
+392,64,122170,6,0,P|316:56|260:112,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
+432,140,123341,1,0,3:0:0:0:
+412,224,123576,2,0,L|488:228,1,72,2|0,1:2|0:0,0:0:0:0:
+332,256,124045,6,0,P|263:246|208:290,1,144,4|2,0:3|1:2,0:0:0:0:
+286,327,124748,1,0,0:0:0:0:
+208,290,124982,2,0,L|212:218,1,72,4|0,0:3|3:0,0:0:0:0:
+135,181,125451,2,0,L|124:252,1,72,2|0,1:2|0:0,0:0:0:0:
+44,204,125920,6,0,L|80:56,1,144,4|2,0:3|1:2,0:0:0:0:
+236,132,126857,2,0,P|304:136|372:104,1,144,4|2,0:3|1:2,0:0:0:0:
+428,40,127560,1,0,0:0:0:0:
+456,124,127795,6,0,L|460:196,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+344,256,128732,2,0,L|340:328,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+268,216,129435,1,0,0:0:0:0:
+180,220,129670,5,4,2:0:0:0:
+256,40,130373,1,2,0:0:0:0:
+64,68,131076,1,2,0:0:0:0:
+92,136,131310,1,0,0:0:0:0:
+64,204,131545,6,0,L|60:288,1,72
+31,343,132248,2,0,P|86:345|127:309,1,108
+332,220,133420,5,2,0:0:0:0:
+256,40,134123,1,2,0:0:0:0:
+448,68,134826,1,2,0:0:0:0:
+420,136,135060,1,0,0:0:0:0:
+448,204,135295,6,0,L|452:288,1,72,2|0,0:0|0:0,0:0:0:0:
+480,343,135998,2,0,P|426:345|385:309,1,108
+256,192,137170,5,2,0:0:0:0:
+156,360,137873,1,2,0:0:0:0:
+356,360,138576,2,0,L|352:308,1,36,2|0,0:0|0:0,0:0:0:0:
+304,268,139045,6,0,P|336:253|372:252,1,72
+448,260,139748,2,0,L|444:152,1,108
+256,192,140920,5,2,0:0:0:0:
+356,24,141623,1,2,0:0:0:0:
+156,24,142326,2,0,L|160:72,1,36,2|0,0:0|0:0,0:0:0:0:
+208,116,142795,6,0,P|176:131|140:132,1,72,2|0,0:0|0:0,0:0:0:0:
+64,124,143498,2,0,L|68:232,1,108
+68,232,144670,5,4,0:3:0:0:
+216,320,145138,1,4,0:3:0:0:
+304,172,145607,1,4,0:3:0:0:
+156,84,146075,1,4,0:3:0:0:
+296,320,146545,5,4,0:3:0:0:
+208,172,147013,1,4,0:3:0:0:
+356,84,147482,1,4,0:3:0:0:
+444,232,147950,1,4,0:3:0:0:
+296,320,148420,6,0,P|252:328|192:296,2,108.000004119873,4|4|4,0:3|0:3|0:3,0:0:0:0:
+260,248,149591,1,0,0:0:0:0:
+320,196,149826,2,0,L|316:140,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0:
+120,236,159670,6,0,L|176:232,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0:
+160,152,160138,2,0,L|104:156,1,54.0000020599366,2|0,0:0|0:0,0:0:0:0:
+240,180,160607,2,0,P|292:188|344:172,1,108.000004119873,4|2,0:3|0:0,3:0:0:0:
+408,120,161310,1,0,3:0:0:0:
+424,200,161545,6,0,L|420:256,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0:
+376,320,162013,2,0,P|396:328|480:304,2,108.000004119873,2|6|2,2:0|0:3|2:0,3:0:0:0:
+312,268,163185,1,0,0:0:0:0:
+296,348,163420,6,0,L|240:344,1,54.0000020599366,4|0,3:0|3:0,0:0:0:0:
+160,320,163888,2,0,L|100:316,1,57.6,4|0,3:0|3:0,0:0:0:0:
+64,232,164357,6,0,L|128:228,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0:
+204,200,164825,2,0,L|268:196,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0:
+232,108,165295,6,0,L|164:104,1,68.399998173523,4|0,3:0|3:0,0:0:0:0:
+80,84,165763,2,0,L|4:80,1,72,4|0,3:0|3:0,0:0:0:0:
+324,120,167170,6,0,P|388:128|456:92,1,144,4|2,0:0|1:2,0:0:0:0:
+496,168,167873,1,0,0:0:0:0:
+496,168,168107,2,0,P|484:204|488:256,1,72,4|0,0:3|3:0,0:0:0:0:
+408,296,168576,2,0,P|398:261|378:231,1,72,2|0,1:2|0:0,0:0:0:0:
+296,200,169045,6,0,B|228:228|156:204,1,144,4|2,0:3|1:2,0:0:0:0:
+84,156,169748,1,0,0:0:0:0:
+80,244,169982,2,0,L|76:316,1,72,4|0,0:3|3:0,0:0:0:0:
+170,274,170451,2,0,L|156:204,1,72,2|0,1:2|0:0,0:0:0:0:
+216,140,170920,6,0,L|284:276,1,144,4|2,0:3|1:2,0:0:0:0:
+320,344,171623,1,0,0:0:0:0:
+372,276,171857,2,0,P|366:240|349:207,1,72,4|0,0:3|3:0,0:0:0:0:
+312,132,172326,2,0,L|276:60,1,72,2|0,1:2|0:0,0:0:0:0:
+208,20,172795,6,0,P|272:36|348:12,1,144,4|2,0:3|1:2,0:0:0:0:
+424,48,173498,2,0,L|412:132,1,72,0|4,0:0|0:3,0:0:0:0:
+484,168,173966,2,0,L|472:252,1,72,0|2,3:0|1:2,0:0:0:0:
+400,280,174435,1,0,0:0:0:0:
+346,348,174670,6,0,P|414:363|472:324,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
+312,268,175841,1,0,3:0:0:0:
+256,336,176076,2,0,L|184:332,1,72,2|0,1:2|0:0,0:0:0:0:
+80,244,176545,6,0,B|140:248|140:248|164:244|164:244|223:247,1,144,4|2,0:3|1:2,0:0:0:0:
+312,268,177248,1,0,0:0:0:0:
+224,247,177482,2,0,P|240:215|272:187,1,72,4|0,0:3|3:0,0:0:0:0:
+204,131,177951,2,0,P|233:111|275:103,1,72,2|0,1:2|0:0,0:0:0:0:
+240,23,178420,6,0,B|280:15|316:35|316:35|376:71,1,144,4|2,0:3|1:2,0:0:0:0:
+399,236,179357,2,0,B|359:244|323:224|323:224|263:188,1,144,4|2,0:3|1:2,0:0:0:0:
+204,132,180060,1,0,0:0:0:0:
+184,216,180295,6,0,L|188:288,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+120,156,180998,1,0,0:0:0:0:
+56,96,181232,2,0,L|60:24,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
+36,180,181935,1,0,0:0:0:0:
+100,240,182170,6,0,P|144:300|116:380,2,144,4|2|4,0:0|1:2|0:3,0:0:0:0:
+60,316,183341,1,0,0:0:0:0:
+220,352,183576,2,0,L|308:348,1,72,2|0,1:2|0:0,0:0:0:0:
+396,264,184045,6,0,B|336:268|336:268|312:264|312:264|253:267,1,144,4|2,0:3|1:2,0:0:0:0:
+253,267,184748,1,0,0:0:0:0:
+268,180,184982,2,0,L|339:177,1,72,4|0,0:3|0:0,0:0:0:0:
+164,280,185451,2,0,L|92:282,1,72,2|0,1:2|0:0,0:0:0:0:
+52,208,185920,6,0,P|8:268|32:344,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
+140,212,187091,1,0,0:0:0:0:
+92,284,187326,2,0,P|104:316|100:368,1,72,2|0,1:2|0:0,0:0:0:0:
+52,208,187795,6,0,P|48:136|76:72,1,144,4|2,0:3|1:2,0:0:0:0:
+160,52,188498,2,0,P|188:28|220:16,1,72,0|4,0:0|0:3,0:0:0:0:
+232,100,188966,2,0,P|268:93|301:98,1,72,0|2,0:0|1:2,0:0:0:0:
+372,152,189435,1,0,0:0:0:0:
+420,224,189670,6,0,P|428:296|400:360,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0:
+372,152,190841,1,0,0:0:0:0:
+392,68,191076,2,0,L|465:64,1,72,2|0,1:2|0:0,0:0:0:0:
+304,92,191545,6,0,P|236:104|168:76,1,144,4|2,0:3|1:2,0:0:0:0:
+108,12,192248,1,0,0:0:0:0:
+168,76,192482,2,0,L|172:152,1,72,4|0,0:3|0:0,0:0:0:0:
+80,136,192951,2,0,L|101:204,1,72,2|0,1:2|0:0,0:0:0:0:
+12,220,193420,6,0,B|50:279|50:279|80:300|120:292,1,144,4|2,0:3|1:2,0:0:0:0:
+284,232,194357,2,0,B|320:221|352:244|352:244|384:267|420:256,1,144,4|2,0:3|1:2,0:0:0:0:
+488,200,195060,1,0,0:0:0:0:
+507,284,195295,6,0,P|492:315|464:338,1,72,4|0,0:0|0:0,0:0:0:0:
+380,356,195763,2,0,L|236:352,1,144,0|4,1:0|0:3,0:0:0:0:
+152,328,196466,1,0,3:0:0:0:
+64,336,196701,2,0,P|29:325|4:300,1,72,0|0,1:0|0:0,0:0:0:0:
+76,252,197170,6,0,P|108:188|96:116,1,144,4|0,0:0|1:0,0:0:0:0:
+36,56,197873,1,2,0:0:0:0:
+120,32,198107,2,0,L|192:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+248,152,199045,6,0,P|280:168|304:196,1,72,4|2,0:3|0:0,0:0:0:0:
+336,277,199513,2,0,P|306:296|269:303,1,72,2|0,1:2|0:0,0:0:0:0:
+183,290,199982,2,0,P|180:254|193:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
+436,252,200920,6,0,P|404:188|416:116,1,144,4|0,0:3|1:0,0:0:0:0:
+476,56,201623,1,2,0:0:0:0:
+392,32,201857,2,0,L|320:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0:
+264,152,202795,6,0,P|232:168|208:196,1,72,4|2,0:3|0:0,0:0:0:0:
+176,277,203263,2,0,P|205:296|242:303,1,72,2|0,1:2|0:0,0:0:0:0:
+329,290,203732,2,0,P|331:254|318:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
+72,324,204670,6,0,B|60:272|60:272|76:180,1,144,4|0,0:0|1:0,0:0:0:0:
+92,96,205373,1,2,0:0:0:0:
+8,124,205607,2,0,P|5:88|14:53,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+168,192,206545,6,0,P|200:174|237:173,1,72,4|2,0:3|0:0,0:0:0:0:
+320,160,207013,2,0,P|318:196|301:229,1,72,2|0,1:2|0:0,0:0:0:0:
+272,307,207482,2,0,P|240:287|221:256,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
+440,324,208420,6,0,B|452:272|452:272|436:180,1,144,4|0,0:3|1:0,0:0:0:0:
+420,96,209123,1,2,0:0:0:0:
+504,124,209357,2,0,P|507:88|498:53,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0:
+344,192,210295,6,0,P|311:174|274:173,1,72,4|2,0:3|0:0,0:0:0:0:
+190,156,210763,2,0,P|191:192|208:225,1,72,2|0,1:2|0:0,0:0:0:0:
+288,256,211232,1,4,0:3:0:0:
+132,332,211701,1,0,1:0:0:0:
+28,192,212170,6,0,P|16:120|44:56,1,144,4|0,0:0|1:0,0:0:0:0:
+120,16,212873,1,2,0:0:0:0:
+204,32,213107,2,0,L|304:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+192,204,214045,6,0,P|196:240|216:272,1,72,4|2,0:3|0:0,0:0:0:0:
+298,241,214513,2,0,P|327:219|345:186,1,72,6|0,1:2|0:0,0:0:0:0:
+280,132,214982,2,0,P|246:117|209:118,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0:
+484,192,215920,6,0,P|496:120|468:56,1,144,4|0,0:3|1:0,0:0:0:0:
+392,16,216623,1,2,0:0:0:0:
+308,32,216857,2,0,L|208:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0:
+320,204,217795,6,0,P|316:240|296:272,1,72,4|2,0:3|0:0,0:0:0:0:
+213,241,218263,2,0,P|184:219|166:186,1,72,2|0,1:2|0:0,0:0:0:0:
+232,132,218732,2,0,B|260:112|300:116|300:116|384:128,1,144,4|0,0:3|1:0,0:0:0:0:
+348,336,219670,6,0,B|320:356|280:352|280:352|196:340,1,144,4|0,0:0|1:0,0:0:0:0:
+124,328,220373,1,2,0:0:0:0:
+54,276,220607,2,0,P|41:308|39:345,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0:
+156,80,221545,6,0,L|251:94,1,72,4|2,0:3|0:0,0:0:0:0:
+212,169,222013,2,0,L|148:160,1,64.799998022461,2|0,1:2|0:0,0:0:0:0:
+140,240,222482,2,0,L|216:252,2,57.6,4|2|0,0:3|0:0|1:0,0:0:0:0:
+256,192,223420,12,0,227170,0:0:0:0:
+";
}
}
diff --git a/osu.Desktop.Tests/Visual/TestCaseReplay.cs b/osu.Desktop.Tests/Visual/TestCaseReplay.cs
index 9b2f59e444..50aefb7af7 100644
--- a/osu.Desktop.Tests/Visual/TestCaseReplay.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseReplay.cs
@@ -2,9 +2,9 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Rulesets;
using osu.Game.Screens.Play;
+using System.Linq;
namespace osu.Desktop.Tests.Visual
{
@@ -12,11 +12,10 @@ namespace osu.Desktop.Tests.Visual
{
public override string Description => @"Testing replay playback.";
- protected override Player CreatePlayer(WorkingBeatmap beatmap)
+ protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
{
- beatmap.Mods.Value = new Mod[] { new OsuModAutoplay() };
-
- return base.CreatePlayer(beatmap);
+ beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
+ return base.CreatePlayer(beatmap, ruleset);
}
}
}
diff --git a/osu.Desktop.Tests/Visual/TestCaseScrollingPlayfield.cs b/osu.Desktop.Tests/Visual/TestCaseScrollingPlayfield.cs
index 444adf6c24..fc8f70b7ce 100644
--- a/osu.Desktop.Tests/Visual/TestCaseScrollingPlayfield.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseScrollingPlayfield.cs
@@ -72,7 +72,7 @@ namespace osu.Desktop.Tests.Visual
[Test]
public void TestSpeedAdjustmentOrdering()
{
- var hitObjectContainer = new ScrollingPlayfield.ScrollingHitObjectContainer(Axes.X);
+ var hitObjectContainer = new ScrollingPlayfield.ScrollingHitObjectContainer(Axes.X);
var speedAdjustments = new[]
{
@@ -129,7 +129,7 @@ namespace osu.Desktop.Tests.Visual
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
}
- private class TestRulesetContainer : ScrollingRulesetContainer
+ private class TestRulesetContainer : ScrollingRulesetContainer
{
private readonly Axes scrollingAxes;
@@ -147,14 +147,14 @@ namespace osu.Desktop.Tests.Visual
protected override BeatmapConverter CreateBeatmapConverter() => new TestBeatmapConverter();
- protected override Playfield CreatePlayfield() => new TestPlayfield(scrollingAxes);
+ protected override Playfield CreatePlayfield() => new TestPlayfield(scrollingAxes);
- protected override DrawableHitObject GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h);
+ protected override DrawableHitObject GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h);
}
- private class TestScoreProcessor : ScoreProcessor
+ private class TestScoreProcessor : ScoreProcessor
{
- protected override void OnNewJudgement(TestJudgement judgement)
+ protected override void OnNewJudgement(Judgement judgement)
{
}
}
@@ -169,7 +169,7 @@ namespace osu.Desktop.Tests.Visual
}
}
- private class DrawableTestHitObject : DrawableScrollingHitObject
+ private class DrawableTestHitObject : DrawableScrollingHitObject
{
public DrawableTestHitObject(Axes scrollingAxes, TestHitObject hitObject)
: base(hitObject)
@@ -185,14 +185,12 @@ namespace osu.Desktop.Tests.Visual
});
}
- protected override TestJudgement CreateJudgement() => new TestJudgement();
-
protected override void UpdateState(ArmedState state)
{
}
}
- private class TestPlayfield : ScrollingPlayfield
+ private class TestPlayfield : ScrollingPlayfield
{
protected override Container Content => content;
private readonly Container content;
@@ -218,11 +216,5 @@ namespace osu.Desktop.Tests.Visual
private class TestHitObject : HitObject
{
}
-
- private class TestJudgement : Judgement
- {
- public override string ResultString { get { throw new NotImplementedException(); } }
- public override string MaxResultString { get { throw new NotImplementedException(); } }
- }
}
}
diff --git a/osu.Desktop.Tests/Visual/TestCaseTaikoPlayfield.cs b/osu.Desktop.Tests/Visual/TestCaseTaikoPlayfield.cs
index 681805ced0..764cf7a1f8 100644
--- a/osu.Desktop.Tests/Visual/TestCaseTaikoPlayfield.cs
+++ b/osu.Desktop.Tests/Visual/TestCaseTaikoPlayfield.cs
@@ -128,7 +128,7 @@ namespace osu.Desktop.Tests.Visual
private void addHitJudgement(bool kiai)
{
- TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great;
+ HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
var cpi = new ControlPointInfo();
cpi.EffectPoints.Add(new EffectControlPoint
@@ -139,36 +139,20 @@ namespace osu.Desktop.Tests.Visual
Hit hit = new Hit();
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
- var h = new DrawableTestHit(hit)
- {
- X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f),
- Judgement = new TaikoJudgement
- {
- Result = HitResult.Hit,
- TaikoResult = hitResult,
- TimeOffset = 0
- }
- };
+ var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
- rulesetContainer.Playfield.OnJudgement(h);
+ rulesetContainer.Playfield.OnJudgement(h, new TaikoJudgement { Result = hitResult });
if (RNG.Next(10) == 0)
{
- h.Judgement.SecondHit = true;
- rulesetContainer.Playfield.OnJudgement(h);
+ rulesetContainer.Playfield.OnJudgement(h, new TaikoJudgement { Result = hitResult });
+ rulesetContainer.Playfield.OnJudgement(h, new TaikoStrongHitJudgement());
}
}
private void addMissJudgement()
{
- rulesetContainer.Playfield.OnJudgement(new DrawableTestHit(new Hit())
- {
- Judgement = new TaikoJudgement
- {
- Result = HitResult.Miss,
- TimeOffset = 0
- }
- });
+ rulesetContainer.Playfield.OnJudgement(new DrawableTestHit(new Hit()), new TaikoJudgement { Result = HitResult.Miss });
}
private void addBarLine(bool major, double delay = scroll_time)
@@ -230,15 +214,13 @@ namespace osu.Desktop.Tests.Visual
rulesetContainer.Playfield.Add(new DrawableRimHit(h));
}
- private class DrawableTestHit : DrawableHitObject
+ private class DrawableTestHit : DrawableHitObject
{
public DrawableTestHit(TaikoHitObject hitObject)
: base(hitObject)
{
}
- protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
-
protected override void UpdateState(ArmedState state)
{
}
diff --git a/osu.Desktop.Tests/osu.Desktop.Tests.csproj b/osu.Desktop.Tests/osu.Desktop.Tests.csproj
index aaa905b5e3..1c02e243a3 100644
--- a/osu.Desktop.Tests/osu.Desktop.Tests.csproj
+++ b/osu.Desktop.Tests/osu.Desktop.Tests.csproj
@@ -9,7 +9,7 @@
Properties
osu.Desktop.Tests
osu.Desktop.Tests
- v4.5
+ v4.6.1
512
@@ -87,6 +87,7 @@
+
diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
index 8bba59207f..33019909c6 100644
--- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
+++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
@@ -22,7 +22,7 @@
OnOutputUpdated
false
LocalIntranet
- v4.5
+ v4.6.1
true
publish\
true
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index bbca4145c6..661c17699b 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -22,7 +22,7 @@
OnOutputUpdated
false
LocalIntranet
- v4.5
+ v4.6.1
true
publish\
true
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index 96f8a8df9b..214cbc7f50 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -93,8 +93,6 @@ namespace osu.Game.Rulesets.Catch
}
}
- public override Mod GetAutoplayMod() => new ModAutoplay();
-
public override string Description => "osu!catch";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
index f0125b4c3a..cc5b1eaaf4 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
@@ -7,8 +7,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchJudgement : Judgement
{
- public override string ResultString => string.Empty;
-
- public override string MaxResultString => string.Empty;
+ // todo: wangs
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index 62e5c094be..3dd086fb48 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -9,14 +9,14 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
-using osu.Game.Rulesets.Catch.Judgements;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
- public class DrawableFruit : DrawableScrollingHitObject
+ public class DrawableFruit : DrawableScrollingHitObject
{
private const float pulp_size = 30;
@@ -98,14 +98,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
};
}
- protected override CatchJudgement CreateJudgement() => new CatchJudgement();
-
private const float preempt = 1000;
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
- if (Judgement.TimeOffset > 0)
- Judgement.Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Hit : HitResult.Miss;
+ if (timeOffset > 0)
+ AddJudgement(new Judgement { Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Perfect : HitResult.Miss });
}
protected override void UpdateState(ArmedState state)
diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
index 33c1355823..2637a98fe2 100644
--- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
@@ -1,20 +1,20 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch.Scoring
{
- internal class CatchScoreProcessor : ScoreProcessor
+ internal class CatchScoreProcessor : ScoreProcessor
{
public CatchScoreProcessor()
{
}
- public CatchScoreProcessor(RulesetContainer rulesetContainer)
+ public CatchScoreProcessor(RulesetContainer rulesetContainer)
: base(rulesetContainer)
{
}
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Scoring
Accuracy.Value = 1;
}
- protected override void OnNewJudgement(CatchJudgement judgement)
+ protected override void OnNewJudgement(Judgement judgement)
{
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 4ea6d180f3..0dac3ec41c 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -2,17 +2,16 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
-using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.UI;
using OpenTK;
-using osu.Game.Rulesets.Catch.Judgements;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Catch.UI
{
- public class CatchPlayfield : ScrollingPlayfield
+ public class CatchPlayfield : ScrollingPlayfield
{
protected override Container Content => content;
private readonly Container content;
@@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.UI
};
}
- public override void Add(DrawableHitObject h)
+ public override void Add(DrawableHitObject h)
{
base.Add(h);
@@ -53,13 +52,13 @@ namespace osu.Game.Rulesets.Catch.UI
fruit.OnJudgement += Fruit_OnJudgement;
}
- private void Fruit_OnJudgement(DrawableHitObject obj)
+ private void Fruit_OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
- if (obj.Judgement.Result == HitResult.Hit)
+ if (judgement.IsHit)
{
- Vector2 screenPosition = obj.ScreenSpaceDrawQuad.Centre;
- Remove(obj);
- catcherArea.Add(obj, screenPosition);
+ Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre;
+ Remove(judgedObject);
+ catcherArea.Add(judgedObject, screenPosition);
}
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
index f8f74af6c9..8f332bdcbf 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
@@ -5,7 +5,6 @@ using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
-using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Scoring;
@@ -15,7 +14,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch.UI
{
- public class CatchRulesetContainer : ScrollingRulesetContainer
+ public class CatchRulesetContainer : ScrollingRulesetContainer
{
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(ruleset, beatmap, isForCurrentRuleset)
@@ -26,11 +25,11 @@ namespace osu.Game.Rulesets.Catch.UI
protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter();
- protected override Playfield CreatePlayfield() => new CatchPlayfield();
+ protected override Playfield CreatePlayfield() => new CatchPlayfield();
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
- protected override DrawableHitObject GetVisualRepresentation(CatchBaseHit h)
+ protected override DrawableHitObject GetVisualRepresentation(CatchBaseHit h)
{
if (h is Fruit)
return new DrawableFruit(h);
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index f416f6acfb..64dbe04ba4 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
-using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Objects.Drawables;
@@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
private Catcher catcher;
- public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
+ public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.Position) < catcher.DrawSize.X / DrawSize.X / 2;
@@ -85,7 +84,7 @@ namespace osu.Game.Rulesets.Catch.UI
var additive = createCatcherSprite();
additive.RelativePositionAxes = Axes.Both;
- additive.BlendingMode = BlendingMode.Additive;
+ additive.Blending = BlendingMode.Additive;
additive.Position = Position;
additive.Scale = Scale;
@@ -152,7 +151,7 @@ namespace osu.Game.Rulesets.Catch.UI
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime / 1800 * speed, 0, 1);
}
- public void AddToStack(DrawableHitObject fruit, Vector2 absolutePosition)
+ public void AddToStack(DrawableHitObject fruit, Vector2 absolutePosition)
{
fruit.RelativePositionAxes = Axes.None;
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
@@ -161,7 +160,6 @@ namespace osu.Game.Rulesets.Catch.UI
fruit.Origin = Anchor.BottomCentre;
fruit.Scale *= 0.7f;
fruit.LifetimeEnd = double.MaxValue;
- fruit.Depth = (float)Time.Current;
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
index 79ef5f4ba8..2ae2262ac7 100644
--- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
+++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
@@ -9,7 +9,7 @@
Properties
osu.Game.Rulesets.Catch
osu.Game.Rulesets.Catch
- v4.5
+ v4.6.1
512
diff --git a/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs b/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs
index 52b55a4ff5..d7bfa9caa1 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HitWindows.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Judgements
{
@@ -145,18 +146,18 @@ namespace osu.Game.Rulesets.Mania.Judgements
///
/// The time offset.
/// The hit result, or null if the time offset results in a miss.
- public ManiaHitResult? ResultFor(double hitOffset)
+ public HitResult? ResultFor(double hitOffset)
{
if (hitOffset <= Perfect / 2)
- return ManiaHitResult.Perfect;
+ return HitResult.Perfect;
if (hitOffset <= Great / 2)
- return ManiaHitResult.Great;
+ return HitResult.Great;
if (hitOffset <= Good / 2)
- return ManiaHitResult.Good;
+ return HitResult.Good;
if (hitOffset <= Ok / 2)
- return ManiaHitResult.Ok;
+ return HitResult.Ok;
if (hitOffset <= Bad / 2)
- return ManiaHitResult.Bad;
+ return HitResult.Meh;
return null;
}
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
index d5cf57a5da..cc7aa63f7e 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTailJudgement.cs
@@ -1,6 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using osu.Game.Rulesets.Objects.Drawables;
+
namespace osu.Game.Rulesets.Mania.Judgements
{
public class HoldNoteTailJudgement : ManiaJudgement
@@ -10,27 +12,27 @@ namespace osu.Game.Rulesets.Mania.Judgements
///
public bool HasBroken;
- public override int NumericResultForScore(ManiaHitResult result)
+ protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
- return base.NumericResultForScore(result);
- case ManiaHitResult.Great:
- case ManiaHitResult.Perfect:
- return base.NumericResultForScore(HasBroken ? ManiaHitResult.Good : result);
+ return base.NumericResultFor(result);
+ case HitResult.Great:
+ case HitResult.Perfect:
+ return base.NumericResultFor(HasBroken ? HitResult.Good : result);
}
}
- public override int NumericResultForAccuracy(ManiaHitResult result)
+ protected override int NumericResultForAccuracy(HitResult result)
{
switch (result)
{
default:
return base.NumericResultForAccuracy(result);
- case ManiaHitResult.Great:
- case ManiaHitResult.Perfect:
- return base.NumericResultForAccuracy(HasBroken ? ManiaHitResult.Good : result);
+ case HitResult.Great:
+ case HitResult.Perfect:
+ return base.NumericResultForAccuracy(HasBroken ? HitResult.Good : result);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
index 852f97b3f2..c00572edff 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
@@ -1,13 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using osu.Game.Rulesets.Objects.Drawables;
+
namespace osu.Game.Rulesets.Mania.Judgements
{
public class HoldNoteTickJudgement : ManiaJudgement
{
public override bool AffectsCombo => false;
- public override int NumericResultForScore(ManiaHitResult result) => 20;
- public override int NumericResultForAccuracy(ManiaHitResult result) => 0; // Don't count ticks into accuracy
+ protected override int NumericResultFor(HitResult result) => 20;
+ protected override int NumericResultForAccuracy(HitResult result) => 0; // Don't count ticks into accuracy
}
}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs
deleted file mode 100644
index 207a1fb251..0000000000
--- a/osu.Game.Rulesets.Mania/Judgements/ManiaHitResult.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.Rulesets.Mania.Judgements
-{
- public enum ManiaHitResult
- {
- [Description("PERFECT")]
- Perfect,
- [Description("GREAT")]
- Great,
- [Description("GOOD")]
- Good,
- [Description("OK")]
- Ok,
- [Description("BAD")]
- Bad
- }
-}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
index 33083ca0f5..e36146aa71 100644
--- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
@@ -8,73 +8,49 @@ namespace osu.Game.Rulesets.Mania.Judgements
{
public class ManiaJudgement : Judgement
{
- ///
- /// The maximum possible hit result.
- ///
- public const ManiaHitResult MAX_HIT_RESULT = ManiaHitResult.Perfect;
-
- ///
- /// The result value for the combo portion of the score.
- ///
- public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(ManiaResult);
-
- ///
- /// The result value for the accuracy portion of the score.
- ///
- public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(ManiaResult);
-
- ///
- /// The maximum result value for the combo portion of the score.
- ///
- public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
-
///
/// The maximum result value for the accuracy portion of the score.
///
- public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
+ public int MaxNumericAccuracyResult => NumericResultForAccuracy(HitResult.Perfect);
- public override string ResultString => string.Empty;
-
- public override string MaxResultString => string.Empty;
-
- ///
- /// The hit result.
- ///
- public ManiaHitResult ManiaResult;
-
- public virtual int NumericResultForScore(ManiaHitResult result)
+ protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
- case ManiaHitResult.Bad:
+ case HitResult.Meh:
return 50;
- case ManiaHitResult.Ok:
+ case HitResult.Ok:
return 100;
- case ManiaHitResult.Good:
+ case HitResult.Good:
return 200;
- case ManiaHitResult.Great:
- case ManiaHitResult.Perfect:
+ case HitResult.Great:
+ case HitResult.Perfect:
return 300;
}
}
- public virtual int NumericResultForAccuracy(ManiaHitResult result)
+ public int NumericAccuracyResult => NumericResultForAccuracy(Result);
+
+ ///
+ /// The result value for the accuracy portion of the score.
+ ///
+ protected virtual int NumericResultForAccuracy(HitResult result)
{
switch (result)
{
default:
return 0;
- case ManiaHitResult.Bad:
+ case HitResult.Meh:
return 50;
- case ManiaHitResult.Ok:
+ case HitResult.Ok:
return 100;
- case ManiaHitResult.Good:
+ case HitResult.Good:
return 200;
- case ManiaHitResult.Great:
+ case HitResult.Great:
return 300;
- case ManiaHitResult.Perfect:
+ case HitResult.Perfect:
return 305;
}
}
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index ed46da4f85..0011d2837f 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Mania
{
Mods = new Mod[]
{
- new ModAutoplay(),
+ new ManiaModAutoplay(),
new ModCinema(),
},
},
@@ -105,8 +105,6 @@ namespace osu.Game.Rulesets.Mania
}
}
- public override Mod GetAutoplayMod() => new ModAutoplay();
-
public override string Description => "osu!mania";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs
index f44ad6fd60..60415632a8 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs
@@ -4,6 +4,13 @@
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using System;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.Replays;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Users;
+using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -68,6 +75,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModFadeIn : Mod
{
public override string Name => "FadeIn";
+ public override string ShortenedName => "FI";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease;
public override double ScoreMultiplier => 1;
@@ -78,12 +86,14 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModRandom : Mod
{
public override string Name => "Random";
+ public override string ShortenedName => "RD";
public override string Description => @"Shuffle around the notes!";
public override double ScoreMultiplier => 1;
}
public abstract class ManiaKeyMod : Mod
{
+ public override string ShortenedName => Name;
public abstract int KeyCount { get; }
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
public override bool Ranked => true;
@@ -146,8 +156,29 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModKeyCoop : Mod
{
public override string Name => "KeyCoop";
+ public override string ShortenedName => "2P";
public override string Description => @"Double the key amount, double the fun!";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
}
+
+ public class ManiaModAutoplay : ModAutoplay
+ {
+ private int availableColumns;
+
+ public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ {
+ // Todo: This shouldn't be done, we should be getting a ManiaBeatmap which should store AvailableColumns
+ // But this is dependent on a _lot_ of refactoring
+ var maniaRulesetContainer = (ManiaRulesetContainer)rulesetContainer;
+ availableColumns = maniaRulesetContainer.AvailableColumns;
+
+ base.ApplyToRulesetContainer(rulesetContainer);
+ }
+ protected override Score CreateReplayScore(Beatmap beatmap) => new Score
+ {
+ User = new User { Username = "osu!topus!" },
+ Replay = new ManiaAutoGenerator(beatmap, availableColumns).Generate(),
+ };
+ }
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
index a054e0db56..70270af6c9 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
@@ -15,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModGravity : Mod, IGenerateSpeedAdjustments
{
public override string Name => "Gravity";
+ public override string ShortenedName => "GR";
public override double ScoreMultiplier => 0;
@@ -23,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public void ApplyToRulesetContainer(ManiaRulesetContainer rulesetContainer, ref List[] hitObjectTimingChanges, ref List barlineTimingChanges)
{
// We have to generate one speed adjustment per hit object for gravity
- foreach (ManiaHitObject obj in rulesetContainer.Objects)
+ foreach (ManiaHitObject obj in rulesetContainer.Objects.OfType())
{
MultiplierControlPoint controlPoint = rulesetContainer.CreateControlPointAt(obj.StartTime);
// Beat length has too large of an effect for gravity, so we'll force it to a constant value for now
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index e06f71cb64..237df72480 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -1,6 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
+using System.Linq;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
@@ -21,8 +23,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly DrawableNote head;
private readonly DrawableNote tail;
+ private readonly GlowPiece glowPiece;
private readonly BodyPiece bodyPiece;
private readonly Container tickContainer;
+ private readonly Container fullHeightContainer;
///
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
@@ -42,13 +46,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddRange(new Drawable[]
{
- // For now the body piece covers the entire height of the container
- // whereas possibly in the future we don't want to extend under the head/tail.
- // This will be fixed when new designs are given or the current design is finalized.
+ // The hit object itself cannot be used for various elements because the tail overshoots it
+ // So a specialized container that is updated to contain the tail height is used
+ fullHeightContainer = new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Child = glowPiece = new GlowPiece()
+ },
bodyPiece = new BodyPiece
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
+ RelativeSizeAxes = Axes.X,
},
tickContainer = new Container
{
@@ -94,6 +103,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
tickContainer.Children.ForEach(t => t.AccentColour = value);
+ glowPiece.AccentColour = value;
bodyPiece.AccentColour = value;
head.AccentColour = value;
tail.AccentColour = value;
@@ -104,6 +114,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
}
+ protected override void Update()
+ {
+ base.Update();
+
+ // Make the body piece not lie under the head note
+ bodyPiece.Y = head.Height;
+ bodyPiece.Height = DrawHeight - head.Height;
+
+ // Make the fullHeightContainer "contain" the height of the tail note, keeping in mind
+ // that the tail note overshoots the height of this hit object
+ fullHeightContainer.Height = DrawHeight + tail.Height;
+ }
+
public bool OnPressed(ManiaAction action)
{
// Make sure the action happened within the body of the hold note
@@ -133,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
holdStartTime = null;
// If the key has been released too early, the user should not receive full score for the release
- if (!tail.Judged)
+ if (!tail.AllJudged)
hasBroken = true;
return true;
@@ -153,6 +176,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativePositionAxes = Axes.None;
Y = 0;
+
+ // Life time managed by the parent DrawableHoldNote
+ LifetimeStart = double.MinValue;
+ LifetimeEnd = double.MaxValue;
+
+ GlowPiece.Alpha = 0;
}
public override bool OnPressed(ManiaAction action)
@@ -160,12 +189,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (!base.OnPressed(action))
return false;
- // We only want to trigger a holding state from the head if the head has received a judgement
- if (!Judged)
- return false;
-
// If the key has been released too early, the user should not receive full score for the release
- if (Judgement.Result == HitResult.Miss)
+ if (Judgements.Any(j => j.Result == HitResult.Miss))
holdNote.hasBroken = true;
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
@@ -190,19 +215,40 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativePositionAxes = Axes.None;
Y = 0;
+
+ // Life time managed by the parent DrawableHoldNote
+ LifetimeStart = double.MinValue;
+ LifetimeEnd = double.MaxValue;
+
+ GlowPiece.Alpha = 0;
}
- protected override ManiaJudgement CreateJudgement() => new HoldNoteTailJudgement();
-
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
- base.CheckJudgement(userTriggered);
+ if (!userTriggered)
+ {
+ if (timeOffset > HitObject.HitWindows.Bad / 2)
+ {
+ AddJudgement(new HoldNoteTailJudgement
+ {
+ Result = HitResult.Miss,
+ HasBroken = holdNote.hasBroken
+ });
+ }
- var tailJudgement = Judgement as HoldNoteTailJudgement;
- if (tailJudgement == null)
+ return;
+ }
+
+ double offset = Math.Abs(timeOffset);
+
+ if (offset > HitObject.HitWindows.Miss / 2)
return;
- tailJudgement.HasBroken = holdNote.hasBroken;
+ AddJudgement(new HoldNoteTailJudgement
+ {
+ Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss,
+ HasBroken = holdNote.hasBroken
+ });
}
public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down
@@ -213,9 +259,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (!holdNote.holdStartTime.HasValue)
return false;
- if (Judgement.Result != HitResult.None)
- return false;
-
if (action != Action)
return false;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
index 39abbb6b3d..49bca6d1d7 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
@@ -23,11 +23,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
///
public Func HoldStartTime;
- ///
- /// References whether the user is currently holding the hold note.
- ///
- public Func IsHolding;
-
private readonly Container glowContainer;
public DrawableHoldNoteTick(HoldNoteTick hitObject)
@@ -36,9 +31,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
+ Y = (float)HitObject.StartTime;
+
RelativeSizeAxes = Axes.X;
Size = new Vector2(1);
+ // Life time managed by the parent DrawableHoldNote
+ LifetimeStart = double.MinValue;
+ LifetimeEnd = double.MaxValue;
+
Children = new[]
{
glowContainer = new CircularContainer
@@ -58,9 +59,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}
}
};
-
- // Set the default glow
- AccentColour = Color4.White;
}
public override Color4 AccentColour
@@ -80,9 +78,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}
}
- protected override ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement();
+ protected ManiaJudgement CreateJudgement() => new HoldNoteTickJudgement();
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered)
return;
@@ -93,8 +91,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (HoldStartTime?.Invoke() > HitObject.StartTime)
return;
- Judgement.ManiaResult = ManiaHitResult.Perfect;
- Judgement.Result = HitResult.Hit;
+ AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
}
protected override void UpdateState(ArmedState state)
@@ -109,10 +106,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected override void Update()
{
- if (Judgement.Result != HitResult.None)
+ if (AllJudged)
return;
- if (IsHolding?.Invoke() != true)
+ if (HoldStartTime?.Invoke() == null)
return;
UpdateJudgement(true);
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
index bfef05ea07..6354c6ff77 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
@@ -1,13 +1,13 @@
// 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 OpenTK.Graphics;
-using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
- public abstract class DrawableManiaHitObject : DrawableScrollingHitObject
+ public abstract class DrawableManiaHitObject : DrawableScrollingHitObject
where TObject : ManiaHitObject
{
///
@@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null)
: base(hitObject)
{
+ RelativePositionAxes = Axes.Y;
HitObject = hitObject;
if (action != null)
@@ -36,7 +37,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.AccentColour = value;
}
}
-
- protected override ManiaJudgement CreateJudgement() => new ManiaJudgement();
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
index c201ab7bd0..537246509b 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
@@ -16,19 +16,31 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
///
public class DrawableNote : DrawableManiaHitObject, IKeyBindingHandler
{
+ protected readonly GlowPiece GlowPiece;
+
+ private readonly LaneGlowPiece laneGlowPiece;
private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, ManiaAction action)
: base(hitObject, action)
{
RelativeSizeAxes = Axes.X;
- Height = 100;
+ AutoSizeAxes = Axes.Y;
- Add(headPiece = new NotePiece
+ Children = new Drawable[]
{
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre
- });
+ laneGlowPiece = new LaneGlowPiece
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre
+ },
+ GlowPiece = new GlowPiece(),
+ headPiece = new NotePiece
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre
+ }
+ };
}
public override Color4 AccentColour
@@ -40,43 +52,31 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return;
base.AccentColour = value;
+ laneGlowPiece.AccentColour = value;
+ GlowPiece.AccentColour = value;
headPiece.AccentColour = value;
}
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered)
{
- if (Judgement.TimeOffset > HitObject.HitWindows.Bad / 2)
- Judgement.Result = HitResult.Miss;
+ if (timeOffset > HitObject.HitWindows.Bad / 2)
+ AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
return;
}
- double offset = Math.Abs(Judgement.TimeOffset);
+ double offset = Math.Abs(timeOffset);
if (offset > HitObject.HitWindows.Miss / 2)
return;
- ManiaHitResult? tmpResult = HitObject.HitWindows.ResultFor(offset);
-
- if (tmpResult.HasValue)
- {
- Judgement.Result = HitResult.Hit;
- Judgement.ManiaResult = tmpResult.Value;
- }
- else
- Judgement.Result = HitResult.Miss;
+ AddJudgement(new ManiaJudgement { Result = HitObject.HitWindows.ResultFor(offset) ?? HitResult.Miss });
}
protected override void UpdateState(ArmedState state)
{
- switch (State)
- {
- case ArmedState.Hit:
- Colour = Color4.Green;
- break;
- }
}
public virtual bool OnPressed(ManiaAction action)
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
index 04e8df4ae2..fe40532e42 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
@@ -1,7 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
+using osu.Framework.Caching;
using OpenTK.Graphics;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -14,22 +17,61 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
///
internal class BodyPiece : Container, IHasAccentColour
{
- private readonly Box box;
+ private readonly Container subtractionLayer;
+
+ private readonly Drawable background;
+ private readonly BufferedContainer foreground;
+ private readonly BufferedContainer subtractionContainer;
public BodyPiece()
{
- RelativeSizeAxes = Axes.Both;
+ Blending = BlendingMode.Additive;
Children = new[]
{
- box = new Box
+ background = new Box { RelativeSizeAxes = Axes.Both },
+ foreground = new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
- Alpha = 0.3f
+ CacheDrawnFrameBuffer = true,
+ Children = new Drawable[]
+ {
+ new Box { RelativeSizeAxes = Axes.Both },
+ subtractionContainer = new BufferedContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ // This is needed because we're blending with another object
+ BackgroundColour = Color4.White.Opacity(0),
+ CacheDrawnFrameBuffer = true,
+ // The 'hole' is achieved by subtracting the result of this container with the parent
+ Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract },
+ Child = subtractionLayer = new CircularContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ // Height computed in Update
+ Width = 1,
+ Masking = true,
+ Child = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ AlwaysPresent = true
+ }
+ }
+ }
+ }
}
};
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ updateAccentColour();
+ }
+
private Color4 accentColour;
public Color4 AccentColour
{
@@ -40,8 +82,51 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
return;
accentColour = value;
- box.Colour = accentColour;
+ updateAccentColour();
}
}
+
+ private Cached subtractionCache = new Cached();
+
+ public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
+ {
+ if ((invalidation & Invalidation.DrawSize) > 0)
+ subtractionCache.Invalidate();
+
+ return base.Invalidate(invalidation, source, shallPropagate);
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (!subtractionCache.IsValid)
+ {
+ subtractionLayer.Width = 5;
+ subtractionLayer.Height = Math.Max(0, DrawHeight - DrawWidth);
+ subtractionLayer.EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.White,
+ Type = EdgeEffectType.Glow,
+ Radius = DrawWidth
+ };
+
+ foreground.ForceRedraw();
+ subtractionContainer.ForceRedraw();
+
+ subtractionCache.Validate();
+ }
+ }
+
+ private void updateAccentColour()
+ {
+ if (!IsLoaded)
+ return;
+
+ foreground.Colour = AccentColour.Opacity(0.4f);
+ background.Colour = AccentColour.Opacity(0.2f);
+
+ subtractionCache.Invalidate();
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
new file mode 100644
index 0000000000..6f022f452f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
@@ -0,0 +1,65 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using OpenTK.Graphics;
+
+namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
+{
+ public class GlowPiece : CompositeDrawable, IHasAccentColour
+ {
+ private const float glow_alpha = 0.7f;
+ private const float glow_radius = 5;
+
+ public GlowPiece()
+ {
+ RelativeSizeAxes = Axes.Both;
+ Masking = true;
+
+ InternalChild = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ AlwaysPresent = true
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ updateGlow();
+ }
+
+ private Color4 accentColour;
+ public Color4 AccentColour
+ {
+ get { return accentColour; }
+ set
+ {
+ if (accentColour == value)
+ return;
+ accentColour = value;
+
+ updateGlow();
+ }
+ }
+
+ private void updateGlow()
+ {
+ if (!IsLoaded)
+ return;
+
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = AccentColour.Opacity(glow_alpha),
+ Radius = glow_radius,
+ Hollow = true
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
new file mode 100644
index 0000000000..6d4ac2fb61
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
@@ -0,0 +1,85 @@
+// 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.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+
+namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
+{
+ public class LaneGlowPiece : CompositeDrawable, IHasAccentColour
+ {
+ private const float total_height = 100;
+ private const float glow_height = 50;
+ private const float glow_alpha = 0.4f;
+ private const float edge_alpha = 0.3f;
+
+ public LaneGlowPiece()
+ {
+ BypassAutoSizeAxes = Axes.Both;
+ RelativeSizeAxes = Axes.X;
+ Height = total_height;
+
+ InternalChildren = new[]
+ {
+ new Container
+ {
+ Name = "Left edge",
+ RelativeSizeAxes = Axes.Y,
+ Width = 1,
+ Children = createGradient(edge_alpha)
+ },
+ new Container
+ {
+ Name = "Right edge",
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ RelativeSizeAxes = Axes.Y,
+ Width = 1,
+ Children = createGradient(edge_alpha)
+ },
+ new Container
+ {
+ Name = "Glow",
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ Height = glow_height,
+ Children = createGradient(glow_alpha)
+ }
+ };
+ }
+
+ private Drawable[] createGradient(float alpha) => new Drawable[]
+ {
+ new Box
+ {
+ Name = "Top",
+ RelativeSizeAxes = Axes.Both,
+ Height = 0.5f,
+ Blending = BlendingMode.Additive,
+ Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha))
+ },
+ new Box
+ {
+ Name = "Bottom",
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ RelativeSizeAxes = Axes.Both,
+ Height = 0.5f,
+ Blending = BlendingMode.Additive,
+ Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent)
+ }
+ };
+
+ public Color4 AccentColour
+ {
+ get { return Colour; }
+ set { Colour = value; }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index c3a29b39a8..fc1331551e 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -37,6 +37,17 @@ namespace osu.Game.Rulesets.Mania.Objects
}
}
+ public override int Column
+ {
+ get { return base.Column; }
+ set
+ {
+ base.Column = value;
+ Head.Column = value;
+ Tail.Column = value;
+ }
+ }
+
///
/// The head note of the hold.
///
@@ -80,7 +91,8 @@ namespace osu.Game.Rulesets.Mania.Objects
{
ret.Add(new HoldNoteTick
{
- StartTime = t
+ StartTime = t,
+ Column = Column
});
}
diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs
index 93aaa94f45..7beb21f9e3 100644
--- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs
@@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Mania.Objects
{
public abstract class ManiaHitObject : HitObject, IHasColumn
{
- public int Column { get; set; }
+ public virtual int Column { get; set; }
}
}
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs
new file mode 100644
index 0000000000..64982532a7
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs
@@ -0,0 +1,133 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Users;
+
+namespace osu.Game.Rulesets.Mania.Replays
+{
+ internal class ManiaAutoGenerator : AutoGenerator
+ {
+ private const double release_delay = 20;
+
+ private readonly int availableColumns;
+
+ public ManiaAutoGenerator(Beatmap beatmap, int availableColumns)
+ : base(beatmap)
+ {
+ this.availableColumns = availableColumns;
+
+ Replay = new Replay { User = new User { Username = @"Autoplay" } };
+ }
+
+ protected Replay Replay;
+
+ public override Replay Generate()
+ {
+ // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
+ Replay.Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None));
+
+ double[] holdEndTimes = new double[availableColumns];
+ for (int i = 0; i < availableColumns; i++)
+ holdEndTimes[i] = double.NegativeInfinity;
+
+ // Notes are handled row-by-row
+ foreach (var objGroup in Beatmap.HitObjects.GroupBy(h => h.StartTime))
+ {
+ double groupTime = objGroup.Key;
+
+ int activeColumns = 0;
+
+ // Get the previously held-down active columns
+ for (int i = 0; i < availableColumns; i++)
+ {
+ if (holdEndTimes[i] > groupTime)
+ activeColumns |= 1 << i;
+ }
+
+ // Add on the group columns, keeping track of the held notes for the next rows
+ foreach (var obj in objGroup)
+ {
+ var holdNote = obj as HoldNote;
+ if (holdNote != null)
+ holdEndTimes[obj.Column] = Math.Max(holdEndTimes[obj.Column], holdNote.EndTime);
+
+ activeColumns |= 1 << obj.Column;
+ }
+
+ Replay.Frames.Add(new ReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None));
+
+ // Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated
+ foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key))
+ {
+ var groupEndTime = obj.Key;
+
+ int activeColumnsAtEnd = 0;
+ for (int i = 0; i < availableColumns; i++)
+ {
+ if (holdEndTimes[i] > groupEndTime)
+ activeColumnsAtEnd |= 1 << i;
+ }
+
+ Replay.Frames.Add(new ReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None));
+ }
+ }
+
+ Replay.Frames = Replay.Frames
+ // Pick the maximum activeColumns for all frames at the same time
+ .GroupBy(f => f.Time)
+ .Select(g => new ReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None))
+ // The addition of release frames above maybe result in unordered frames, but we need them ordered
+ .OrderBy(f => f.Time)
+ .ToList();
+
+ return Replay;
+ }
+
+ ///
+ /// Finds the maximum by count of bits from a grouping of s.
+ ///
+ /// The grouping to search.
+ /// The maximum by count of bits.
+ private float maxMouseX(IGrouping group)
+ {
+ int currentCount = -1;
+ int currentMax = 0;
+
+ foreach (var val in group)
+ {
+ int newCount = countBits((int)(val.MouseX ?? 0));
+ if (newCount > currentCount)
+ {
+ currentCount = newCount;
+ currentMax = (int)(val.MouseX ?? 0);
+ }
+ }
+
+ return currentMax;
+ }
+
+ ///
+ /// Counts the number of bits set in a value.
+ ///
+ /// The value to count.
+ /// The number of set bits.
+ private int countBits(int value)
+ {
+ int count = 0;
+ while (value > 0)
+ {
+ if ((value & 1) > 0)
+ count++;
+ value >>= 1;
+ }
+
+ return count;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
new file mode 100644
index 0000000000..e352997f2c
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
@@ -0,0 +1,35 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using osu.Framework.Input;
+using osu.Game.Rulesets.Replays;
+
+namespace osu.Game.Rulesets.Mania.Replays
+{
+ internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler
+ {
+ public ManiaFramedReplayInputHandler(Replay replay)
+ : base(replay)
+ {
+ }
+
+ public override List GetPendingStates()
+ {
+ var actions = new List();
+
+ int activeColumns = (int)(CurrentFrame.MouseX ?? 0);
+
+ int counter = 0;
+ while (activeColumns > 0)
+ {
+ if ((activeColumns & 1) > 0)
+ actions.Add(ManiaAction.Key1 + counter);
+ counter++;
+ activeColumns >>= 1;
+ }
+
+ return new List { new ReplayState { PressedActions = actions } };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs
index 63b443319f..946caf71cf 100644
--- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs
+++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs
@@ -4,6 +4,7 @@
using System;
using System.Linq;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@@ -12,7 +13,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Scoring
{
- internal class ManiaScoreProcessor : ScoreProcessor
+ internal class ManiaScoreProcessor : ScoreProcessor
{
///
/// The maximum score achievable.
@@ -155,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
{
}
- public ManiaScoreProcessor(RulesetContainer rulesetContainer)
+ public ManiaScoreProcessor(RulesetContainer rulesetContainer)
: base(rulesetContainer)
{
}
@@ -174,37 +175,19 @@ namespace osu.Game.Rulesets.Mania.Scoring
if (obj is Note)
{
- AddJudgement(new ManiaJudgement
- {
- Result = HitResult.Hit,
- ManiaResult = ManiaHitResult.Perfect
- });
+ AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
}
else if (holdNote != null)
{
// Head
- AddJudgement(new ManiaJudgement
- {
- Result = HitResult.Hit,
- ManiaResult = ManiaJudgement.MAX_HIT_RESULT
- });
+ AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
// Ticks
int tickCount = holdNote.Ticks.Count();
for (int i = 0; i < tickCount; i++)
- {
- AddJudgement(new HoldNoteTickJudgement
- {
- Result = HitResult.Hit,
- ManiaResult = ManiaJudgement.MAX_HIT_RESULT,
- });
- }
+ AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
- AddJudgement(new HoldNoteTailJudgement
- {
- Result = HitResult.Hit,
- ManiaResult = ManiaJudgement.MAX_HIT_RESULT
- });
+ AddJudgement(new HoldNoteTailJudgement { Result = HitResult.Perfect });
}
}
@@ -221,50 +204,50 @@ namespace osu.Game.Rulesets.Mania.Scoring
maxComboPortion = comboPortion;
}
- protected override void OnNewJudgement(ManiaJudgement judgement)
+ protected override void OnNewJudgement(Judgement judgement)
{
bool isTick = judgement is HoldNoteTickJudgement;
- if (!isTick)
+ if (isTick)
+ {
+ if (judgement.IsHit)
+ {
+ Health.Value += hpMultiplier * hp_increase_tick;
+ bonusScore += judgement.NumericResult;
+ }
+ }
+ else
+ {
totalHits++;
- switch (judgement.Result)
- {
- case HitResult.Miss:
- Health.Value += hpMissMultiplier * hp_increase_miss;
- break;
- case HitResult.Hit:
- if (isTick)
- {
- Health.Value += hpMultiplier * hp_increase_tick;
- bonusScore += judgement.ResultValueForScore;
- }
- else
- {
- switch (judgement.ManiaResult)
- {
- case ManiaHitResult.Bad:
- Health.Value += hpMultiplier * hp_increase_bad;
- break;
- case ManiaHitResult.Ok:
- Health.Value += hpMultiplier * hp_increase_ok;
- break;
- case ManiaHitResult.Good:
- Health.Value += hpMultiplier * hp_increase_good;
- break;
- case ManiaHitResult.Great:
- Health.Value += hpMultiplier * hp_increase_great;
- break;
- case ManiaHitResult.Perfect:
- Health.Value += hpMultiplier * hp_increase_perfect;
- break;
- }
+ switch (judgement.Result)
+ {
+ case HitResult.Miss:
+ Health.Value += hpMissMultiplier * hp_increase_miss;
+ break;
+ case HitResult.Meh:
+ Health.Value += hpMultiplier * hp_increase_bad;
+ break;
+ case HitResult.Ok:
+ Health.Value += hpMultiplier * hp_increase_ok;
+ break;
+ case HitResult.Good:
+ Health.Value += hpMultiplier * hp_increase_good;
+ break;
+ case HitResult.Great:
+ Health.Value += hpMultiplier * hp_increase_great;
+ break;
+ case HitResult.Perfect:
+ Health.Value += hpMultiplier * hp_increase_perfect;
+ break;
+ }
- // A factor that is applied to make higher combos more relevant
- double comboRelevance = Math.Min(Math.Max(0.5, Math.Log(Combo.Value, combo_base)), Math.Log(combo_relevance_cap, combo_base));
- comboPortion += judgement.ResultValueForScore * comboRelevance;
- }
- break;
+ if (judgement.IsHit)
+ {
+ // A factor that is applied to make higher combos more relevant
+ double comboRelevance = Math.Min(Math.Max(0.5, Math.Log(Combo.Value, combo_base)), Math.Log(combo_relevance_cap, combo_base));
+ comboPortion += judgement.NumericResult * comboRelevance;
+ }
}
int scoreForAccuracy = 0;
@@ -272,8 +255,10 @@ namespace osu.Game.Rulesets.Mania.Scoring
foreach (var j in Judgements)
{
- scoreForAccuracy += j.ResultValueForAccuracy;
- maxScoreForAccuracy += j.MaxResultValueForAccuracy;
+ var maniaJudgement = (ManiaJudgement)j;
+
+ scoreForAccuracy += maniaJudgement.NumericAccuracyResult;
+ maxScoreForAccuracy += maniaJudgement.MaxNumericAccuracyResult;
}
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
@@ -285,6 +270,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
base.Reset();
Health.Value = 1;
+ Accuracy.Value = 1;
bonusScore = 0;
comboPortion = 0;
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index a8f5b4919d..1133c9f2ee 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -13,12 +13,11 @@ using osu.Game.Rulesets.Objects.Drawables;
using System;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.UI;
-using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.Judgements;
+using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Mania.UI
{
- public class Column : ScrollingPlayfield, IHasAccentColour
+ public class Column : ScrollingPlayfield, IHasAccentColour
{
private const float key_icon_size = 10;
private const float key_icon_corner_radius = 3;
@@ -36,9 +35,15 @@ namespace osu.Game.Rulesets.Mania.UI
private readonly Container hitTargetBar;
private readonly Container keyIcon;
+ internal readonly Container TopLevelContainer;
+ private readonly Container explosionContainer;
+
protected override Container Content => content;
private readonly Container content;
+ private const float opacity_released = 0.1f;
+ private const float opacity_pressed = 0.25f;
+
public Column()
: base(Axes.Y)
{
@@ -48,9 +53,9 @@ namespace osu.Game.Rulesets.Mania.UI
{
background = new Box
{
- Name = "Foreground",
+ Name = "Background",
RelativeSizeAxes = Axes.Both,
- Alpha = 0.2f
+ Alpha = opacity_released
},
new Container
{
@@ -98,6 +103,11 @@ namespace osu.Game.Rulesets.Mania.UI
{
Pressed = onPressed,
Released = onReleased
+ },
+ explosionContainer = new Container
+ {
+ Name = "Hit explosions",
+ RelativeSizeAxes = Axes.Both
}
}
},
@@ -136,8 +146,11 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
}
- }
+ },
+ TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
};
+
+ TopLevelContainer.Add(explosionContainer.CreateProxy());
}
public override Axes RelativeSizeAxes => Axes.Y;
@@ -188,17 +201,25 @@ namespace osu.Game.Rulesets.Mania.UI
/// Adds a DrawableHitObject to this Playfield.
///
/// The DrawableHitObject to add.
- public override void Add(DrawableHitObject hitObject)
+ public override void Add(DrawableHitObject hitObject)
{
hitObject.AccentColour = AccentColour;
HitObjects.Add(hitObject);
}
+ public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
+ {
+ if (!judgement.IsHit)
+ return;
+
+ explosionContainer.Add(new HitExplosion(judgedObject));
+ }
+
private bool onPressed(ManiaAction action)
{
if (action == Action)
{
- background.FadeTo(background.Alpha + 0.2f, 50, Easing.OutQuint);
+ background.FadeTo(opacity_pressed, 50, Easing.OutQuint);
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
}
@@ -209,7 +230,7 @@ namespace osu.Game.Rulesets.Mania.UI
{
if (action == Action)
{
- background.FadeTo(0.2f, 800, Easing.OutQuart);
+ background.FadeTo(opacity_released, 800, Easing.OutQuart);
keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
}
diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs
new file mode 100644
index 0000000000..08478cef33
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs
@@ -0,0 +1,34 @@
+// 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.Game.Rulesets.Judgements;
+
+namespace osu.Game.Rulesets.Mania.UI
+{
+ internal class DrawableManiaJudgement : DrawableJudgement
+ {
+ public DrawableManiaJudgement(Judgement judgement)
+ : base(judgement)
+ {
+ JudgementText.TextSize = 25;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ this.FadeInFromZero(50, Easing.OutQuint);
+
+ if (Judgement.IsHit)
+ {
+ this.ScaleTo(0.8f);
+ this.ScaleTo(1, 250, Easing.OutElastic);
+
+ this.Delay(50).FadeOut(200).ScaleTo(0.75f, 250);
+ }
+
+ Expire();
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
new file mode 100644
index 0000000000..8164adcebd
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
@@ -0,0 +1,64 @@
+// 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.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Mania.UI
+{
+ internal class HitExplosion : CompositeDrawable
+ {
+ private readonly Box inner;
+
+ public HitExplosion(DrawableHitObject judgedObject)
+ {
+ bool isTick = judgedObject is DrawableHoldNoteTick;
+
+ Anchor = Anchor.TopCentre;
+ Origin = Anchor.Centre;
+
+ RelativeSizeAxes = Axes.Both;
+ Size = new Vector2(isTick ? 0.5f : 1);
+ FillMode = FillMode.Fit;
+
+ Blending = BlendingMode.Additive;
+
+ Color4 accent = isTick ? Color4.White : judgedObject.AccentColour;
+
+ InternalChild = new CircularContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ BorderThickness = 1,
+ BorderColour = accent,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = accent,
+ Radius = 10,
+ Hollow = true
+ },
+ Child = inner = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = accent,
+ Alpha = 1,
+ AlwaysPresent = true,
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500).Expire();
+ inner.FadeOut(250);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index d3dc920fc6..6c164a34f0 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -6,31 +6,24 @@ using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI;
using OpenTK;
using OpenTK.Graphics;
-using osu.Game.Rulesets.Mania.Judgements;
using osu.Framework.Graphics.Containers;
using System;
using osu.Game.Graphics;
using osu.Framework.Allocation;
-using OpenTK.Input;
using System.Linq;
using System.Collections.Generic;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Framework.Graphics.Shapes;
+using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Mania.UI
{
- public class ManiaPlayfield : ScrollingPlayfield
+ public class ManiaPlayfield : ScrollingPlayfield
{
public const float HIT_TARGET_POSITION = 50;
- ///
- /// Default column keys, expanding outwards from the middle as more column are added.
- /// E.g. 2 columns use FJ, 4 columns use DFJK, 6 use SDFJKL, etc...
- ///
- private static readonly Key[] default_keys = { Key.A, Key.S, Key.D, Key.F, Key.J, Key.K, Key.L, Key.Semicolon };
-
private SpecialColumnPosition specialColumnPosition;
///
/// The style to use for the special column.
@@ -60,6 +53,8 @@ namespace osu.Game.Rulesets.Mania.UI
private List normalColumnColours = new List();
private Color4 specialColumnColour;
+ private readonly Container judgements;
+
private readonly int columnCount;
public ManiaPlayfield(int columnCount)
@@ -72,21 +67,21 @@ namespace osu.Game.Rulesets.Mania.UI
Inverted.Value = true;
+ Container topLevelContainer;
InternalChildren = new Drawable[]
{
new Container
{
+ Name = "Playfield elements",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
+ RelativeSizeAxes = Axes.Y,
+ AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new Container
{
- Name = "Masked elements",
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
+ Name = "Columns mask",
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Masking = true,
@@ -94,6 +89,7 @@ namespace osu.Game.Rulesets.Mania.UI
{
new Box
{
+ Name = "Background",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black
},
@@ -105,27 +101,36 @@ namespace osu.Game.Rulesets.Mania.UI
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Left = 1, Right = 1 },
Spacing = new Vector2(1, 0)
- }
+ },
}
},
new Container
{
+ Name = "Barlines mask",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Top = HIT_TARGET_POSITION },
- Children = new[]
+ RelativeSizeAxes = Axes.Y,
+ Width = 1366, // Bar lines should only be masked on the vertical axis
+ BypassAutoSizeAxes = Axes.Both,
+ Masking = true,
+ Child = content = new Container
{
- content = new Container
- {
- Name = "Bar lines",
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- RelativeSizeAxes = Axes.Y,
- // Width is set in the Update method
- }
+ Name = "Bar lines",
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ RelativeSizeAxes = Axes.Y,
+ Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
}
- }
+ },
+ judgements = new Container
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.Centre,
+ AutoSizeAxes = Axes.Both,
+ Y = HIT_TARGET_POSITION + 150,
+ BypassAutoSizeAxes = Axes.Both
+ },
+ topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
}
}
};
@@ -139,6 +144,8 @@ namespace osu.Game.Rulesets.Mania.UI
c.IsSpecial = isSpecialColumn(i);
c.Action = c.IsSpecial ? ManiaAction.Special : currentAction++;
+ topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
+
columns.Add(c);
AddNested(c);
}
@@ -150,6 +157,7 @@ namespace osu.Game.Rulesets.Mania.UI
private void invertedChanged(bool newValue)
{
Scale = new Vector2(1, newValue ? -1 : 1);
+ judgements.Scale = Scale;
}
[BackgroundDependencyLoader]
@@ -184,6 +192,19 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
+ public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
+ {
+ var maniaObject = (ManiaHitObject)judgedObject.HitObject;
+ columns[maniaObject.Column].OnJudgement(judgedObject, judgement);
+
+ judgements.Clear();
+ judgements.Add(new DrawableManiaJudgement(judgement)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+ }
+
///
/// Whether the column index is a special column for this playfield.
///
@@ -203,7 +224,8 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
- public override void Add(DrawableHitObject h) => Columns.ElementAt(h.HitObject.Column).Add(h);
+ public override void Add(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column).Add(h);
+
public void Add(DrawableBarLine barline) => HitObjects.Add(barline);
protected override void Update()
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs
index 5a3da6d074..e9c4895284 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs
@@ -15,26 +15,27 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
-using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.UI
{
- public class ManiaRulesetContainer : ScrollingRulesetContainer
+ public class ManiaRulesetContainer : ScrollingRulesetContainer
{
///
/// The number of columns which the should display, and which
/// the beatmap converter will attempt to convert beatmaps to use.
///
- private int availableColumns;
+ public int AvailableColumns { get; private set; }
public IEnumerable BarLines;
@@ -75,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.UI
BarLines.ForEach(Playfield.Add);
}
- protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(availableColumns)
+ protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(AvailableColumns)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -83,29 +84,29 @@ namespace osu.Game.Rulesets.Mania.UI
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
- public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, availableColumns);
+ public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, AvailableColumns);
protected override BeatmapConverter CreateBeatmapConverter()
{
if (IsForCurrentRuleset)
- availableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize));
+ AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize));
else
{
float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count;
if (percentSliderOrSpinner < 0.2)
- availableColumns = 7;
+ AvailableColumns = 7;
else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5)
- availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6;
+ AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6)
- availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4;
+ AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4;
else
- availableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7));
+ AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7));
}
- return new ManiaBeatmapConverter(IsForCurrentRuleset, availableColumns);
+ return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns);
}
- protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h)
+ protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h)
{
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
@@ -123,5 +124,7 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic);
+
+ protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
}
}
diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
index 890c9116cf..bd540f72c0 100644
--- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
+++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
@@ -9,7 +9,7 @@
Properties
osu.Game.Rulesets.Mania
osu.Game.Rulesets.Mania
- v4.5
+ v4.6.1
512
@@ -60,7 +60,6 @@
-
@@ -70,8 +69,12 @@
+
+
+
+
@@ -83,6 +86,8 @@
+
+
@@ -96,14 +101,6 @@
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}
osu.Framework
-
- {C92A607B-1FDD-4954-9F92-03FF547D9080}
- osu.Game.Rulesets.Osu
-
-
- {F167E17A-7DE6-4AF5-B920-A5112296C695}
- osu.Game.Rulesets.Taiko
-
{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}
osu.Game
diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs b/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs
index d61e179002..3d19d19546 100644
--- a/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs
+++ b/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs
@@ -4,10 +4,14 @@
using OpenTK;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Objects.Drawables;
-using osu.Framework.Extensions;
+using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Judgements
{
+ public class SliderTickJudgement : OsuJudgement
+ {
+ }
+
public class OsuJudgement : Judgement
{
///
@@ -15,38 +19,18 @@ namespace osu.Game.Rulesets.Osu.Judgements
///
public Vector2 PositionOffset;
- ///
- /// The score the user achieved.
- ///
- public OsuScoreResult Score;
-
- ///
- /// The score which would be achievable on a perfect hit.
- ///
- public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
-
- public override string ResultString => Score.GetDescription();
-
- public override string MaxResultString => MaxScore.GetDescription();
-
- public int ScoreValue => scoreToInt(Score);
-
- public int MaxScoreValue => scoreToInt(MaxScore);
-
- private int scoreToInt(OsuScoreResult result)
+ protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
- case OsuScoreResult.Hit50:
+ case HitResult.Meh:
return 50;
- case OsuScoreResult.Hit100:
+ case HitResult.Good:
return 100;
- case OsuScoreResult.Hit300:
+ case HitResult.Great:
return 300;
- case OsuScoreResult.SliderTick:
- return 10;
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs
index 432c6d391c..2970055bff 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs
@@ -96,6 +96,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModSpunOut : Mod
{
public override string Name => "Spun Out";
+ public override string ShortenedName => "SO";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
public override string Description => @"Spinners will be automatically completed";
public override double ScoreMultiplier => 0.9;
@@ -106,6 +107,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModAutopilot : Mod
{
public override string Name => "Autopilot";
+ public override string ShortenedName => "AP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
public override double ScoreMultiplier => 0;
@@ -126,6 +128,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModTarget : Mod
{
public override string Name => "Target";
+ public override string ShortenedName => "TP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
public override string Description => @"";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
index 30e6172802..dbf5c6c541 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
new Box
{
Size = new Vector2(width),
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Alpha = 0.5f,
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index f68a7a765b..3184b83202 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -7,6 +7,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using OpenTK;
using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -38,9 +39,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Colour = AccentColour,
Hit = () =>
{
- if (Judgement.Result != HitResult.None) return false;
+ if (AllJudged)
+ return false;
- Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value
UpdateJudgement(true);
return true;
},
@@ -65,24 +66,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Size = circle.DrawSize;
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered)
{
- if (Judgement.TimeOffset > HitObject.HitWindowFor(OsuScoreResult.Hit50))
- Judgement.Result = HitResult.Miss;
+ if (timeOffset > HitObject.HitWindowFor(HitResult.Meh))
+ AddJudgement(new OsuJudgement { Result = HitResult.Miss });
return;
}
- double hitOffset = Math.Abs(Judgement.TimeOffset);
-
- if (hitOffset < HitObject.HitWindowFor(OsuScoreResult.Hit50))
+ AddJudgement(new OsuJudgement
{
- Judgement.Result = HitResult.Hit;
- Judgement.Score = HitObject.ScoreResultForOffset(hitOffset);
- }
- else
- Judgement.Result = HitResult.Miss;
+ Result = HitObject.ScoreResultForOffset(Math.Abs(timeOffset)),
+ PositionOffset = Vector2.Zero //todo: set to correct value
+ });
}
protected override void UpdateInitialState()
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index b3043d18f6..9205f43a6d 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -3,12 +3,12 @@
using System.ComponentModel;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Judgements;
using osu.Framework.Graphics;
+using System.Linq;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
- public class DrawableOsuHitObject : DrawableHitObject
+ public class DrawableOsuHitObject : DrawableHitObject
{
public const float TIME_PREEMPT = 600;
public const float TIME_FADEIN = 400;
@@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Alpha = 0;
}
- protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.Hit300 };
-
protected sealed override void UpdateState(ArmedState state)
{
FinishTransforms();
@@ -33,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
UpdatePreemptState();
- using (BeginDelayedSequence(TIME_PREEMPT + Judgement.TimeOffset, true))
+ using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
UpdateCurrentState(state);
}
}
@@ -65,18 +63,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
[Description(@"Amazing")]
Perfect
}
-
- public enum OsuScoreResult
- {
- [Description(@"Miss")]
- Miss,
- [Description(@"50")]
- Hit50,
- [Description(@"100")]
- Hit100,
- [Description(@"300")]
- Hit300,
- [Description(@"10")]
- SliderTick
- }
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs
index 892d106b02..7755a54e88 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs
@@ -9,9 +9,10 @@ using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
- public class DrawableOsuJudgement : DrawableJudgement
+ public class DrawableOsuJudgement : DrawableJudgement
{
- public DrawableOsuJudgement(OsuJudgement judgement) : base(judgement)
+ public DrawableOsuJudgement(OsuJudgement judgement)
+ : base(judgement)
{
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index d5583b0d9d..7cb06df679 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -8,6 +8,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -114,33 +115,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
bouncer2.Position = slider.Curve.PositionAt(body.SnakedEnd ?? 0);
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
- if (initialCircle.Judgement?.Result != HitResult.Hit)
+ if (!initialCircle.Judgements.Any(j => j.IsHit))
initialCircle.Position = slider.Curve.PositionAt(progress);
foreach (var c in components) c.UpdateProgress(progress, repeat);
foreach (var t in ticks.Children) t.Tracking = ball.Tracking;
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered && Time.Current >= slider.EndTime)
{
var ticksCount = ticks.Children.Count + 1;
- var ticksHit = ticks.Children.Count(t => t.Judgement.Result == HitResult.Hit);
- if (initialCircle.Judgement.Result == HitResult.Hit)
+ var ticksHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit));
+ if (initialCircle.Judgements.Any(j => j.IsHit))
ticksHit++;
var hitFraction = (double)ticksHit / ticksCount;
- if (hitFraction == 1 && initialCircle.Judgement.Score == OsuScoreResult.Hit300)
- Judgement.Score = OsuScoreResult.Hit300;
- else if (hitFraction >= 0.5 && initialCircle.Judgement.Score >= OsuScoreResult.Hit100)
- Judgement.Score = OsuScoreResult.Hit100;
+ if (hitFraction == 1 && initialCircle.Judgements.Any(j => j.Result == HitResult.Great))
+ AddJudgement(new OsuJudgement { Result = HitResult.Great });
+ else if (hitFraction >= 0.5 && initialCircle.Judgements.Any(j => j.Result >= HitResult.Good))
+ AddJudgement(new OsuJudgement { Result = HitResult.Good });
else if (hitFraction > 0)
- Judgement.Score = OsuScoreResult.Hit50;
+ AddJudgement(new OsuJudgement { Result = HitResult.Meh });
else
- Judgement.Score = OsuScoreResult.Miss;
-
- Judgement.Result = Judgement.Score != OsuScoreResult.Miss ? HitResult.Hit : HitResult.Miss;
+ AddJudgement(new OsuJudgement { Result = HitResult.Miss });
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
index 2a50b23047..0938f78843 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -4,10 +4,10 @@
using System;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Judgements;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
+using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public override bool RemoveWhenNotAlive => false;
- protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.SliderTick };
-
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
{
this.sliderTick = sliderTick;
@@ -49,13 +47,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
};
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
- if (Judgement.TimeOffset >= 0)
- {
- Judgement.Result = Tracking ? HitResult.Hit : HitResult.Miss;
- Judgement.Score = Tracking ? OsuScoreResult.SliderTick : OsuScoreResult.Miss;
- }
+ if (timeOffset >= 0)
+ AddJudgement(new SliderTickJudgement { Result = Tracking ? HitResult.Perfect : HitResult.Miss });
}
protected override void UpdatePreemptState()
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
index 8473cc2453..98dd40b0e6 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
@@ -11,6 +11,7 @@ using OpenTK.Graphics;
using osu.Game.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation;
+using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Screens.Ranking;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
@@ -107,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1);
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (Time.Current < HitObject.StartTime) return;
@@ -129,26 +130,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (!userTriggered && Time.Current >= spinner.EndTime)
{
if (Progress >= 1)
- {
- Judgement.Score = OsuScoreResult.Hit300;
- Judgement.Result = HitResult.Hit;
- }
+ AddJudgement(new OsuJudgement { Result = HitResult.Great });
else if (Progress > .9)
- {
- Judgement.Score = OsuScoreResult.Hit100;
- Judgement.Result = HitResult.Hit;
- }
+ AddJudgement(new OsuJudgement { Result = HitResult.Good });
else if (Progress > .75)
- {
- Judgement.Score = OsuScoreResult.Hit50;
- Judgement.Result = HitResult.Hit;
- }
- else
- {
- Judgement.Score = OsuScoreResult.Miss;
- if (Time.Current >= spinner.EndTime)
- Judgement.Result = HitResult.Miss;
- }
+ AddJudgement(new OsuJudgement { Result = HitResult.Meh });
+ else if (Time.Current >= spinner.EndTime)
+ AddJudgement(new OsuJudgement { Result = HitResult.Miss });
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs
index 0c3c4f0a6d..a7384b8f8e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
new TrianglesPiece
{
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Alpha = 0.5f,
}
};
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs
index e5cf10b88a..7912108901 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs
@@ -16,14 +16,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
- BlendingMode = BlendingMode.Additive;
+ Blending = BlendingMode.Additive;
Alpha = 0;
Children = new Drawable[]
{
new TrianglesPiece
{
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f,
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
index 97d7de35cf..a80d163246 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
- BlendingMode = BlendingMode.Additive;
+ Blending = BlendingMode.Additive;
Alpha = 0;
Children = new Drawable[]
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs
index 8a7b353da1..0adfed2710 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Alpha = 0.5f
}
};
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
index 0bcb8a4986..1986b1431b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
this.slider = slider;
Masking = true;
AutoSizeAxes = Axes.Both;
- BlendingMode = BlendingMode.Additive;
+ Blending = BlendingMode.Additive;
Origin = Anchor.Centre;
BorderThickness = 10;
BorderColour = Color4.Orange;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
index 680f987274..2082e9a27b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
path = new Path
{
- BlendingMode = BlendingMode.None,
+ Blending = BlendingMode.None,
},
}
},
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
index 942f166241..a06aaff7fb 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
this.isEnd = isEnd;
AutoSizeAxes = Axes.Both;
- BlendingMode = BlendingMode.Additive;
+ Blending = BlendingMode.Additive;
Origin = Anchor.Centre;
Children = new Drawable[]
diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
index 7a311f1467..e6bfd8a277 100644
--- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
@@ -4,10 +4,10 @@
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using OpenTK;
-using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Objects
{
@@ -42,30 +42,30 @@ namespace osu.Game.Rulesets.Osu.Objects
public virtual bool NewCombo { get; set; }
public int ComboIndex { get; set; }
- public double HitWindowFor(OsuScoreResult result)
+ public double HitWindowFor(HitResult result)
{
switch (result)
{
default:
return 300;
- case OsuScoreResult.Hit50:
+ case HitResult.Meh:
return 150;
- case OsuScoreResult.Hit100:
+ case HitResult.Good:
return 80;
- case OsuScoreResult.Hit300:
+ case HitResult.Great:
return 30;
}
}
- public OsuScoreResult ScoreResultForOffset(double offset)
+ public HitResult ScoreResultForOffset(double offset)
{
- if (offset < HitWindowFor(OsuScoreResult.Hit300))
- return OsuScoreResult.Hit300;
- if (offset < HitWindowFor(OsuScoreResult.Hit100))
- return OsuScoreResult.Hit100;
- if (offset < HitWindowFor(OsuScoreResult.Hit50))
- return OsuScoreResult.Hit50;
- return OsuScoreResult.Miss;
+ if (offset < HitWindowFor(HitResult.Great))
+ return HitResult.Great;
+ if (offset < HitWindowFor(HitResult.Good))
+ return HitResult.Good;
+ if (offset < HitWindowFor(HitResult.Meh))
+ return HitResult.Meh;
+ return HitResult.Miss;
}
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs
index 72ba421344..c6ecc3a506 100644
--- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs
@@ -51,6 +51,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
foreach (OsuDifficultyHitObject h in onScreen)
{
+ // ReSharper disable once PossibleNullReferenceException (resharper not smart enough to understand IEnumerator.MoveNext())
h.TimeUntilHit -= latest.DeltaTime;
// Calculate reading strain here
}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 00413331e0..c943518b0b 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -112,8 +112,6 @@ namespace osu.Game.Rulesets.Osu
}
}
- public override Mod GetAutoplayMod() => new OsuModAutoplay();
-
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap);
diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs
index b92f1bc60a..f82c6ce3b2 100644
--- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs
+++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs
@@ -9,6 +9,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
using System;
using System.Diagnostics;
using osu.Framework.Graphics;
+using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
@@ -89,20 +90,20 @@ namespace osu.Game.Rulesets.Osu.Replays
double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime;
// Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
- if (h.StartTime - h.HitWindowFor(OsuScoreResult.Miss) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
+ if (h.StartTime - h.HitWindowFor(HitResult.Miss) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
{
- if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
- if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
+ if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
+ if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
}
- else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
+ else if (h.StartTime - h.HitWindowFor(HitResult.Meh) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
{
- if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
- if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
+ if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
+ if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
}
- else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100) > endTime + h.HitWindowFor(OsuScoreResult.Hit100) + 50)
+ else if (h.StartTime - h.HitWindowFor(HitResult.Good) > endTime + h.HitWindowFor(HitResult.Good) + 50)
{
- if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
- if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
+ if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Good), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
+ if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Good), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
}
}
diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs
index 3ee8f56665..59d4492480 100644
--- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs
+++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using osu.Framework.Configuration;
using osu.Framework.Extensions;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
@@ -15,7 +16,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Osu.Scoring
{
- internal class OsuScoreProcessor : ScoreProcessor
+ internal class OsuScoreProcessor : ScoreProcessor
{
public readonly Bindable Mode = new Bindable(ScoringMode.Exponential);
@@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
{
}
- public OsuScoreProcessor(RulesetContainer rulesetContainer)
+ public OsuScoreProcessor(RulesetContainer rulesetContainer)
: base(rulesetContainer)
{
}
@@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
private int totalAccurateJudgements;
- private readonly Dictionary scoreResultCounts = new Dictionary();
+ private readonly Dictionary scoreResultCounts = new Dictionary();
private readonly Dictionary comboResultCounts = new Dictionary();
private double comboMaxScore;
@@ -42,18 +43,10 @@ namespace osu.Game.Rulesets.Osu.Scoring
hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate;
totalAccurateJudgements = beatmap.HitObjects.Count;
- foreach (var h in beatmap.HitObjects)
+ foreach (var unused in beatmap.HitObjects)
{
- if (h != null)
- {
- // TODO: add support for other object types.
- AddJudgement(new OsuJudgement
- {
- MaxScore = OsuScoreResult.Hit300,
- Score = OsuScoreResult.Hit300,
- Result = HitResult.Hit
- });
- }
+ // TODO: add support for other object types.
+ AddJudgement(new OsuJudgement { Result = HitResult.Great });
}
}
@@ -72,44 +65,43 @@ namespace osu.Game.Rulesets.Osu.Scoring
{
base.PopulateScore(score);
- score.Statistics[@"300"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit300);
- score.Statistics[@"100"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit100);
- score.Statistics[@"50"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit50);
- score.Statistics[@"x"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Miss);
+ score.Statistics[@"300"] = scoreResultCounts.GetOrDefault(HitResult.Great);
+ score.Statistics[@"100"] = scoreResultCounts.GetOrDefault(HitResult.Good);
+ score.Statistics[@"50"] = scoreResultCounts.GetOrDefault(HitResult.Meh);
+ score.Statistics[@"x"] = scoreResultCounts.GetOrDefault(HitResult.Miss);
}
- protected override void OnNewJudgement(OsuJudgement judgement)
+ protected override void OnNewJudgement(Judgement judgement)
{
- if (judgement != null)
+ var osuJudgement = (OsuJudgement)judgement;
+
+ if (judgement.Result != HitResult.None)
{
- if (judgement.Result != HitResult.None)
- {
- scoreResultCounts[judgement.Score] = scoreResultCounts.GetOrDefault(judgement.Score) + 1;
- comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1;
- }
+ scoreResultCounts[judgement.Result] = scoreResultCounts.GetOrDefault(judgement.Result) + 1;
+ comboResultCounts[osuJudgement.Combo] = comboResultCounts.GetOrDefault(osuJudgement.Combo) + 1;
+ }
- switch (judgement.Score)
- {
- case OsuScoreResult.Hit300:
- Health.Value += (10.2 - hpDrainRate) * 0.02;
- break;
+ switch (judgement.Result)
+ {
+ case HitResult.Great:
+ Health.Value += (10.2 - hpDrainRate) * 0.02;
+ break;
- case OsuScoreResult.Hit100:
- Health.Value += (8 - hpDrainRate) * 0.02;
- break;
+ case HitResult.Good:
+ Health.Value += (8 - hpDrainRate) * 0.02;
+ break;
- case OsuScoreResult.Hit50:
- Health.Value += (4 - hpDrainRate) * 0.02;
- break;
+ case HitResult.Meh:
+ Health.Value += (4 - hpDrainRate) * 0.02;
+ break;
- case OsuScoreResult.SliderTick:
- Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01;
- break;
+ /*case HitResult.SliderTick:
+ Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01;
+ break;*/
- case OsuScoreResult.Miss:
- Health.Value -= hpDrainRate * 0.04;
- break;
- }
+ case HitResult.Miss:
+ Health.Value -= hpDrainRate * 0.04;
+ break;
}
calculateScore();
@@ -124,10 +116,10 @@ namespace osu.Game.Rulesets.Osu.Scoring
foreach (var j in Judgements)
{
- baseScore += j.ScoreValue;
- baseMaxScore += j.MaxScoreValue;
+ baseScore += j.NumericResult;
+ baseMaxScore += j.MaxNumericResult;
- comboScore += j.ScoreValue * (1 + Combo.Value / 10d);
+ comboScore += j.NumericResult * (1 + Combo.Value / 10d);
}
Accuracy.Value = (double)baseScore / baseMaxScore;
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 9b88c9d1b3..17f4f9f541 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -10,12 +10,13 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
using osu.Game.Rulesets.UI;
using System.Linq;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
namespace osu.Game.Rulesets.Osu.UI
{
- public class OsuPlayfield : Playfield
+ public class OsuPlayfield : Playfield
{
private readonly Container approachCircles;
private readonly Container judgementLayer;
@@ -67,11 +68,9 @@ namespace osu.Game.Rulesets.Osu.UI
AddInternal(new GameplayCursor());
}
- public override void Add(DrawableHitObject h)
+ public override void Add(DrawableHitObject h)
{
- h.Depth = (float)h.HitObject.StartTime;
-
- IDrawableHitObjectWithProxiedApproach c = h as IDrawableHitObjectWithProxiedApproach;
+ var c = h as IDrawableHitObjectWithProxiedApproach;
if (c != null)
approachCircles.Add(c.ProxiedLayer.CreateProxy());
@@ -85,12 +84,15 @@ namespace osu.Game.Rulesets.Osu.UI
.OrderBy(h => h.StartTime).OfType();
}
- public override void OnJudgement(DrawableHitObject judgedObject)
+ public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
- DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgedObject.Judgement)
+ var osuJudgement = (OsuJudgement)judgement;
+ var osuObject = (OsuHitObject)judgedObject.HitObject;
+
+ DrawableOsuJudgement explosion = new DrawableOsuJudgement(osuJudgement)
{
Origin = Anchor.Centre,
- Position = judgedObject.HitObject.StackedEndPosition + judgedObject.Judgement.PositionOffset
+ Position = osuObject.StackedEndPosition + osuJudgement.PositionOffset
};
judgementLayer.Add(explosion);
diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs
index 0b87bf7346..668a440c4a 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs
@@ -7,7 +7,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Beatmaps;
-using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Replays;
@@ -18,7 +17,7 @@ using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Osu.UI
{
- public class OsuRulesetContainer : RulesetContainer
+ public class OsuRulesetContainer : RulesetContainer
{
public OsuRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(ruleset, beatmap, isForCurrentRuleset)
@@ -31,11 +30,11 @@ namespace osu.Game.Rulesets.Osu.UI
protected override BeatmapProcessor CreateBeatmapProcessor() => new OsuBeatmapProcessor();
- protected override Playfield CreatePlayfield() => new OsuPlayfield();
+ protected override Playfield CreatePlayfield() => new OsuPlayfield();
public override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
- protected override DrawableHitObject GetVisualRepresentation(OsuHitObject h)
+ protected override DrawableHitObject GetVisualRepresentation(OsuHitObject h)
{
var circle = h as HitCircle;
if (circle != null)
diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
index 0c9e53cf69..857f47f9b9 100644
--- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
+++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
@@ -9,7 +9,7 @@
Properties
osu.Game.Rulesets.Osu
osu.Game.Rulesets.Osu
- v4.5
+ v4.6.1
512
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs
index 78a5b29d36..0d61494add 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs
+++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs
@@ -1,34 +1,26 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using osu.Game.Rulesets.Objects.Drawables;
+
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoDrumRollTickJudgement : TaikoJudgement
{
- ///
- /// Drum roll ticks don't display judgement text.
- ///
- public override string ResultString => string.Empty;
-
- ///
- /// Drum roll ticks don't display judgement text.
- ///
- public override string MaxResultString => string.Empty;
-
public override bool AffectsCombo => false;
- protected override int NumericResultForScore(TaikoHitResult result)
+ protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
- case TaikoHitResult.Great:
+ case HitResult.Great:
return 200;
}
}
- protected override int NumericResultForAccuracy(TaikoHitResult result)
+ protected override int NumericResultForAccuracy(HitResult result)
{
return 0;
}
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoHitResult.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoHitResult.cs
deleted file mode 100644
index 5fd850d6b0..0000000000
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoHitResult.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 System.ComponentModel;
-
-namespace osu.Game.Rulesets.Taiko.Judgements
-{
- public enum TaikoHitResult
- {
- [Description("GOOD")]
- Good,
- [Description("GREAT")]
- Great
- }
-}
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs
index 7bca59bf11..9d6b5ca535 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs
+++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs
@@ -2,86 +2,56 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Judgements;
-using osu.Framework.Extensions;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoJudgement : Judgement
{
- ///
- /// The maximum result.
- ///
- public const TaikoHitResult MAX_HIT_RESULT = TaikoHitResult.Great;
-
- ///
- /// The result.
- ///
- public TaikoHitResult TaikoResult;
-
- ///
- /// The result value for the combo portion of the score.
- ///
- public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(TaikoResult);
-
///
/// The result value for the accuracy portion of the score.
///
- public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(TaikoResult);
-
- ///
- /// The maximum result value for the combo portion of the score.
- ///
- public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
+ public int ResultNumericForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(Result);
///
/// The maximum result value for the accuracy portion of the score.
///
- public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
-
- public override string ResultString => TaikoResult.GetDescription();
-
- public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
-
- ///
- /// Whether this Judgement has a secondary hit in the case of strong hits.
- ///
- public virtual bool SecondHit { get; set; }
+ public int MaxResultValueForAccuracy => NumericResultForAccuracy(HitResult.Great);
///
/// Computes the numeric result value for the combo portion of the score.
- /// For the accuracy portion of the score (including accuracy percentage), see .
+ /// For the accuracy portion of the score (including accuracy percentage), see .
///
/// The result to compute the value for.
/// The numeric result value.
- protected virtual int NumericResultForScore(TaikoHitResult result)
+ protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
- case TaikoHitResult.Good:
+ case HitResult.Good:
return 100;
- case TaikoHitResult.Great:
+ case HitResult.Great:
return 300;
}
}
///
/// Computes the numeric result value for the accuracy portion of the score.
- /// For the combo portion of the score, see .
+ /// For the combo portion of the score, see .
///
/// The result to compute the value for.
/// The numeric result value.
- protected virtual int NumericResultForAccuracy(TaikoHitResult result)
+ protected virtual int NumericResultForAccuracy(HitResult result)
{
switch (result)
{
default:
return 0;
- case TaikoHitResult.Good:
+ case HitResult.Good:
return 150;
- case TaikoHitResult.Great:
+ case HitResult.Great:
return 300;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs
index 4996cac39e..bb67784ab1 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs
+++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs
@@ -1,25 +1,17 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Taiko.Judgements
{
- public class TaikoStrongHitJudgement : TaikoJudgement, IPartialJudgement
+ public class TaikoStrongHitJudgement : TaikoJudgement
{
- public bool Changed { get; set; }
-
- public override bool SecondHit
+ public TaikoStrongHitJudgement()
{
- get { return base.SecondHit; }
- set
- {
- if (base.SecondHit == value)
- return;
- base.SecondHit = value;
-
- Changed = true;
- }
+ base.Result = HitResult.Perfect;
}
+
+ public new HitResult Result => base.Result;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
index 9df1b41a8b..b30b3a1aca 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
@@ -5,14 +5,13 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using OpenTK;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
///
/// A line that scrolls alongside hit objects in the playfield and visualises control points.
///
- public class DrawableBarLine : DrawableScrollingHitObject
+ public class DrawableBarLine : DrawableScrollingHitObject
{
///
/// The width of the line tracker.
@@ -58,8 +57,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
};
}
- protected override TaikoJudgement CreateJudgement() => null;
-
protected override void UpdateState(ArmedState state)
{
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
index 5d6ea8f51e..2396f3bf91 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
@@ -12,6 +12,7 @@ using OpenTK.Graphics;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
@@ -52,8 +53,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
- protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = HitObject.IsStrong };
-
protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece();
public override bool OnPressed(TaikoAction action) => false;
@@ -65,9 +64,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
accentDarkColour = colours.YellowDarker;
}
- private void onTickJudgement(DrawableHitObject obj)
+ private void onTickJudgement(DrawableHitObject obj, Judgement judgement)
{
- if (obj.Judgement.Result == HitResult.Hit)
+ if (judgement.Result > HitResult.Miss)
rollingHits++;
else
rollingHits--;
@@ -78,23 +77,24 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
MainPiece.FadeAccent(newAccent, 100);
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (userTriggered)
return;
- if (Judgement.TimeOffset < 0)
+ if (timeOffset < 0)
return;
- int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
+ int countHit = NestedHitObjects.Count(o => o.AllJudged);
if (countHit > HitObject.RequiredGoodHits)
{
- Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
+ AddJudgement(new TaikoJudgement { Result = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good });
+ if (HitObject.IsStrong)
+ AddJudgement(new TaikoStrongHitJudgement());
}
else
- Judgement.Result = HitResult.Miss;
+ AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
}
protected override void UpdateState(ArmedState state)
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
index e94886df16..8ac67ba0a6 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
@@ -34,18 +34,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Filled = HitObject.FirstTick
};
- protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong };
-
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered)
return;
- if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
- {
- Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = TaikoHitResult.Great;
- }
+ if (!(Math.Abs(timeOffset) < HitObject.HitWindow))
+ return;
+
+ AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
+ if (HitObject.IsStrong)
+ AddJudgement(new TaikoStrongHitJudgement());
}
protected override void UpdateState(ArmedState state)
@@ -58,9 +57,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
- public override bool OnPressed(TaikoAction action)
- {
- return Judgement.Result == HitResult.None && UpdateJudgement(true);
- }
+ public override bool OnPressed(TaikoAction action) => UpdateJudgement(true);
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
index 6b041dfe25..55eaa8dbb8 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
@@ -28,36 +28,30 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
FillMode = FillMode.Fit;
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered)
{
- if (Judgement.TimeOffset > HitObject.HitWindowGood)
- Judgement.Result = HitResult.Miss;
+ if (timeOffset > HitObject.HitWindowGood)
+ AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
return;
}
- double hitOffset = Math.Abs(Judgement.TimeOffset);
+ double hitOffset = Math.Abs(timeOffset);
if (hitOffset > HitObject.HitWindowMiss)
return;
if (!validKeyPressed)
- Judgement.Result = HitResult.Miss;
+ AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
else if (hitOffset < HitObject.HitWindowGood)
- {
- Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = hitOffset < HitObject.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
- }
+ AddJudgement(new TaikoJudgement { Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good });
else
- Judgement.Result = HitResult.Miss;
+ AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
}
public override bool OnPressed(TaikoAction action)
{
- if (Judgement.Result != HitResult.None)
- return false;
-
validKeyPressed = HitActions.Contains(action);
return UpdateJudgement(true);
@@ -75,7 +69,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
var circlePiece = MainPiece as CirclePiece;
circlePiece?.FlashBox.FinishTransforms();
- using (BeginDelayedSequence(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true))
+ var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime;
+ using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true))
{
switch (State)
{
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs
index 256c50d33a..48812093c4 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@@ -25,13 +24,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
}
- protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
+ private bool processedSecondHit;
+ public override bool AllJudged => processedSecondHit && base.AllJudged;
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
- if (Judgement.Result == HitResult.None)
+ if (!base.AllJudged)
{
- base.CheckJudgement(userTriggered);
+ base.CheckForJudgements(userTriggered, timeOffset);
return;
}
@@ -41,7 +41,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
// If we get here, we're assured that the key pressed is the correct secondary key
if (Math.Abs(firstHitTime - Time.Current) < second_hit_window)
- Judgement.SecondHit = true;
+ {
+ AddJudgement(new TaikoStrongHitJudgement());
+ processedSecondHit = true;
+ }
}
public override bool OnReleased(TaikoAction action)
@@ -54,7 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public override bool OnPressed(TaikoAction action)
{
// Check if we've handled the first key
- if (Judgement.Result == HitResult.None)
+ if (!base.AllJudged)
{
// First key hasn't been handled yet, attempt to handle it
bool handled = base.OnPressed(action);
@@ -70,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
// If we've already hit the second key, don't handle this object any further
- if (Judgement.SecondHit)
+ if (processedSecondHit)
return false;
// Don't handle represses of the first key
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
index 4eb5c46838..738902846b 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
@@ -9,11 +9,11 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
+using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
@@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Origin = Anchor.Centre,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Masking = true,
Children = new[]
{
@@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = target_ring_thick_border,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Children = new Drawable[]
{
new Box
@@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Width *= Parent.RelativeChildSize.X;
}
- protected override void CheckJudgement(bool userTriggered)
+ protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (userTriggered)
{
@@ -153,24 +153,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint);
if (userHits == HitObject.RequiredHits)
- {
- Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = TaikoHitResult.Great;
- }
+ AddJudgement(new TaikoJudgement { Result = HitResult.Great });
}
else
{
- if (Judgement.TimeOffset < 0)
+ if (timeOffset < 0)
return;
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
- if (userHits > HitObject.RequiredHits / 2)
- {
- Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = TaikoHitResult.Good;
- }
- else
- Judgement.Result = HitResult.Miss;
+ AddJudgement(userHits > HitObject.RequiredHits / 2
+ ? new TaikoJudgement { Result = HitResult.Good }
+ : new TaikoJudgement { Result = HitResult.Miss });
}
}
@@ -180,7 +173,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
const float out_transition_time = 300;
double untilStartTime = HitObject.StartTime - Time.Current;
- double untilJudgement = untilStartTime + Judgement.TimeOffset + HitObject.Duration;
+ double untilJudgement = untilStartTime + (Judgements.FirstOrDefault()?.TimeOffset ?? 0) + HitObject.Duration;
targetRing.Delay(untilStartTime - preempt).ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint);
this.Delay(untilJudgement).FadeOut(out_transition_time, Easing.Out);
@@ -214,9 +207,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public override bool OnPressed(TaikoAction action)
{
- if (Judgement.Result != HitResult.None)
- return false;
-
// Don't handle keys before the swell starts
if (Time.Current < HitObject.StartTime)
return false;
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index 46cdfcc365..7976cbbbc1 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -4,15 +4,13 @@
using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
- public abstract class DrawableTaikoHitObject
- : DrawableScrollingHitObject, IKeyBindingHandler
- where TaikoHitType : TaikoHitObject
+ public abstract class DrawableTaikoHitObject : DrawableScrollingHitObject, IKeyBindingHandler
+ where TaikoHitType : TaikoHitObject
{
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
@@ -37,8 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
MainPiece.KiaiMode = HitObject.Kiai;
}
- protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
-
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();
public abstract bool OnPressed(TaikoAction action);
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
index ba717371dd..3264b77bc4 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
@@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Alpha = 0,
AlwaysPresent = true
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs
index f1c0afc675..1be91a7d94 100644
--- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs
@@ -1,8 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Beatmaps;
-using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Taiko.Objects
@@ -29,19 +27,5 @@ namespace osu.Game.Rulesets.Taiko.Objects
/// Strong hit objects give more points for hitting the hit object with both keys.
///
public bool IsStrong;
-
- ///
- /// Whether this HitObject is in Kiai time.
- ///
- public bool Kiai { get; protected set; }
-
- public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
- {
- base.ApplyDefaults(controlPointInfo, difficulty);
-
- EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime);
-
- Kiai |= effectPoint.KiaiMode;
- }
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs
index 83203f5a7e..6b99b23a12 100644
--- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs
+++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs
@@ -3,6 +3,7 @@
using System;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Judgements;
@@ -12,7 +13,7 @@ using OpenTK;
namespace osu.Game.Rulesets.Taiko.Scoring
{
- internal class TaikoScoreProcessor : ScoreProcessor
+ internal class TaikoScoreProcessor : ScoreProcessor
{
///
/// The maximum score achievable.
@@ -36,12 +37,12 @@ namespace osu.Game.Rulesets.Taiko.Scoring
private const double combo_base = 4;
///
- /// The HP awarded by a hit.
+ /// The HP awarded by a hit.
///
private const double hp_hit_great = 0.03;
///
- /// The HP awarded for a hit.
+ /// The HP awarded for a hit.
///
private const double hp_hit_good = 0.011;
@@ -113,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{
}
- public TaikoScoreProcessor(RulesetContainer rulesetContainer)
+ public TaikoScoreProcessor(RulesetContainer rulesetContainer)
: base(rulesetContainer)
{
}
@@ -138,39 +139,28 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{
if (obj is Hit)
{
- AddJudgement(new TaikoJudgement
- {
- Result = HitResult.Hit,
- TaikoResult = TaikoHitResult.Great,
- SecondHit = obj.IsStrong
- });
+ AddJudgement(new TaikoJudgement { Result = HitResult.Great });
+ if (obj.IsStrong)
+ AddJudgement(new TaikoStrongHitJudgement());
}
else if (obj is DrumRoll)
{
for (int i = 0; i < ((DrumRoll)obj).TotalTicks; i++)
{
- AddJudgement(new TaikoDrumRollTickJudgement
- {
- Result = HitResult.Hit,
- TaikoResult = TaikoHitResult.Great,
- SecondHit = obj.IsStrong
- });
+ AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
+
+ if (obj.IsStrong)
+ AddJudgement(new TaikoStrongHitJudgement());
}
- AddJudgement(new TaikoJudgement
- {
- Result = HitResult.Hit,
- TaikoResult = TaikoHitResult.Great,
- SecondHit = obj.IsStrong
- });
+ AddJudgement(new TaikoJudgement { Result = HitResult.Great });
+
+ if (obj.IsStrong)
+ AddJudgement(new TaikoStrongHitJudgement());
}
else if (obj is Swell)
{
- AddJudgement(new TaikoJudgement
- {
- Result = HitResult.Hit,
- TaikoResult = TaikoHitResult.Great
- });
+ AddJudgement(new TaikoJudgement { Result = HitResult.Great });
}
}
@@ -178,16 +168,40 @@ namespace osu.Game.Rulesets.Taiko.Scoring
maxComboPortion = comboPortion;
}
- protected override void OnNewJudgement(TaikoJudgement judgement)
+ protected override void OnNewJudgement(Judgement judgement)
{
+ bool isStrong = judgement is TaikoStrongHitJudgement;
bool isTick = judgement is TaikoDrumRollTickJudgement;
- // Don't consider ticks as a type of hit that counts towards map completion
- if (!isTick)
+ // Don't consider ticks and strong hits as a type of hit that counts towards map completion
+ if (!isTick && !isStrong)
totalHits++;
// Apply score changes
- addHitScore(judgement);
+ if (judgement.IsHit)
+ {
+ double baseValue = judgement.NumericResult;
+
+ if (isStrong)
+ {
+ // Add increased score for the previous judgement by hitting a strong hit object with the second key
+ var prevJudgement = Judgements[Judgements.Count - 1];
+ baseValue = prevJudgement.NumericResult * strongHitScale;
+
+ }
+
+ // Add score to portions
+ if (judgement is TaikoDrumRollTickJudgement)
+ bonusScore += baseValue;
+ else
+ {
+ // A relevance factor that needs to be applied to make higher combos more relevant
+ // Value is capped at 400 combo
+ double comboRelevance = Math.Min(Math.Log(400, combo_base), Math.Max(0.5, Math.Log(Combo.Value, combo_base)));
+
+ comboPortion += baseValue * comboRelevance;
+ }
+ }
// Apply HP changes
switch (judgement.Result)
@@ -197,66 +211,26 @@ namespace osu.Game.Rulesets.Taiko.Scoring
if (!isTick)
Health.Value += hpIncreaseMiss;
break;
- case HitResult.Hit:
- switch (judgement.TaikoResult)
- {
- case TaikoHitResult.Good:
- Health.Value += hpIncreaseGood;
- break;
- case TaikoHitResult.Great:
- if (isTick)
- Health.Value += hpIncreaseTick;
- else
- Health.Value += hpIncreaseGreat;
- break;
- }
+ case HitResult.Good:
+ Health.Value += hpIncreaseGood;
+ break;
+ case HitResult.Great:
+ if (isTick)
+ Health.Value += hpIncreaseTick;
+ else
+ Health.Value += hpIncreaseGreat;
break;
}
- calculateScore();
- }
-
- protected override void OnJudgementChanged(TaikoJudgement judgement)
- {
- // Apply score changes
- addHitScore(judgement);
-
- calculateScore();
- }
-
- private void addHitScore(TaikoJudgement judgement)
- {
- if (judgement.Result != HitResult.Hit)
- return;
-
- double baseValue = judgement.ResultValueForScore;
-
- // Add increased score for hitting a strong hit object with the second key
- if (judgement.SecondHit)
- baseValue *= strongHitScale;
-
- // Add score to portions
- if (judgement is TaikoDrumRollTickJudgement)
- bonusScore += baseValue;
- else
- {
- // A relevance factor that needs to be applied to make higher combos more relevant
- // Value is capped at 400 combo
- double comboRelevance = Math.Min(Math.Log(400, combo_base), Math.Max(0.5, Math.Log(Combo.Value, combo_base)));
-
- comboPortion += baseValue * comboRelevance;
- }
- }
-
- private void calculateScore()
- {
int scoreForAccuracy = 0;
int maxScoreForAccuracy = 0;
foreach (var j in Judgements)
{
- scoreForAccuracy += j.ResultValueForAccuracy;
- maxScoreForAccuracy += j.MaxResultValueForAccuracy;
+ var taikoJudgement = (TaikoJudgement)j;
+
+ scoreForAccuracy += taikoJudgement.ResultNumericForAccuracy;
+ maxScoreForAccuracy += taikoJudgement.MaxResultValueForAccuracy;
}
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
index f457732085..7b1452766e 100644
--- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
@@ -95,8 +95,6 @@ namespace osu.Game.Rulesets.Taiko
}
}
- public override Mod GetAutoplayMod() => new TaikoModAutoplay();
-
public override string Description => "osu!taiko";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs
index 779471b8dc..41b66c286b 100644
--- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs
+++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs
@@ -1,7 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Allocation;
using osu.Game.Graphics;
@@ -13,15 +12,19 @@ namespace osu.Game.Rulesets.Taiko.UI
///
/// Text that is shown as judgement when a hit object is hit or missed.
///
- public class DrawableTaikoJudgement : DrawableJudgement
+ public class DrawableTaikoJudgement : DrawableJudgement
{
+ public readonly DrawableHitObject JudgedObject;
+
///
/// Creates a new judgement text.
///
+ /// The object which is being judged.
/// The judgement to visualise.
- public DrawableTaikoJudgement(TaikoJudgement judgement)
+ public DrawableTaikoJudgement(DrawableHitObject judgedObject, Judgement judgement)
: base(judgement)
{
+ JudgedObject = judgedObject;
}
[BackgroundDependencyLoader]
@@ -29,28 +32,19 @@ namespace osu.Game.Rulesets.Taiko.UI
{
switch (Judgement.Result)
{
- case HitResult.Hit:
- switch (Judgement.TaikoResult)
- {
- case TaikoHitResult.Good:
- Colour = colours.GreenLight;
- break;
- case TaikoHitResult.Great:
- Colour = colours.BlueLight;
- break;
- }
+ case HitResult.Good:
+ Colour = colours.GreenLight;
+ break;
+ case HitResult.Great:
+ Colour = colours.BlueLight;
break;
}
}
protected override void LoadComplete()
{
- switch (Judgement.Result)
- {
- case HitResult.Hit:
- this.MoveToY(-100, 500);
- break;
- }
+ if (Judgement.IsHit)
+ this.MoveToY(-100, 500);
base.LoadComplete();
}
diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
index cb849a11c7..830a01bfbc 100644
--- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
-using osu.Game.Rulesets.Taiko.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.UI
@@ -18,17 +18,17 @@ namespace osu.Game.Rulesets.Taiko.UI
///
internal class HitExplosion : CircularContainer
{
- public readonly TaikoJudgement Judgement;
+ public readonly DrawableHitObject JudgedObject;
private readonly Box innerFill;
private readonly bool isRim;
- public HitExplosion(TaikoJudgement judgement, bool isRim)
+ public HitExplosion(DrawableHitObject judgedObject, bool isRim)
{
this.isRim = isRim;
- Judgement = judgement;
+ JudgedObject = judgedObject;
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs
index 659f421ebe..5e79166bec 100644
--- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs
+++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs
@@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Taiko.UI
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
},
centre = new Sprite
{
@@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f),
Alpha = 0,
- BlendingMode = BlendingMode.Additive
+ Blending = BlendingMode.Additive
}
};
}
diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
index bac956a25b..e3e1d485d8 100644
--- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
@@ -7,22 +7,22 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
-using osu.Game.Rulesets.Taiko.Judgements;
+using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.UI
{
public class KiaiHitExplosion : CircularContainer
{
- public readonly TaikoJudgement Judgement;
+ public readonly DrawableHitObject JudgedObject;
private readonly bool isRim;
- public KiaiHitExplosion(TaikoJudgement judgement, bool isRim)
+ public KiaiHitExplosion(DrawableHitObject judgedObject, bool isRim)
{
this.isRim = isRim;
- Judgement = judgement;
+ JudgedObject = judgedObject;
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index 678de7f713..2dd06f7179 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -14,11 +14,12 @@ using osu.Game.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Extensions.Color4Extensions;
using System.Linq;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
namespace osu.Game.Rulesets.Taiko.UI
{
- public class TaikoPlayfield : ScrollingPlayfield
+ public class TaikoPlayfield : ScrollingPlayfield
{
///
/// Default height of a when inside a .
@@ -97,7 +98,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
},
new HitTarget
{
@@ -126,14 +127,14 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
- BlendingMode = BlendingMode.Additive
+ Blending = BlendingMode.Additive
},
judgementContainer = new Container
{
Name = "Judgements",
RelativeSizeAxes = Axes.Y,
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
- BlendingMode = BlendingMode.Additive
+ Blending = BlendingMode.Additive
},
}
},
@@ -202,10 +203,8 @@ namespace osu.Game.Rulesets.Taiko.UI
background.Colour = colours.Gray0;
}
- public override void Add(DrawableHitObject h)
+ public override void Add(DrawableHitObject h)
{
- h.Depth = (float)h.HitObject.StartTime;
-
base.Add(h);
var barline = h as DrawableBarLine;
@@ -218,25 +217,27 @@ namespace osu.Game.Rulesets.Taiko.UI
swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy());
}
- public override void OnJudgement(DrawableHitObject judgedObject)
+ public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
- bool wasHit = judgedObject.Judgement.Result == HitResult.Hit;
- bool secondHit = judgedObject.Judgement.SecondHit;
-
- judgementContainer.Add(new DrawableTaikoJudgement(judgedObject.Judgement)
+ if (judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
{
- Anchor = wasHit ? Anchor.TopLeft : Anchor.CentreLeft,
- Origin = wasHit ? Anchor.BottomCentre : Anchor.Centre,
- RelativePositionAxes = Axes.X,
- X = wasHit ? judgedObject.Position.X : 0,
- });
+ judgementContainer.Add(new DrawableTaikoJudgement(judgedObject, judgement)
+ {
+ Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft,
+ Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre,
+ RelativePositionAxes = Axes.X,
+ X = judgement.IsHit ? judgedObject.Position.X : 0,
+ });
+ }
- if (!wasHit)
+ if (!judgement.IsHit)
return;
bool isRim = judgedObject.HitObject is RimHit;
- if (!secondHit)
+ if (judgement is TaikoStrongHitJudgement)
+ hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == judgedObject)?.VisualiseSecondHit();
+ else
{
if (judgedObject.X >= -0.05f && judgedObject is DrawableHit)
{
@@ -244,13 +245,11 @@ namespace osu.Game.Rulesets.Taiko.UI
topLevelHitContainer.Add(judgedObject.CreateProxy());
}
- hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement, isRim));
+ hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
if (judgedObject.HitObject.Kiai)
- kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject.Judgement, isRim));
+ kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim));
}
- else
- hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit();
}
}
}
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs
index 96e5df12cd..4e7b676fbc 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs
@@ -9,7 +9,6 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Beatmaps;
-using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Scoring;
@@ -22,7 +21,7 @@ using osu.Framework.Input;
namespace osu.Game.Rulesets.Taiko.UI
{
- public class TaikoRulesetContainer : ScrollingRulesetContainer
+ public class TaikoRulesetContainer : ScrollingRulesetContainer
{
public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(ruleset, beatmap, isForCurrentRuleset)
@@ -95,13 +94,13 @@ namespace osu.Game.Rulesets.Taiko.UI
public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
- protected override Playfield CreatePlayfield() => new TaikoPlayfield
+ protected override Playfield CreatePlayfield() => new TaikoPlayfield
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft
};
- protected override DrawableHitObject GetVisualRepresentation(TaikoHitObject h)
+ protected override DrawableHitObject GetVisualRepresentation(TaikoHitObject h)
{
var centreHit = h as CentreHit;
if (centreHit != null)
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index 33748a267f..a840997214 100644
--- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
+++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
@@ -9,7 +9,7 @@
Properties
osu.Game.Rulesets.Taiko
osu.Game.Rulesets.Taiko
- v4.5
+ v4.6.1
512
@@ -52,7 +52,6 @@
-
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 8ec68b41be..220b1aac7f 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -7,7 +7,7 @@
Library
osu.Game.Tests
osu.Game.Tests
- v4.5
+ v4.6.1
true
diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs
index 82777734bb..15953fcd82 100644
--- a/osu.Game/Beatmaps/Beatmap.cs
+++ b/osu.Game/Beatmaps/Beatmap.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
public class Beatmap
where T : HitObject
{
- public BeatmapInfo BeatmapInfo;
+ public BeatmapInfo BeatmapInfo = new BeatmapInfo();
public ControlPointInfo ControlPointInfo = new ControlPointInfo();
public List Breaks = new List();
public readonly List ComboColors = new List
@@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps
///
/// The HitObjects this Beatmap contains.
///
- public List HitObjects;
+ public List HitObjects = new List();
///
/// Total amount of break time in the beatmap.
@@ -44,12 +44,13 @@ namespace osu.Game.Beatmaps
/// Constructs a new beatmap.
///
/// The original beatmap to use the parameters of.
- public Beatmap(Beatmap original = null)
+ public Beatmap(Beatmap original = null)
{
BeatmapInfo = original?.BeatmapInfo.DeepClone() ?? BeatmapInfo;
ControlPointInfo = original?.ControlPointInfo ?? ControlPointInfo;
Breaks = original?.Breaks ?? Breaks;
ComboColors = original?.ComboColors ?? ComboColors;
+ HitObjects = original?.HitObjects ?? HitObjects;
}
}
@@ -65,7 +66,6 @@ namespace osu.Game.Beatmaps
public Beatmap(Beatmap original = null)
: base(original)
{
- HitObjects = original?.HitObjects;
}
}
}
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 551612330b..f58b3505c5 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -20,6 +20,9 @@ using osu.Game.IPC;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using SQLite.Net;
+using osu.Game.Online.API.Requests;
+using System.Threading.Tasks;
+using osu.Game.Online.API;
namespace osu.Game.Beatmaps
{
@@ -63,6 +66,10 @@ namespace osu.Game.Beatmaps
private readonly BeatmapStore beatmaps;
+ private readonly APIAccess api;
+
+ private readonly List currentDownloads = new List();
+
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc;
@@ -76,7 +83,7 @@ namespace osu.Game.Beatmaps
///
public Func GetStableStorage { private get; set; }
- public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null)
+ public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null)
{
beatmaps = new BeatmapStore(connection);
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
@@ -88,6 +95,7 @@ namespace osu.Game.Beatmaps
this.files = files;
this.connection = connection;
this.rulesets = rulesets;
+ this.api = api;
if (importHost != null)
ipc = new BeatmapIPCChannel(importHost, this);
@@ -177,6 +185,74 @@ namespace osu.Game.Beatmaps
beatmaps.Add(beatmapSetInfo);
}
+ ///
+ /// Downloads a beatmap.
+ ///
+ /// The to be downloaded.
+ /// A new , or an existing one if a download is already in progress.
+ public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo)
+ {
+ var existing = GetExistingDownload(beatmapSetInfo);
+
+ if (existing != null) return existing;
+
+ if (api == null) return null;
+
+ ProgressNotification downloadNotification = new ProgressNotification
+ {
+ Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
+ };
+
+ var request = new DownloadBeatmapSetRequest(beatmapSetInfo);
+
+ request.DownloadProgressed += progress =>
+ {
+ downloadNotification.State = ProgressNotificationState.Active;
+ downloadNotification.Progress = progress;
+ };
+
+ request.Success += data =>
+ {
+ downloadNotification.State = ProgressNotificationState.Completed;
+
+ using (var stream = new MemoryStream(data))
+ using (var archive = new OszArchiveReader(stream))
+ Import(archive);
+
+ currentDownloads.Remove(request);
+ };
+
+ request.Failure += data =>
+ {
+ downloadNotification.State = ProgressNotificationState.Completed;
+ Logger.Error(data, "Failed to get beatmap download information");
+ currentDownloads.Remove(request);
+ };
+
+ downloadNotification.CancelRequested += () =>
+ {
+ request.Cancel();
+ currentDownloads.Remove(request);
+ downloadNotification.State = ProgressNotificationState.Cancelled;
+ return true;
+ };
+
+ currentDownloads.Add(request);
+ PostNotification?.Invoke(downloadNotification);
+
+ // don't run in the main api queue as this is a long-running task.
+ Task.Run(() => request.Perform(api));
+
+ return request;
+ }
+
+ ///
+ /// Get an existing download request if it exists.
+ ///
+ /// The whose download request is wanted.
+ /// The object if it exists, or null.
+ public DownloadBeatmapSetRequest GetExistingDownload(BeatmapSetInfo beatmap) => currentDownloads.Find(d => d.BeatmapSet.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID);
+
///
/// Delete a beatmap from the manager.
/// Is a no-op for already deleted beatmaps.
diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs
index 479f274efb..ad0b110e48 100644
--- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs
@@ -7,7 +7,6 @@ using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
@@ -42,10 +41,7 @@ namespace osu.Game.Beatmaps
this.game = game;
}
- protected override Beatmap GetBeatmap() => new Beatmap
- {
- HitObjects = new List(),
- };
+ protected override Beatmap GetBeatmap() => new Beatmap();
protected override Texture GetBackground() => game.Textures.Get(@"Backgrounds/bg4");
@@ -59,8 +55,6 @@ namespace osu.Game.Beatmaps
{
public override IEnumerable GetModsFor(ModType type) => new Mod[] { };
- public override Mod GetAutoplayMod() => new ModAutoplay();
-
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset)
{
throw new NotImplementedException();
diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
index 234d65eee4..81695c3b5a 100644
--- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using osu.Game.Rulesets.Objects;
namespace osu.Game.Beatmaps.Formats
{
@@ -21,7 +20,7 @@ namespace osu.Game.Beatmaps.Formats
{
string line;
do { line = stream.ReadLine()?.Trim(); }
- while (line != null && line.Length == 0);
+ while (line != null && line.Length == 0);
if (line == null || !decoders.ContainsKey(line))
throw new IOException(@"Unknown file format");
@@ -47,7 +46,6 @@ namespace osu.Game.Beatmaps.Formats
{
var beatmap = new Beatmap
{
- HitObjects = new List(),
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata(),
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 462f94ed7c..df8e7f5e3b 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps
{
if (beatmap != null) return beatmap;
- beatmap = GetBeatmap();
+ beatmap = GetBeatmap() ?? new Beatmap();
// use the database-backed info.
beatmap.BeatmapInfo = BeatmapInfo;
@@ -87,7 +87,9 @@ namespace osu.Game.Beatmaps
{
if (track != null) return track;
- track = GetTrack();
+ // we want to ensure that we always have a track, even if it's a fake one.
+ track = GetTrack() ?? new TrackVirtual();
+
applyRateAdjustments();
return track;
}
@@ -107,10 +109,17 @@ namespace osu.Game.Beatmaps
public virtual void Dispose()
{
- track?.Dispose();
- track = null;
background?.Dispose();
background = null;
}
+
+ public void DisposeTrack()
+ {
+ lock (trackLock)
+ {
+ track?.Dispose();
+ track = null;
+ }
+ }
}
}
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index ea02feef0e..053ed9c191 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -131,7 +131,7 @@ namespace osu.Game.Graphics.Cursor
},
AdditiveLayer = new Sprite
{
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Colour = colour.Pink,
Alpha = 0,
Texture = textures.Get(@"Cursor/menu-cursor-additive"),
diff --git a/osu.Game/Graphics/SpriteIcon.cs b/osu.Game/Graphics/SpriteIcon.cs
index d49814952c..d4f9127d54 100644
--- a/osu.Game/Graphics/SpriteIcon.cs
+++ b/osu.Game/Graphics/SpriteIcon.cs
@@ -57,6 +57,12 @@ namespace osu.Game.Graphics
private void load(FontStore store)
{
this.store = store;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
updateTexture();
}
diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs
index 1cbf77d8f2..289ccbf5cd 100644
--- a/osu.Game/Graphics/UserInterface/DialogButton.cs
+++ b/osu.Game/Graphics/UserInterface/DialogButton.cs
@@ -99,7 +99,8 @@ namespace osu.Game.Graphics.UserInterface
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, Easing.In);
flash();
- this.Delay(click_duration).Schedule(delegate {
+ this.Delay(click_duration).Schedule(delegate
+ {
colourContainer.ResizeTo(new Vector2(0.8f, 1f));
spriteText.Spacing = Vector2.Zero;
glowContainer.FadeOut();
@@ -140,7 +141,7 @@ namespace osu.Game.Graphics.UserInterface
colourContainer.Add(flash);
flash.Colour = ButtonColour;
- flash.BlendingMode = BlendingMode.Additive;
+ flash.Blending = BlendingMode.Additive;
flash.Alpha = 0.3f;
flash.FadeOutFromOne(click_duration);
flash.Expire();
diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs
index abc1b036bc..32a37a4910 100644
--- a/osu.Game/Graphics/UserInterface/OsuButton.cs
+++ b/osu.Game/Graphics/UserInterface/OsuButton.cs
@@ -63,7 +63,7 @@ namespace osu.Game.Graphics.UserInterface
hover = new Box
{
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Colour = Color4.White.Opacity(0.1f),
Alpha = 0,
},
diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
index b69186e8b0..f605804aaa 100644
--- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs
+++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
@@ -96,7 +96,7 @@ namespace osu.Game.Graphics.UserInterface
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour };
#region DrawableOsuDropdownMenuItem
- protected class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour
+ public class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour
{
private Color4? accentColour;
public Color4 AccentColour
diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs
index 103155dd1f..3fd5481152 100644
--- a/osu.Game/Graphics/UserInterface/OsuMenu.cs
+++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs
@@ -18,8 +18,8 @@ namespace osu.Game.Graphics.UserInterface
{
public class OsuMenu : Menu
{
- public OsuMenu(Direction direction)
- : base(direction)
+ public OsuMenu(Direction direction, bool topLevelMenu = false)
+ : base(direction, topLevelMenu)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
@@ -46,6 +46,11 @@ namespace osu.Game.Graphics.UserInterface
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item);
+ protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical)
+ {
+ Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight
+ };
+
protected class DrawableOsuMenuItem : DrawableMenuItem
{
private const int margin_horizontal = 17;
@@ -61,7 +66,6 @@ namespace osu.Game.Graphics.UserInterface
public DrawableOsuMenuItem(MenuItem item)
: base(item)
{
-
}
[BackgroundDependencyLoader]
@@ -114,9 +118,10 @@ namespace osu.Game.Graphics.UserInterface
return base.OnClick(state);
}
- protected override Drawable CreateContent() => text = new TextContainer();
+ protected sealed override Drawable CreateContent() => text = CreateTextContainer();
+ protected virtual TextContainer CreateTextContainer() => new TextContainer();
- private class TextContainer : Container, IHasText
+ protected class TextContainer : Container, IHasText
{
public string Text
{
diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
index 4c108e793a..8c777f491b 100644
--- a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
+++ b/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
@@ -15,11 +15,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
{
private readonly VolumeMeter volumeMeterMaster;
- private void volumeChanged(double newVolume)
- {
- Show();
- schedulePopOut();
- }
+ protected override bool BlockPassThroughMouse => false;
public VolumeControl()
{
@@ -85,6 +81,12 @@ namespace osu.Game.Graphics.UserInterface.Volume
return false;
}
+ private void volumeChanged(double newVolume)
+ {
+ Show();
+ schedulePopOut();
+ }
+
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
diff --git a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs
new file mode 100644
index 0000000000..5a9f609bca
--- /dev/null
+++ b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs
@@ -0,0 +1,24 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Beatmaps;
+using System;
+
+namespace osu.Game.Online.API.Requests
+{
+ public class DownloadBeatmapSetRequest : APIDownloadRequest
+ {
+ public readonly BeatmapSetInfo BeatmapSet;
+
+ public Action DownloadProgressed;
+
+ public DownloadBeatmapSetRequest(BeatmapSetInfo set)
+ {
+ BeatmapSet = set;
+
+ Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total);
+ }
+
+ protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download";
+ }
+}
diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs
index 966049429e..ef9ee85d25 100644
--- a/osu.Game/Online/API/Requests/GetScoresRequest.cs
+++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs
@@ -1,10 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
using osu.Game.Beatmaps;
+using osu.Game.Users;
+using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Online.API.Requests
@@ -16,6 +20,14 @@ namespace osu.Game.Online.API.Requests
public GetScoresRequest(BeatmapInfo beatmap)
{
this.beatmap = beatmap;
+
+ Success += onSuccess;
+ }
+
+ private void onSuccess(GetScoresResponse r)
+ {
+ foreach (OnlineScore score in r.Scores)
+ score.ApplyBeatmap(beatmap);
}
protected override WebRequest CreateWebRequest()
@@ -32,6 +44,88 @@ namespace osu.Game.Online.API.Requests
public class GetScoresResponse
{
[JsonProperty(@"scores")]
- public IEnumerable Scores;
+ public IEnumerable Scores;
}
-}
\ No newline at end of file
+
+ public class OnlineScore : Score
+ {
+ [JsonProperty(@"score")]
+ private double totalScore
+ {
+ set { TotalScore = value; }
+ }
+
+ [JsonProperty(@"max_combo")]
+ private int maxCombo
+ {
+ set { MaxCombo = value; }
+ }
+
+ [JsonProperty(@"user")]
+ private User user
+ {
+ set { User = value; }
+ }
+
+ [JsonProperty(@"replay_data")]
+ private Replay replay
+ {
+ set { Replay = value; }
+ }
+
+ [JsonProperty(@"score_id")]
+ private long onlineScoreID
+ {
+ set { OnlineScoreID = value; }
+ }
+
+ [JsonProperty(@"created_at")]
+ private DateTimeOffset date
+ {
+ set { Date = value; }
+ }
+
+ [JsonProperty(@"statistics")]
+ private Dictionary jsonStats
+ {
+ set
+ {
+ foreach (var kvp in value)
+ {
+ string key = kvp.Key;
+ switch (key)
+ {
+ case @"count_300":
+ key = @"300";
+ break;
+ case @"count_100":
+ key = @"100";
+ break;
+ case @"count_50":
+ key = @"50";
+ break;
+ case @"count_miss":
+ key = @"x";
+ break;
+ default:
+ continue;
+ }
+
+ Statistics.Add(key, kvp.Value);
+ }
+ }
+ }
+
+ [JsonProperty(@"mods")]
+ private string[] modStrings { get; set; }
+
+ public void ApplyBeatmap(BeatmapInfo beatmap)
+ {
+ Beatmap = beatmap;
+ Ruleset = beatmap.Ruleset;
+
+ // Evaluate the mod string
+ Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray();
+ }
+ }
+}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index c020675881..b4fbdfb252 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -245,7 +245,11 @@ namespace osu.Game
LoadComponentAsync(Toolbar = new Toolbar
{
Depth = -4,
- OnHome = delegate { intro?.ChildScreen?.MakeCurrent(); },
+ OnHome = delegate
+ {
+ hideAllOverlays();
+ intro?.ChildScreen?.MakeCurrent();
+ },
}, overlayContent.Add);
settings.StateChanged += delegate
@@ -310,6 +314,16 @@ namespace osu.Game
private OsuScreen currentScreen;
private FrameworkConfigManager frameworkConfig;
+ private void hideAllOverlays()
+ {
+ settings.State = Visibility.Hidden;
+ chat.State = Visibility.Hidden;
+ direct.State = Visibility.Hidden;
+ social.State = Visibility.Hidden;
+ userProfile.State = Visibility.Hidden;
+ notificationOverlay.State = Visibility.Hidden;
+ }
+
private void screenChanged(Screen newScreen)
{
currentScreen = newScreen as OsuScreen;
@@ -323,19 +337,12 @@ namespace osu.Game
//central game screen change logic.
if (!currentScreen.ShowOverlays)
{
- settings.State = Visibility.Hidden;
- Toolbar.State = Visibility.Hidden;
+ hideAllOverlays();
musicController.State = Visibility.Hidden;
- chat.State = Visibility.Hidden;
- direct.State = Visibility.Hidden;
- social.State = Visibility.Hidden;
- userProfile.State = Visibility.Hidden;
- notificationOverlay.State = Visibility.Hidden;
+ Toolbar.State = Visibility.Hidden;
}
else
- {
Toolbar.State = Visibility.Visible;
- }
ScreenChanged?.Invoke(newScreen);
}
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index a7136ce803..d81c7cdf73 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -106,9 +106,15 @@ namespace osu.Game
connection.CreateTable();
+ dependencies.Cache(API = new APIAccess
+ {
+ Username = LocalConfig.Get(OsuSetting.Username),
+ Token = LocalConfig.Get(OsuSetting.Token)
+ });
+
dependencies.Cache(RulesetStore = new RulesetStore(connection));
dependencies.Cache(FileStore = new FileStore(connection, Host.Storage));
- dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host));
+ dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, API, Host));
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager, RulesetStore));
dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore));
dependencies.Cache(new OsuColour());
@@ -144,18 +150,21 @@ namespace osu.Game
Beatmap = new NonNullableBindable(defaultBeatmap);
BeatmapManager.DefaultBeatmap = defaultBeatmap;
- dependencies.Cache(API = new APIAccess
- {
- Username = LocalConfig.Get(OsuSetting.Username),
- Token = LocalConfig.Get(OsuSetting.Token)
- });
-
Beatmap.ValueChanged += b =>
{
+ var trackLoaded = lastBeatmap?.TrackLoaded ?? false;
+
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
- if (lastBeatmap?.Track != b.Track)
+ if (!trackLoaded || lastBeatmap?.Track != b.Track)
{
- lastBeatmap?.Track?.Dispose();
+ if (trackLoaded)
+ {
+ Debug.Assert(lastBeatmap != null);
+ Debug.Assert(lastBeatmap.Track != null);
+
+ lastBeatmap.DisposeTrack();
+ }
+
Audio.Track.AddItem(b.Track);
}
diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelListItem.cs
index f43154ea20..8360e793d8 100644
--- a/osu.Game/Overlays/Chat/ChannelListItem.cs
+++ b/osu.Game/Overlays/Chat/ChannelListItem.cs
@@ -76,7 +76,6 @@ namespace osu.Game.Overlays.Chat
Size = new Vector2(text_size),
Shadow = false,
Margin = new MarginPadding { Right = 10f },
- Alpha = 0f,
},
},
},
@@ -109,7 +108,6 @@ namespace osu.Game.Overlays.Chat
TextSize = text_size,
Font = @"Exo2.0-SemiBold",
Shadow = false,
- Alpha = 0.8f,
},
},
},
@@ -151,6 +149,9 @@ namespace osu.Game.Overlays.Chat
joinedBind.ValueChanged += updateColour;
joinedBind.BindTo(channel.Joined);
+
+ joinedBind.TriggerChange();
+ FinishTransforms(true);
}
protected override bool OnHover(InputState state)
diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs
index a642f72821..6f1f581d0b 100644
--- a/osu.Game/Overlays/Direct/DirectPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectPanel.cs
@@ -4,8 +4,6 @@
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
-using System.IO;
-using System.Threading.Tasks;
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -20,8 +18,8 @@ using osu.Framework.Input;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Framework.Logging;
-using osu.Game.Beatmaps.IO;
using osu.Game.Overlays.Notifications;
+using osu.Game.Online.API.Requests;
namespace osu.Game.Overlays.Direct
{
@@ -97,6 +95,11 @@ namespace osu.Game.Overlays.Direct
},
}
});
+
+ var downloadRequest = beatmaps.GetExistingDownload(SetInfo);
+
+ if (downloadRequest != null)
+ attachDownload(downloadRequest);
}
protected override bool OnHover(InputState state)
@@ -115,23 +118,8 @@ namespace osu.Game.Overlays.Direct
base.OnHoverLost(state);
}
- // this should eventually be moved to a more central place, like BeatmapManager.
- private DownloadBeatmapSetRequest downloadRequest;
-
protected void StartDownload()
{
- if (api == null) return;
-
- // we already have an active download running.
- if (downloadRequest != null)
- {
- content.MoveToX(-5, 50, Easing.OutSine).Then()
- .MoveToX(5, 100, Easing.InOutSine).Then()
- .MoveToX(-5, 100, Easing.InOutSine).Then()
- .MoveToX(0, 50, Easing.InSine).Then();
- return;
- }
-
if (!api.LocalUser.Value.IsSupporter)
{
notifications.Post(new SimpleNotification
@@ -142,72 +130,43 @@ namespace osu.Game.Overlays.Direct
return;
}
+ if (beatmaps.GetExistingDownload(SetInfo) != null)
+ {
+ // we already have an active download running.
+ content.MoveToX(-5, 50, Easing.OutSine).Then()
+ .MoveToX(5, 100, Easing.InOutSine).Then()
+ .MoveToX(-5, 100, Easing.InOutSine).Then()
+ .MoveToX(0, 50, Easing.InSine).Then();
+
+ return;
+ }
+
+ var request = beatmaps.Download(SetInfo);
+
+ attachDownload(request);
+ }
+
+ private void attachDownload(DownloadBeatmapSetRequest request)
+ {
progressBar.FadeIn(400, Easing.OutQuint);
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
progressBar.Current.Value = 0;
- ProgressNotification downloadNotification = new ProgressNotification
- {
- Text = $"Downloading {SetInfo.Metadata.Artist} - {SetInfo.Metadata.Title}",
- };
-
- downloadRequest = new DownloadBeatmapSetRequest(SetInfo);
- downloadRequest.Failure += e =>
+ request.Failure += e =>
{
progressBar.Current.Value = 0;
progressBar.FadeOut(500);
- downloadNotification.State = ProgressNotificationState.Completed;
Logger.Error(e, "Failed to get beatmap download information");
-
- downloadRequest = null;
};
- downloadRequest.Progress += (current, total) =>
- {
- float progress = (float)current / total;
+ request.DownloadProgressed += progress => progressBar.Current.Value = progress;
- progressBar.Current.Value = progress;
-
- downloadNotification.State = ProgressNotificationState.Active;
- downloadNotification.Progress = progress;
- };
-
- downloadRequest.Success += data =>
+ request.Success += data =>
{
progressBar.Current.Value = 1;
progressBar.FadeOut(500);
-
- downloadNotification.State = ProgressNotificationState.Completed;
-
- using (var stream = new MemoryStream(data))
- using (var archive = new OszArchiveReader(stream))
- beatmaps.Import(archive);
};
-
- downloadNotification.CancelRequested += () =>
- {
- downloadRequest.Cancel();
- downloadRequest = null;
- return true;
- };
-
- notifications.Post(downloadNotification);
-
- // don't run in the main api queue as this is a long-running task.
- Task.Run(() => downloadRequest.Perform(api));
- }
-
- public class DownloadBeatmapSetRequest : APIDownloadRequest
- {
- private readonly BeatmapSetInfo beatmapSet;
-
- public DownloadBeatmapSetRequest(BeatmapSetInfo beatmapSet)
- {
- this.beatmapSet = beatmapSet;
- }
-
- protected override string Target => $@"beatmapsets/{beatmapSet.OnlineBeatmapSetID}/download";
}
protected override void LoadComplete()
diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs
index f734e43826..9c07e1087f 100644
--- a/osu.Game/Overlays/DirectOverlay.cs
+++ b/osu.Game/Overlays/DirectOverlay.cs
@@ -27,6 +27,7 @@ namespace osu.Game.Overlays
private APIAccess api;
private RulesetStore rulesets;
+ private BeatmapManager beatmaps;
private readonly FillFlowContainer resultCountsContainer;
private readonly OsuSpriteText resultCountsText;
@@ -46,9 +47,26 @@ namespace osu.Game.Overlays
set
{
if (beatmapSets?.Equals(value) ?? false) return;
+
beatmapSets = value;
- recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
+ if (beatmapSets == null) return;
+
+ var artists = new List();
+ var songs = new List();
+ var tags = new List();
+ foreach (var s in beatmapSets)
+ {
+ artists.Add(s.Metadata.Artist);
+ songs.Add(s.Metadata.Title);
+ tags.AddRange(s.Metadata.Tags.Split(' '));
+ }
+
+ ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags));
+
+ if (beatmapSets.Any() && panels == null)
+ // real use case? currently only seems to be for test case
+ recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
}
}
@@ -147,6 +165,8 @@ namespace osu.Game.Overlays
{
this.api = api;
this.rulesets = rulesets;
+ this.beatmaps = beatmaps;
+
resultCountsContainer.Colour = colours.Yellow;
beatmaps.BeatmapSetAdded += setAdded;
@@ -156,6 +176,7 @@ namespace osu.Game.Overlays
{
// if a new map was imported, we should remove it from search results (download completed etc.)
panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire();
+ BeatmapSets = BeatmapSets?.Where(b => b.OnlineBeatmapSetID != set.OnlineBeatmapSetID);
}
private void updateResultCounts()
@@ -237,20 +258,11 @@ namespace osu.Game.Overlays
getSetsRequest.Success += r =>
{
- BeatmapSets = r?.Select(response => response.ToBeatmapSet(rulesets));
- if (BeatmapSets == null) return;
+ BeatmapSets = r?.
+ Select(response => response.ToBeatmapSet(rulesets)).
+ Where(b => beatmaps.QueryBeatmapSet(q => q.OnlineBeatmapSetID == b.OnlineBeatmapSetID) == null);
- var artists = new List();
- var songs = new List();
- var tags = new List();
- foreach (var s in BeatmapSets)
- {
- artists.Add(s.Metadata.Artist);
- songs.Add(s.Metadata.Title);
- tags.AddRange(s.Metadata.Tags.Split(' '));
- }
-
- ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags));
+ recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
};
api.Queue(getSetsRequest);
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 0a06439c3e..64d0d628f0 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -302,8 +302,8 @@ namespace osu.Game.Overlays
else
{
//figure out the best direction based on order in playlist.
- var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
- var next = beatmap == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmap.BeatmapSetInfo.ID).Count();
+ var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count();
+ var next = beatmap == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmap.BeatmapSetInfo?.ID).Count();
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
}
diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs
index 7af7363dda..b39c8ab7cf 100644
--- a/osu.Game/Overlays/Settings/SidebarButton.cs
+++ b/osu.Game/Overlays/Settings/SidebarButton.cs
@@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Settings
backgroundBox = new Box
{
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Colour = OsuColour.Gray(60),
Alpha = 0,
},
diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs
index f2df2721d3..cb17216679 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs
@@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Toolbar
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(80).Opacity(180),
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Alpha = 0,
},
Flow = new FillFlowContainer
diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs
index c530e8d7ff..28ecf6ad03 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Toolbar
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(150).Opacity(180),
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Depth = 2,
Alpha = 0,
});
diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs
index f0a53d677b..12edfd802a 100644
--- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs
+++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs
@@ -16,11 +16,9 @@ namespace osu.Game.Rulesets.Judgements
///
/// A drawable object which visualises the hit result of a .
///
- /// The type of judgement to visualise.
- public class DrawableJudgement : Container
- where TJudgement : Judgement
+ public class DrawableJudgement : Container
{
- protected readonly TJudgement Judgement;
+ protected readonly Judgement Judgement;
protected readonly SpriteText JudgementText;
@@ -28,21 +26,19 @@ namespace osu.Game.Rulesets.Judgements
/// Creates a drawable which visualises a .
///
/// The judgement to visualise.
- public DrawableJudgement(TJudgement judgement)
+ public DrawableJudgement(Judgement judgement)
{
Judgement = judgement;
AutoSizeAxes = Axes.Both;
- string resultString = judgement.Result == HitResult.Hit ? judgement.ResultString : judgement.Result.GetDescription();
-
Children = new[]
{
JudgementText = new OsuSpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Text = resultString.ToUpper(),
+ Text = judgement.Result.GetDescription().ToUpper(),
Font = @"Venera",
TextSize = 16
}
@@ -68,6 +64,8 @@ namespace osu.Game.Rulesets.Judgements
switch (Judgement.Result)
{
+ case HitResult.None:
+ break;
case HitResult.Miss:
this.ScaleTo(1.6f);
this.ScaleTo(1, 100, Easing.In);
@@ -77,7 +75,7 @@ namespace osu.Game.Rulesets.Judgements
this.Delay(600).FadeOut(200);
break;
- case HitResult.Hit:
+ default:
this.ScaleTo(0.9f);
this.ScaleTo(1, 500, Easing.OutElastic);
diff --git a/osu.Game/Rulesets/Judgements/IPartialJudgement.cs b/osu.Game/Rulesets/Judgements/IPartialJudgement.cs
deleted file mode 100644
index 38080835e0..0000000000
--- a/osu.Game/Rulesets/Judgements/IPartialJudgement.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Rulesets.Judgements
-{
- ///
- /// Inidicates that the judgement this is attached to is a partial judgement and the scoring value may change.
- ///
- public interface IPartialJudgement
- {
- ///
- /// Indicates that this partial judgement has changed and requires reprocessing.
- ///
- /// This is set to false once the judgement has been re-processed.
- ///
- ///
- bool Changed { get; set; }
- }
-}
diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs
index ed33cee5d4..29cd3ff384 100644
--- a/osu.Game/Rulesets/Judgements/Judgement.cs
+++ b/osu.Game/Rulesets/Judgements/Judgement.cs
@@ -5,7 +5,7 @@ using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Judgements
{
- public abstract class Judgement
+ public class Judgement
{
///
/// Whether this judgement is the result of a hit or a miss.
@@ -13,20 +13,35 @@ namespace osu.Game.Rulesets.Judgements
public HitResult Result;
///
- /// The offset at which this judgement occurred.
+ /// The maximum that can be achieved.
///
- public double TimeOffset;
+ public virtual HitResult MaxResult => HitResult.Perfect;
+
+ public bool IsHit => Result > HitResult.Miss;
+
+ ///
+ /// The offset from a perfect hit at which this judgement occurred.
+ /// Populated when added via .
+ ///
+ public double TimeOffset { get; internal set; }
public virtual bool AffectsCombo => true;
///
- /// The string representation for the result achieved.
+ /// The numeric representation for the result achieved.
///
- public abstract string ResultString { get; }
+ public int NumericResult => NumericResultFor(Result);
///
- /// The string representation for the max result achievable.
+ /// The numeric representation for the maximum achievable result.
///
- public abstract string MaxResultString { get; }
+ public int MaxNumericResult => NumericResultFor(MaxResult);
+
+ ///
+ /// Convert a to a numeric score representation.
+ ///
+ /// The value to convert.
+ /// The number.
+ protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0;
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs
index f54267af29..7b0034863e 100644
--- a/osu.Game/Rulesets/Mods/Mod.cs
+++ b/osu.Game/Rulesets/Mods/Mod.cs
@@ -16,6 +16,11 @@ namespace osu.Game.Rulesets.Mods
///
public abstract string Name { get; }
+ ///
+ /// The shortened name of this mod.
+ ///
+ public abstract string ShortenedName { get; }
+
///
/// The icon of this mod.
///
diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs
index ca120e446e..ece0deba84 100644
--- a/osu.Game/Rulesets/Mods/ModAutoplay.cs
+++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs
@@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mods
{
protected abstract Score CreateReplayScore(Beatmap beatmap);
- public void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ public virtual void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
{
rulesetContainer.SetReplay(CreateReplayScore(rulesetContainer.Beatmap)?.Replay);
}
@@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Mods
public class ModAutoplay : Mod
{
public override string Name => "Autoplay";
+ public override string ShortenedName => "AT";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
public override string Description => "Watch a perfect automated play through the song";
public override double ScoreMultiplier => 0;
diff --git a/osu.Game/Rulesets/Mods/ModCinema.cs b/osu.Game/Rulesets/Mods/ModCinema.cs
index 332bd2c5ac..581fbc5e3a 100644
--- a/osu.Game/Rulesets/Mods/ModCinema.cs
+++ b/osu.Game/Rulesets/Mods/ModCinema.cs
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mods
public class ModCinema : ModAutoplay
{
public override string Name => "Cinema";
+ public override string ShortenedName => "CN";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_cinema;
}
}
\ No newline at end of file
diff --git a/osu.Game/Rulesets/Mods/ModDaycore.cs b/osu.Game/Rulesets/Mods/ModDaycore.cs
index 3e878d7104..cbad224316 100644
--- a/osu.Game/Rulesets/Mods/ModDaycore.cs
+++ b/osu.Game/Rulesets/Mods/ModDaycore.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModDaycore : ModHalfTime
{
public override string Name => "Daycore";
+ public override string ShortenedName => "DC";
public override FontAwesome Icon => FontAwesome.fa_question;
public override string Description => "whoaaaaa";
diff --git a/osu.Game/Rulesets/Mods/ModDoubleTime.cs b/osu.Game/Rulesets/Mods/ModDoubleTime.cs
index 1aab56a9fc..d8aa5ea1d2 100644
--- a/osu.Game/Rulesets/Mods/ModDoubleTime.cs
+++ b/osu.Game/Rulesets/Mods/ModDoubleTime.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
public class ModDoubleTime : Mod, IApplicableToClock
{
public override string Name => "Double Time";
+ public override string ShortenedName => "DT";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_doubletime;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Zoooooooooom";
diff --git a/osu.Game/Rulesets/Mods/ModEasy.cs b/osu.Game/Rulesets/Mods/ModEasy.cs
index 075a62b0d7..aaf083fd9e 100644
--- a/osu.Game/Rulesets/Mods/ModEasy.cs
+++ b/osu.Game/Rulesets/Mods/ModEasy.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModEasy : Mod, IApplicableToDifficulty
{
public override string Name => "Easy";
+ public override string ShortenedName => "EZ";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_easy;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required.";
diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs
index b5ad859172..b7499e624a 100644
--- a/osu.Game/Rulesets/Mods/ModFlashlight.cs
+++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModFlashlight : Mod
{
public override string Name => "Flashlight";
+ public override string ShortenedName => "FL";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Restricted view area.";
diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs
index 14aede0809..a9e49bb4b0 100644
--- a/osu.Game/Rulesets/Mods/ModHalfTime.cs
+++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModHalfTime : Mod, IApplicableToClock
{
public override string Name => "Half Time";
+ public override string ShortenedName => "HT";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_halftime;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => "Less zoom";
diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs
index f33f46a207..36d82362e3 100644
--- a/osu.Game/Rulesets/Mods/ModHardRock.cs
+++ b/osu.Game/Rulesets/Mods/ModHardRock.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModHardRock : Mod, IApplicableToDifficulty
{
public override string Name => "Hard Rock";
+ public override string ShortenedName => "HR";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hardrock;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Everything just got a bit harder...";
diff --git a/osu.Game/Rulesets/Mods/ModHidden.cs b/osu.Game/Rulesets/Mods/ModHidden.cs
index 89b9b3b62d..25f6ad024d 100644
--- a/osu.Game/Rulesets/Mods/ModHidden.cs
+++ b/osu.Game/Rulesets/Mods/ModHidden.cs
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModHidden : Mod
{
public override string Name => "Hidden";
+ public override string ShortenedName => "HD";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease;
public override bool Ranked => true;
diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs
index d04643fb8b..5cefd89023 100644
--- a/osu.Game/Rulesets/Mods/ModNightcore.cs
+++ b/osu.Game/Rulesets/Mods/ModNightcore.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModNightcore : ModDoubleTime
{
public override string Name => "Nightcore";
+ public override string ShortenedName => "NC";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nightcore;
public override string Description => "uguuuuuuuu";
diff --git a/osu.Game/Rulesets/Mods/ModNoFail.cs b/osu.Game/Rulesets/Mods/ModNoFail.cs
index d41c4e3956..3a3878d77e 100644
--- a/osu.Game/Rulesets/Mods/ModNoFail.cs
+++ b/osu.Game/Rulesets/Mods/ModNoFail.cs
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModNoFail : Mod
{
public override string Name => "NoFail";
+ public override string ShortenedName => "NF";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => "You can't fail, no matter what.";
diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs
index 35217c8305..082370ea5d 100644
--- a/osu.Game/Rulesets/Mods/ModPerfect.cs
+++ b/osu.Game/Rulesets/Mods/ModPerfect.cs
@@ -6,6 +6,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModPerfect : ModSuddenDeath
{
public override string Name => "Perfect";
+ public override string ShortenedName => "PF";
public override string Description => "SS or quit.";
}
}
\ No newline at end of file
diff --git a/osu.Game/Rulesets/Mods/ModRelax.cs b/osu.Game/Rulesets/Mods/ModRelax.cs
index 5491f8fc58..a3f38e4ff6 100644
--- a/osu.Game/Rulesets/Mods/ModRelax.cs
+++ b/osu.Game/Rulesets/Mods/ModRelax.cs
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModRelax : Mod
{
public override string Name => "Relax";
+ public override string ShortenedName => "RX";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax;
public override double ScoreMultiplier => 0;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) };
diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs
index 2bf0278046..999cb40f89 100644
--- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs
+++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
public abstract class ModSuddenDeath : Mod
{
public override string Name => "Sudden Death";
+ public override string ShortenedName => "SD";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_suddendeath;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Miss a note and fail.";
diff --git a/osu.Game/Rulesets/Mods/MultiMod.cs b/osu.Game/Rulesets/Mods/MultiMod.cs
index c5fac250d0..c40d107bda 100644
--- a/osu.Game/Rulesets/Mods/MultiMod.cs
+++ b/osu.Game/Rulesets/Mods/MultiMod.cs
@@ -6,6 +6,7 @@ namespace osu.Game.Rulesets.Mods
public class MultiMod : Mod
{
public override string Name => string.Empty;
+ public override string ShortenedName => string.Empty;
public override string Description => string.Empty;
public override double ScoreMultiplier => 0.0;
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 3fba168216..7cf098c3fa 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -12,17 +12,18 @@ using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics;
using osu.Game.Audio;
using System.Linq;
+using osu.Game.Graphics;
namespace osu.Game.Rulesets.Objects.Drawables
{
- public abstract class DrawableHitObject : Container
+ public abstract class DrawableHitObject : Container, IHasAccentColour
{
public readonly HitObject HitObject;
///
/// The colour used for various elements of this DrawableHitObject.
///
- public virtual Color4 AccentColour { get; set; }
+ public virtual Color4 AccentColour { get; set; } = Color4.Gray;
protected DrawableHitObject(HitObject hitObject)
{
@@ -33,32 +34,29 @@ namespace osu.Game.Rulesets.Objects.Drawables
public abstract class DrawableHitObject : DrawableHitObject
where TObject : HitObject
{
+ public event Action OnJudgement;
+
public new readonly TObject HitObject;
- protected DrawableHitObject(TObject hitObject)
- : base(hitObject)
- {
- HitObject = hitObject;
- }
- }
-
- public abstract class DrawableHitObject : DrawableHitObject
- where TObject : HitObject
- where TJudgement : Judgement
- {
- public event Action> OnJudgement;
-
public override bool HandleInput => Interactive;
-
public bool Interactive = true;
- public TJudgement Judgement;
+ ///
+ /// Whether this can be judged.
+ ///
+ protected virtual bool ProvidesJudgement => true;
+
+ private readonly List judgements = new List();
+ public IReadOnlyList Judgements => judgements;
protected List Samples = new List();
protected DrawableHitObject(TObject hitObject)
: base(hitObject)
{
+ HitObject = hitObject;
+
+ Depth = (float)hitObject.StartTime;
}
private ArmedState state;
@@ -95,69 +93,80 @@ namespace osu.Game.Rulesets.Objects.Drawables
UpdateState(State);
}
- ///
- /// Whether this hit object and all of its nested hit objects have been judged.
- ///
- public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
+ private bool hasJudgementResult;
+ private bool judgementOccurred;
///
- /// Process a hit of this hitobject. Carries out judgement.
+ /// Whether this and all of its nested s have been judged.
///
- /// Whether a hit was processed.
- protected bool UpdateJudgement(bool userTriggered)
+ public virtual bool AllJudged => (!ProvidesJudgement || hasJudgementResult) && (NestedHitObjects?.All(h => h.AllJudged) ?? true);
+
+ ///
+ /// Notifies that a new judgement has occurred for this .
+ ///
+ /// The .
+ protected void AddJudgement(Judgement judgement)
{
- if (Judgement == null)
- return false;
+ hasJudgementResult = judgement.Result >= HitResult.Miss;
+ judgementOccurred = true;
- var partial = Judgement as IPartialJudgement;
+ // Ensure that the judgement is given a valid time offset, because this may not get set by the caller
+ var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
+ judgement.TimeOffset = Time.Current - endTime;
- // Never re-process non-partial hits
- if (Judgement.Result != HitResult.None && partial == null)
- return false;
+ judgements.Add(judgement);
- // Update the judgement state
- double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
- Judgement.TimeOffset = Time.Current - endTime;
-
- // Update the judgement state
- bool hadResult = Judgement.Result != HitResult.None;
- CheckJudgement(userTriggered);
-
- // Don't process judgements with no result
- if (Judgement.Result == HitResult.None)
- return false;
-
- // Don't process judgements that previously had results but the results were unchanged
- if (hadResult && partial?.Changed != true)
- return false;
-
- switch (Judgement.Result)
+ switch (judgement.Result)
{
- default:
- State = ArmedState.Hit;
+ case HitResult.None:
break;
case HitResult.Miss:
State = ArmedState.Miss;
break;
+ default:
+ State = ArmedState.Hit;
+ break;
}
- OnJudgement?.Invoke(this);
-
- if (partial != null)
- partial.Changed = false;
-
- return true;
+ OnJudgement?.Invoke(this, judgement);
}
- protected virtual void CheckJudgement(bool userTriggered)
+ ///
+ /// Processes this , checking if any judgements have occurred.
+ ///
+ /// Whether the user triggered this process.
+ /// Whether a judgement has occurred from this or any nested s.
+ protected bool UpdateJudgement(bool userTriggered)
{
+ judgementOccurred = false;
+
+ if (AllJudged || State != ArmedState.Idle)
+ return false;
+
if (NestedHitObjects != null)
{
foreach (var d in NestedHitObjects)
- d.CheckJudgement(userTriggered);
+ judgementOccurred |= d.UpdateJudgement(userTriggered);
}
+
+ if (!ProvidesJudgement || hasJudgementResult || judgementOccurred)
+ return judgementOccurred;
+
+ var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
+ CheckForJudgements(userTriggered, Time.Current - endTime);
+
+ return judgementOccurred;
}
+ ///
+ /// Checks if any judgements have occurred for this . This method must construct
+ /// all s and notify of them through .
+ ///
+ /// Whether the user triggered this check.
+ /// The offset from the end time at which this check occurred. A > 0
+ /// implies that this check occurred after the end time of .
+ protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { }
+
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
@@ -178,25 +187,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
channel.Volume.Value = sample.Volume;
Samples.Add(channel);
}
-
- //we may be setting a custom judgement in test cases or what not.
- if (Judgement == null)
- Judgement = CreateJudgement();
}
- private List> nestedHitObjects;
- protected IEnumerable> NestedHitObjects => nestedHitObjects;
+ private List> nestedHitObjects;
+ protected IEnumerable> NestedHitObjects => nestedHitObjects;
- protected virtual void AddNested(DrawableHitObject h)
+ protected virtual void AddNested(DrawableHitObject h)
{
if (nestedHitObjects == null)
- nestedHitObjects = new List>();
+ nestedHitObjects = new List>();
- h.OnJudgement += d => OnJudgement?.Invoke(d);
+ h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j);
nestedHitObjects.Add(h);
}
- protected abstract TJudgement CreateJudgement();
protected abstract void UpdateState(ArmedState state);
}
}
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableScrollingHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableScrollingHitObject.cs
index a7c4dd0333..5ba9c2ff4d 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableScrollingHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableScrollingHitObject.cs
@@ -3,19 +3,17 @@
using osu.Framework.Configuration;
using osu.Framework.Graphics;
-using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Objects.Drawables
{
///
- /// A basic class that overrides and implements .
+ /// A basic class that overrides and implements .
/// This object does not need to have its set to be able to scroll, as this will
/// will be set by the scrolling container that contains it.
///
- public abstract class DrawableScrollingHitObject : DrawableHitObject, IScrollingHitObject
+ public abstract class DrawableScrollingHitObject : DrawableHitObject, IScrollingHitObject
where TObject : HitObject
- where TJudgement : Judgement
{
public BindableDouble LifetimeOffset { get; } = new BindableDouble();
@@ -57,7 +55,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
set { lifetimeEnd = value; }
}
- protected override void AddNested(DrawableHitObject h)
+ protected override void AddNested(DrawableHitObject h)
{
var scrollingHitObject = h as IScrollingHitObject;
scrollingHitObject?.LifetimeOffset.BindTo(LifetimeOffset);
diff --git a/osu.Game/Rulesets/Objects/Drawables/HitResult.cs b/osu.Game/Rulesets/Objects/Drawables/HitResult.cs
index 7492c0ab96..961843cbd7 100644
--- a/osu.Game/Rulesets/Objects/Drawables/HitResult.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/HitResult.cs
@@ -10,17 +10,34 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
/// Indicates that the object has not been judged yet.
///
- [Description("")]
+ [Description(@"")]
None,
+
///
/// Indicates that the object has been judged as a miss.
///
[Description(@"Miss")]
Miss,
+
+ [Description(@"Meh")]
+ Meh,
+
///
- /// Indicates that the object has been judged as a hit.
+ /// Optional judgement.
///
- [Description(@"Hit")]
- Hit,
+ [Description(@"OK")]
+ Ok,
+
+ [Description(@"Good")]
+ Good,
+
+ [Description(@"Great")]
+ Great,
+
+ ///
+ /// Optional judgement.
+ ///
+ [Description(@"Perfect")]
+ Perfect,
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs
index c343cdaf33..c69979d4cf 100644
--- a/osu.Game/Rulesets/Objects/HitObject.cs
+++ b/osu.Game/Rulesets/Objects/HitObject.cs
@@ -30,6 +30,11 @@ namespace osu.Game.Rulesets.Objects
///
public SampleInfoList Samples = new SampleInfoList();
+ ///
+ /// Whether this is in Kiai time.
+ ///
+ public bool Kiai { get; private set; }
+
///
/// Applies default values to this HitObject.
///
@@ -38,6 +43,9 @@ namespace osu.Game.Rulesets.Objects
public virtual void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime);
+ EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime);
+
+ Kiai |= effectPoint.KiaiMode;
// Initialize first sample
Samples.ForEach(s => initializeSampleInfo(s, soundPoint));
diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs
index c54aeb7852..33621662af 100644
--- a/osu.Game/Rulesets/Ruleset.cs
+++ b/osu.Game/Rulesets/Ruleset.cs
@@ -1,15 +1,17 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Beatmaps;
-using osu.Game.Graphics;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
+using System;
using System.Collections.Generic;
+using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
-using osu.Game.Rulesets.Scoring;
+using osu.Game.Beatmaps;
+using osu.Game.Graphics;
using osu.Game.Overlays.Settings;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets
{
@@ -19,9 +21,18 @@ namespace osu.Game.Rulesets
public virtual IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { };
+ public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).Cast()
+ // Get all mod types as an IEnumerable
+ .SelectMany(GetModsFor)
+ // Confine all mods of each mod type into a single IEnumerable
+ .Where(mod => mod != null)
+ // Filter out all null mods
+ .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
+ // Resolve MultiMods as their .Mods property
+
public abstract IEnumerable GetModsFor(ModType type);
- public abstract Mod GetAutoplayMod();
+ public Mod GetAutoplayMod() => GetAllMods().First(mod => mod is ModAutoplay);
protected Ruleset(RulesetInfo rulesetInfo)
{
diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs
index 00406ccf79..69ed9197d7 100644
--- a/osu.Game/Rulesets/Scoring/Score.cs
+++ b/osu.Game/Rulesets/Scoring/Score.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Users;
@@ -15,7 +14,6 @@ namespace osu.Game.Rulesets.Scoring
{
public ScoreRank Rank { get; set; }
- [JsonProperty(@"score")]
public double TotalScore { get; set; }
public double Accuracy { get; set; }
@@ -24,63 +22,24 @@ namespace osu.Game.Rulesets.Scoring
public double PP { get; set; }
- [JsonProperty(@"max_combo")]
public int MaxCombo { get; set; }
public int Combo { get; set; }
- [JsonProperty(@"mods")]
- protected string[] ModStrings { get; set; } //todo: parse to Mod objects
-
public RulesetInfo Ruleset { get; set; }
public Mod[] Mods { get; set; }
- [JsonProperty(@"user")]
public User User;
- [JsonProperty(@"replay_data")]
public Replay Replay;
public BeatmapInfo Beatmap;
- [JsonProperty(@"score_id")]
public long OnlineScoreID;
- [JsonProperty(@"created_at")]
public DateTimeOffset Date;
- [JsonProperty(@"statistics")]
- private Dictionary jsonStats
- {
- set
- {
- foreach (var kvp in value)
- {
- string key = kvp.Key;
- switch (key)
- {
- case @"count_300":
- key = @"300";
- break;
- case @"count_100":
- key = @"100";
- break;
- case @"count_50":
- key = @"50";
- break;
- case @"count_miss":
- key = @"x";
- break;
- default:
- continue;
- }
-
- Statistics.Add(key, kvp.Value);
- }
- }
- }
-
public Dictionary Statistics = new Dictionary();
}
}
diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
index 5ccac2db32..2ca733d82a 100644
--- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
@@ -135,14 +135,13 @@ namespace osu.Game.Rulesets.Scoring
}
}
- public abstract class ScoreProcessor : ScoreProcessor
+ public abstract class ScoreProcessor : ScoreProcessor
where TObject : HitObject
- where TJudgement : Judgement
{
///
/// All judgements held by this ScoreProcessor.
///
- protected readonly List Judgements = new List();
+ protected readonly List Judgements = new List();
public override bool HasFailed => Health.Value == Health.MinValue;
@@ -150,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring
{
}
- protected ScoreProcessor(RulesetContainer rulesetContainer)
+ protected ScoreProcessor(RulesetContainer rulesetContainer)
{
Judgements.Capacity = rulesetContainer.Beatmap.HitObjects.Count;
@@ -171,7 +170,7 @@ namespace osu.Game.Rulesets.Scoring
/// Adds a judgement to this ScoreProcessor.
///
/// The judgement to add.
- protected void AddJudgement(TJudgement judgement)
+ protected void AddJudgement(Judgement judgement)
{
bool exists = Judgements.Contains(judgement);
@@ -181,10 +180,12 @@ namespace osu.Game.Rulesets.Scoring
{
switch (judgement.Result)
{
+ case HitResult.None:
+ break;
case HitResult.Miss:
Combo.Value = 0;
break;
- case HitResult.Hit:
+ default:
Combo.Value++;
break;
}
@@ -195,8 +196,6 @@ namespace osu.Game.Rulesets.Scoring
NotifyNewJudgement(judgement);
}
- else
- OnJudgementChanged(judgement);
UpdateFailed();
}
@@ -210,20 +209,8 @@ namespace osu.Game.Rulesets.Scoring
///
/// Updates any values that need post-processing. Invoked when a new judgement has occurred.
- ///
- /// This is not triggered when existing judgements are changed - for that see .
- ///
///
/// The judgement that triggered this calculation.
- protected abstract void OnNewJudgement(TJudgement judgement);
-
- ///
- /// Updates any values that need post-processing. Invoked when an existing judgement has changed.
- ///
- /// This is not triggered when a new judgement has occurred - for that see .
- ///
- ///
- /// The judgement that triggered this calculation.
- protected virtual void OnJudgementChanged(TJudgement judgement) { }
+ protected abstract void OnNewJudgement(Judgement judgement);
}
}
diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs
index 986d8c92dc..47a39d4644 100644
--- a/osu.Game/Rulesets/UI/ModIcon.cs
+++ b/osu.Game/Rulesets/UI/ModIcon.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.UI
private readonly SpriteIcon modIcon;
private readonly SpriteIcon background;
- private const float icon_size = 80;
+ private const float background_size = 80;
public FontAwesome Icon
{
@@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.UI
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Size = new Vector2(icon_size),
+ Size = new Vector2(background_size),
Icon = FontAwesome.fa_osu_mod_bg,
Shadow = true,
},
@@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.UI
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Colour = OsuColour.Gray(84),
- Size = new Vector2(icon_size - 35),
+ Size = new Vector2(background_size - 35),
Y = 25,
Icon = mod.Icon
},
diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs
index cc16eff6d6..0270751946 100644
--- a/osu.Game/Rulesets/UI/Playfield.cs
+++ b/osu.Game/Rulesets/UI/Playfield.cs
@@ -4,7 +4,6 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
using osu.Game.Rulesets.Judgements;
@@ -14,9 +13,7 @@ using System.Linq;
namespace osu.Game.Rulesets.UI
{
- public abstract class Playfield : Container
- where TObject : HitObject
- where TJudgement : Judgement
+ public abstract class Playfield : Container
{
///
/// The HitObjects contained in this Playfield.
@@ -70,7 +67,7 @@ namespace osu.Game.Rulesets.UI
public override Axes RelativeSizeAxes
{
get { return Axes.Both; }
- set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
+ set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
}
///
@@ -82,19 +79,20 @@ namespace osu.Game.Rulesets.UI
/// Adds a DrawableHitObject to this Playfield.
///
/// The DrawableHitObject to add.
- public virtual void Add(DrawableHitObject h) => HitObjects.Add(h);
+ public virtual void Add(DrawableHitObject h) => HitObjects.Add(h);
///
/// Remove a DrawableHitObject from this Playfield.
///
/// The DrawableHitObject to remove.
- public virtual void Remove(DrawableHitObject h) => HitObjects.Remove(h);
+ public virtual void Remove(DrawableHitObject h) => HitObjects.Remove(h);
///
- /// Triggered when an object's Judgement is updated.
+ /// Triggered when a new occurs on a .
///
- /// The object that Judgement has been updated for.
- public virtual void OnJudgement(DrawableHitObject judgedObject) { }
+ /// The object that occured for.
+ /// The that occurred.
+ public virtual void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { }
public class HitObjectContainer : CompositeDrawable
{
diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs
index e2701faca0..f7ece531c3 100644
--- a/osu.Game/Rulesets/UI/RulesetContainer.cs
+++ b/osu.Game/Rulesets/UI/RulesetContainer.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.UI
///
/// Base RulesetContainer. Doesn't hold objects.
///
- /// Should not be derived - derive instead.
+ /// Should not be derived - derive instead.
///
///
public abstract class RulesetContainer : Container
@@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.UI
public event Action OnAllJudged;
///
- /// Whether to apply adjustments to the child based on our own size.
+ /// Whether to apply adjustments to the child based on our own size.
///
public bool AspectAdjust = true;
@@ -77,13 +77,6 @@ namespace osu.Game.Rulesets.UI
Ruleset = ruleset;
}
- [BackgroundDependencyLoader]
- private void load()
- {
- KeyBindingInputManager = CreateInputManager();
- KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
- }
-
///
/// Checks whether all HitObjects have been judged, and invokes OnAllJudged.
///
@@ -123,13 +116,15 @@ namespace osu.Game.Rulesets.UI
/// RulesetContainer that applies conversion to Beatmaps. Does not contain a Playfield
/// and does not load drawable hit objects.
///
- /// Should not be derived - derive instead.
+ /// Should not be derived - derive instead.
///
///
/// The type of HitObject contained by this RulesetContainer.
public abstract class RulesetContainer : RulesetContainer
where TObject : HitObject
{
+ public event Action OnJudgement;
+
///
/// The Beatmap
///
@@ -155,6 +150,20 @@ namespace osu.Game.Rulesets.UI
///
protected readonly bool IsForCurrentRuleset;
+ public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
+
+ protected override bool AllObjectsJudged => drawableObjects.All(h => h.AllJudged);
+
+ ///
+ /// The playfield.
+ ///
+ public Playfield Playfield { get; private set; }
+
+ protected override Container Content => content;
+ private Container content;
+
+ private readonly List> drawableObjects = new List>();
+
///
/// Whether to assume the beatmap passed into this is for the current ruleset.
/// Creates a hit renderer for a beatmap.
@@ -162,7 +171,7 @@ namespace osu.Game.Rulesets.UI
/// The ruleset being repesented.
/// The beatmap to create the hit renderer for.
/// Whether to assume the beatmap is for the current ruleset.
- internal RulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap, bool isForCurrentRuleset)
+ protected RulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap, bool isForCurrentRuleset)
: base(ruleset)
{
Debug.Assert(workingBeatmap != null, "RulesetContainer initialized with a null beatmap.");
@@ -194,78 +203,13 @@ namespace osu.Game.Rulesets.UI
// Post-process the beatmap
processor.PostProcess(Beatmap);
+ KeyBindingInputManager = CreateInputManager();
+ KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
+
// Add mods, should always be the last thing applied to give full control to mods
applyMods(Mods);
}
- ///
- /// Applies the active mods to this RulesetContainer.
- ///
- ///
- private void applyMods(IEnumerable mods)
- {
- if (mods == null)
- return;
-
- foreach (var mod in mods.OfType>())
- mod.ApplyToRulesetContainer(this);
- }
-
- ///
- /// Creates a processor to perform post-processing operations
- /// on HitObjects in converted Beatmaps.
- ///
- /// The Beatmap processor.
- protected virtual BeatmapProcessor CreateBeatmapProcessor() => new BeatmapProcessor();
-
- ///
- /// Creates a converter to convert Beatmap to a specific mode.
- ///
- /// The Beatmap converter.
- protected abstract BeatmapConverter CreateBeatmapConverter();
- }
-
- ///
- /// A derivable RulesetContainer that manages the Playfield and HitObjects.
- ///
- /// The type of HitObject contained by this RulesetContainer.
- /// The type of Judgement of DrawableHitObjects contained by this RulesetContainer.
- public abstract class RulesetContainer : RulesetContainer
- where TObject : HitObject
- where TJudgement : Judgement
- {
- public event Action OnJudgement;
-
- public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
-
- ///
- /// All the converted hit objects contained by this hit renderer.
- ///
- public new IEnumerable Objects => Beatmap.HitObjects;
-
- protected override bool AllObjectsJudged => drawableObjects.All(h => h.Judged);
-
- ///
- /// The playfield.
- ///
- public Playfield Playfield { get; private set; }
-
- protected override Container Content => content;
- private Container content;
-
- private readonly List> drawableObjects = new List>();
-
- ///
- /// Creates a hit renderer for a beatmap.
- ///
- /// The ruleset being repesented.
- /// The beatmap to create the hit renderer for.
- /// Whether to assume the beatmap is for the current ruleset.
- protected RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
- : base(ruleset, beatmap, isForCurrentRuleset)
- {
- }
-
[BackgroundDependencyLoader]
private void load()
{
@@ -280,6 +224,19 @@ namespace osu.Game.Rulesets.UI
loadObjects();
}
+ ///
+ /// Applies the active mods to this RulesetContainer.
+ ///
+ ///
+ private void applyMods(IEnumerable mods)
+ {
+ if (mods == null)
+ return;
+
+ foreach (var mod in mods.OfType>())
+ mod.ApplyToRulesetContainer(this);
+ }
+
public override void SetReplay(Replay replay)
{
base.SetReplay(replay);
@@ -302,7 +259,12 @@ namespace osu.Game.Rulesets.UI
if (drawableObject == null)
continue;
- drawableObject.OnJudgement += onJudgement;
+ drawableObject.OnJudgement += (d, j) =>
+ {
+ Playfield.OnJudgement(d, j);
+ OnJudgement?.Invoke(j);
+ CheckAllJudged();
+ };
drawableObjects.Add(drawableObject);
Playfield.Add(drawableObject);
@@ -319,36 +281,36 @@ namespace osu.Game.Rulesets.UI
}
///
- /// In some cases we want to apply changes to the relative size of our contained based on custom conditions.
+ /// Creates a processor to perform post-processing operations
+ /// on HitObjects in converted Beatmaps.
+ ///
+ /// The Beatmap processor.
+ protected virtual BeatmapProcessor CreateBeatmapProcessor() => new BeatmapProcessor();
+
+ ///
+ /// In some cases we want to apply changes to the relative size of our contained based on custom conditions.
///
///
protected virtual Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f); //a sane default
///
- /// Triggered when an object's Judgement is updated.
+ /// Creates a converter to convert Beatmap to a specific mode.
///
- /// The object that Judgement has been updated for.
- private void onJudgement(DrawableHitObject judgedObject)
- {
- Playfield.OnJudgement(judgedObject);
-
- OnJudgement?.Invoke(judgedObject.Judgement);
-
- CheckAllJudged();
- }
+ /// The Beatmap converter.
+ protected abstract BeatmapConverter CreateBeatmapConverter();
///
/// Creates a DrawableHitObject from a HitObject.
///
/// The HitObject to make drawable.
/// The DrawableHitObject.
- protected abstract DrawableHitObject GetVisualRepresentation(TObject h);
+ protected abstract DrawableHitObject GetVisualRepresentation(TObject h);
///
/// Creates a Playfield.
///
/// The Playfield.
- protected abstract Playfield CreatePlayfield();
+ protected abstract Playfield CreatePlayfield();
}
///
@@ -356,11 +318,9 @@ namespace osu.Game.Rulesets.UI
///
/// The type of Playfield contained by this RulesetContainer.
/// The type of HitObject contained by this RulesetContainer.
- /// The type of Judgement of DrawableHitObjects contained by this RulesetContainer.
- public abstract class RulesetContainer : RulesetContainer
+ public abstract class RulesetContainer : RulesetContainer
where TObject : HitObject
- where TJudgement : Judgement
- where TPlayfield : Playfield
+ where TPlayfield : Playfield
{
///
/// The playfield.
diff --git a/osu.Game/Rulesets/UI/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/ScrollingPlayfield.cs
index 1d13e2abb1..395248b2fd 100644
--- a/osu.Game/Rulesets/UI/ScrollingPlayfield.cs
+++ b/osu.Game/Rulesets/UI/ScrollingPlayfield.cs
@@ -11,19 +11,15 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input;
using osu.Framework.MathUtils;
-using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Timing;
namespace osu.Game.Rulesets.UI
{
///
- /// A type of specialized towards scrolling s.
+ /// A type of specialized towards scrolling s.
///
- public class ScrollingPlayfield : Playfield
- where TObject : HitObject
- where TJudgement : Judgement
+ public class ScrollingPlayfield : Playfield
{
///
/// The default span of time visible by the length of the scrolling axes.
@@ -65,7 +61,7 @@ namespace osu.Game.Rulesets.UI
public new readonly ScrollingHitObjectContainer HitObjects;
///
- /// Creates a new .
+ /// Creates a new .
///
/// The axes on which s in this container should scroll.
/// Whether we want our internal coordinate system to be scaled to a specified width
@@ -77,21 +73,21 @@ namespace osu.Game.Rulesets.UI
HitObjects.Reversed.BindTo(Reversed);
}
- private List> nestedPlayfields;
+ private List nestedPlayfields;
///
- /// All the s nested inside this playfield.
+ /// All the s nested inside this playfield.
///
- public IEnumerable> NestedPlayfields => nestedPlayfields;
+ public IEnumerable NestedPlayfields => nestedPlayfields;
///
- /// Adds a to this playfield. The nested
+ /// Adds a to this playfield. The nested
/// will be given all of the same speed adjustments as this playfield.
///
- /// The to add.
- protected void AddNested(ScrollingPlayfield otherPlayfield)
+ /// The to add.
+ protected void AddNested(ScrollingPlayfield otherPlayfield)
{
if (nestedPlayfields == null)
- nestedPlayfields = new List>();
+ nestedPlayfields = new List();
nestedPlayfields.Add(otherPlayfield);
}
@@ -119,7 +115,7 @@ namespace osu.Game.Rulesets.UI
this.TransformTo(this.PopulateTransform(new TransformVisibleTimeRange(), newTimeRange, duration, easing));
}
- private class TransformVisibleTimeRange : Transform>
+ private class TransformVisibleTimeRange : Transform
{
private double valueAt(double time)
{
@@ -131,8 +127,8 @@ namespace osu.Game.Rulesets.UI
public override string TargetMember => "VisibleTimeRange.Value";
- protected override void Apply(ScrollingPlayfield d, double time) => d.VisibleTimeRange.Value = valueAt(time);
- protected override void ReadIntoStartValue(ScrollingPlayfield d) => StartValue = d.VisibleTimeRange.Value;
+ protected override void Apply(ScrollingPlayfield d, double time) => d.VisibleTimeRange.Value = valueAt(time);
+ protected override void ReadIntoStartValue(ScrollingPlayfield d) => StartValue = d.VisibleTimeRange.Value;
}
///
diff --git a/osu.Game/Rulesets/UI/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/ScrollingRulesetContainer.cs
index ff156f788c..f1b8838fa9 100644
--- a/osu.Game/Rulesets/UI/ScrollingRulesetContainer.cs
+++ b/osu.Game/Rulesets/UI/ScrollingRulesetContainer.cs
@@ -9,7 +9,6 @@ using osu.Framework.Lists;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.IO.Serialization;
-using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Timing;
@@ -17,17 +16,16 @@ using osu.Game.Rulesets.Timing;
namespace osu.Game.Rulesets.UI
{
///
- /// A type of that supports a .
- /// s inside this will scroll within the playfield.
+ /// A type of that supports a .
+ /// s inside this will scroll within the playfield.
///
- public abstract class ScrollingRulesetContainer : RulesetContainer
+ public abstract class ScrollingRulesetContainer : RulesetContainer
where TObject : HitObject
- where TJudgement : Judgement
- where TPlayfield : ScrollingPlayfield
+ where TPlayfield : ScrollingPlayfield
{
///
/// Provides the default s that adjust the scrolling rate of s
- /// inside this .
+ /// inside this .
///
///
protected readonly SortedList DefaultControlPoints = new SortedList(Comparer.Default);
@@ -88,7 +86,7 @@ namespace osu.Game.Rulesets.UI
DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield));
}
- private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield playfield)
+ private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield playfield)
{
playfield.HitObjects.AddSpeedAdjustment(CreateSpeedAdjustmentContainer(controlPoint));
playfield.NestedPlayfields.ForEach(p => applySpeedAdjustment(controlPoint, p));
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 9f33d624e2..be9098e3be 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -8,6 +8,11 @@ using osu.Framework.Screens;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Select;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Screens.Edit.Menus;
namespace osu.Game.Screens.Edit
{
@@ -17,6 +22,175 @@ namespace osu.Game.Screens.Edit
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
+ internal override bool ShowOverlays => false;
+
+ public Editor()
+ {
+ Add(new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 40,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.FromHex("111")
+ },
+ new EditorMenuBar
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ X = 100,
+ Items = new[]
+ {
+ new EditorMenuBarItem("File")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Clear all notes"),
+ new EditorMenuItem("Open difficulty..."),
+ new EditorMenuItem("Save"),
+ new EditorMenuItem("Create new difficulty..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Revert to saved"),
+ new EditorMenuItem("Revert to saved (full"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Test beatmap"),
+ new EditorMenuItem("Open AiMod"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Upload Beatmap..."),
+ new EditorMenuItem("Export package"),
+ new EditorMenuItem("Export map package"),
+ new EditorMenuItem("Import from..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Open song folder"),
+ new EditorMenuItem("Open .osu in Notepad"),
+ new EditorMenuItem("Open .osb in Notepad"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Exit", MenuItemType.Standard, Exit)
+ }
+ },
+ new EditorMenuBarItem("Edit")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Undo"),
+ new EditorMenuItem("Redo"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Cut"),
+ new EditorMenuItem("Copy"),
+ new EditorMenuItem("Paste"),
+ new EditorMenuItem("Delete"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Select all"),
+ new EditorMenuItem("Clone"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Reverse selection"),
+ new EditorMenuItem("Flip horizontally"),
+ new EditorMenuItem("Flip vertically"),
+ new EditorMenuItem("Rotate 90deg clockwise"),
+ new EditorMenuItem("Rotate 90deg anticlockwise"),
+ new EditorMenuItem("Rotate by..."),
+ new EditorMenuItem("Scale by..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Reset selected objects' samples"),
+ new EditorMenuItem("Reset all samples", MenuItemType.Destructive),
+ new EditorMenuItem("Reset combo colours", MenuItemType.Destructive),
+ new EditorMenuItem("Reset breaks", MenuItemType.Destructive),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Nudge backward"),
+ new EditorMenuItem("Nudge forward")
+ }
+ },
+ new EditorMenuBarItem("View")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Compose"),
+ new EditorMenuItem("Design"),
+ new EditorMenuItem("Timing"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Song setup..."),
+ new EditorMenuItem("Timing setup..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Volume"),
+ new EditorMenuItem("Grid level"),
+ new EditorMenuItem("Show video"),
+ new EditorMenuItem("Show sample name"),
+ new EditorMenuItem("Snaking sliders"),
+ new EditorMenuItem("Hit animations"),
+ new EditorMenuItem("Follow points"),
+ new EditorMenuItem("Stacking")
+ }
+ },
+ new EditorMenuBarItem("Compose")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Snap divisor"),
+ new EditorMenuItem("Audio rate"),
+ new EditorMenuItem("Grid snapping"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Create polygon cricles..."),
+ new EditorMenuItem("Convert slider to stream"),
+ new EditorMenuItem("Enable live mapping mode"),
+ new EditorMenuItem("Sample import")
+ }
+ },
+ new EditorMenuBarItem("Design")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Move all elements in time...")
+ }
+ },
+ new EditorMenuBarItem("Timing")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Time signature"),
+ new EditorMenuItem("Metronome clicks"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Add timing section"),
+ new EditorMenuItem("Add inheriting section"),
+ new EditorMenuItem("Reset current section"),
+ new EditorMenuItem("Delete timing section"),
+ new EditorMenuItem("Resnap current section"),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Timing setup..."),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Resnap all notes", MenuItemType.Destructive),
+ new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
+ new EditorMenuItem("Recalculate slider lengths", MenuItemType.Destructive),
+ new EditorMenuItem("Delete all timing sections", MenuItemType.Destructive),
+ new EditorMenuItemSpacer(),
+ new EditorMenuItem("Set current position as preview point")
+ }
+ },
+ new EditorMenuBarItem("Web")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("This Beatmap's information page"),
+ new EditorMenuItem("This Beatmap's thread"),
+ new EditorMenuItem("Quick reply")
+ }
+ },
+ new EditorMenuBarItem("Help")
+ {
+ Items = new[]
+ {
+ new EditorMenuItem("Show in-game help"),
+ new EditorMenuItem("View FAQ")
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
protected override void OnResuming(Screen last)
{
Beatmap.Value.Track?.Stop();
diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs
new file mode 100644
index 0000000000..bb349b1531
--- /dev/null
+++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs
@@ -0,0 +1,122 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Input;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Screens.Edit.Menus
+{
+ public class EditorMenuBar : OsuMenu
+ {
+ public EditorMenuBar()
+ : base(Direction.Horizontal, true)
+ {
+ ItemsContainer.Padding = new MarginPadding(0);
+ BackgroundColour = Color4.Transparent;
+ }
+
+ protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu();
+
+ protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableEditorBarMenuItem(item);
+
+ private class DrawableEditorBarMenuItem : DrawableOsuMenuItem
+ {
+ private Color4 openedForegroundColour;
+ private Color4 openedBackgroundColour;
+
+ public DrawableEditorBarMenuItem(MenuItem item)
+ : base(item)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ ForegroundColour = ForegroundColourHover = colours.BlueLight;
+ BackgroundColour = BackgroundColourHover = Color4.Transparent;
+ openedForegroundColour = Color4.White;
+ openedBackgroundColour = colours.Gray3;
+ }
+
+ protected override void UpdateBackgroundColour()
+ {
+ if (State == MenuItemState.Selected)
+ Background.FadeColour(openedBackgroundColour);
+ else
+ base.UpdateBackgroundColour();
+ }
+
+ protected override void UpdateForegroundColour()
+ {
+ if (State == MenuItemState.Selected)
+ Foreground.FadeColour(openedForegroundColour);
+ else
+ base.UpdateForegroundColour();
+ }
+
+ protected override Drawable CreateBackground() => new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Height = 2,
+ Masking = true,
+ CornerRadius = 4,
+ Child = new Box { RelativeSizeAxes = Axes.Both }
+ }
+ };
+ }
+
+ private class SubMenu : OsuMenu
+ {
+ public SubMenu()
+ : base(Direction.Vertical)
+ {
+ OriginPosition = new Vector2(5, 1);
+ ItemsContainer.Padding = new MarginPadding { Top = 5, Bottom = 5 };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ BackgroundColour = colours.Gray3;
+ }
+
+ protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu();
+
+ protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableSubMenuItem(item);
+
+ private class DrawableSubMenuItem : DrawableOsuMenuItem
+ {
+ public DrawableSubMenuItem(MenuItem item)
+ : base(item)
+ {
+ }
+
+ protected override bool OnHover(InputState state)
+ {
+ if (Item is EditorMenuItemSpacer)
+ return true;
+ return base.OnHover(state);
+ }
+
+ protected override bool OnClick(InputState state)
+ {
+ if (Item is EditorMenuItemSpacer)
+ return true;
+ return base.OnClick(state);
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBarItem.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBarItem.cs
new file mode 100644
index 0000000000..201bc6e5c3
--- /dev/null
+++ b/osu.Game/Screens/Edit/Menus/EditorMenuBarItem.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 osu.Framework.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Edit.Menus
+{
+ public class EditorMenuBarItem : MenuItem
+ {
+ public EditorMenuBarItem(string text)
+ : base(text)
+ {
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs
new file mode 100644
index 0000000000..c7e36522cf
--- /dev/null
+++ b/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs
@@ -0,0 +1,23 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Edit.Menus
+{
+ public class EditorMenuItem : OsuMenuItem
+ {
+ private const int min_text_length = 40;
+
+ public EditorMenuItem(string text, MenuItemType type = MenuItemType.Standard)
+ : base(text.PadRight(min_text_length), type)
+ {
+ }
+
+ public EditorMenuItem(string text, MenuItemType type, Action action)
+ : base(text.PadRight(min_text_length), type, action)
+ {
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs b/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs
new file mode 100644
index 0000000000..5060165ef7
--- /dev/null
+++ b/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs
@@ -0,0 +1,13 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Screens.Edit.Menus
+{
+ public class EditorMenuItemSpacer : EditorMenuItem
+ {
+ public EditorMenuItemSpacer()
+ : base(" ")
+ {
+ }
+ }
+}
diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs
index aca169c3dc..6952f66f95 100644
--- a/osu.Game/Screens/Menu/Button.cs
+++ b/osu.Game/Screens/Menu/Button.cs
@@ -83,7 +83,7 @@ namespace osu.Game.Screens.Menu
{
EdgeSmoothness = new Vector2(1.5f, 0),
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Colour = Color4.White,
Alpha = 0,
},
diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs
index a0cf6eec66..3aeef4bbc9 100644
--- a/osu.Game/Screens/Menu/Intro.cs
+++ b/osu.Game/Screens/Menu/Intro.cs
@@ -52,7 +52,7 @@ namespace osu.Game.Screens.Menu
{
Alpha = 0,
Triangles = false,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Interactive = false,
Colour = Color4.DarkGray,
Ripple = false
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index 2de4c1b21f..bc94f88866 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -73,7 +73,7 @@ namespace osu.Game.Screens.Menu
{
texture = Texture.WhitePixel;
AccentColour = new Color4(1, 1, 1, 0.2f);
- BlendingMode = BlendingMode.Additive;
+ Blending = BlendingMode.Additive;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs
index 49c777f09a..9317780eac 100644
--- a/osu.Game/Screens/Menu/MenuSideFlashes.cs
+++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs
@@ -50,7 +50,7 @@ namespace osu.Game.Screens.Menu
RelativeSizeAxes = Axes.Y,
Width = box_width,
Alpha = 0,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
},
rightBox = new Box
{
@@ -59,7 +59,7 @@ namespace osu.Game.Screens.Menu
RelativeSizeAxes = Axes.Y,
Width = box_width,
Alpha = 0,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
}
};
}
diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs
index 64c28816d8..6f4a46b10b 100644
--- a/osu.Game/Screens/Menu/OsuLogo.cs
+++ b/osu.Game/Screens/Menu/OsuLogo.cs
@@ -108,7 +108,7 @@ namespace osu.Game.Screens.Menu
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Alpha = 0
}
}
@@ -169,7 +169,7 @@ namespace osu.Game.Screens.Menu
flashLayer = new Box
{
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Colour = Color4.White,
Alpha = 0,
},
@@ -272,14 +272,22 @@ namespace osu.Game.Screens.Menu
const float scale_adjust_cutoff = 0.4f;
const float velocity_adjust_cutoff = 0.98f;
+ const float paused_velocity = 0.5f;
- var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value.Track?.CurrentAmplitudes.Maximum ?? 0 : 0;
- logoAmplitudeContainer.ScaleTo(1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 75, Easing.OutQuint);
+ if (Beatmap.Value.Track.IsRunning)
+ {
+ var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value.Track.CurrentAmplitudes.Maximum : 0;
+ logoAmplitudeContainer.ScaleTo(1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 75, Easing.OutQuint);
- if (maxAmplitude > velocity_adjust_cutoff)
- triangles.Velocity = 1 + Math.Max(0, maxAmplitude - velocity_adjust_cutoff) * 50;
+ if (maxAmplitude > velocity_adjust_cutoff)
+ triangles.Velocity = 1 + Math.Max(0, maxAmplitude - velocity_adjust_cutoff) * 50;
+ else
+ triangles.Velocity = (float)Interpolation.Damp(triangles.Velocity, 1, 0.995f, Time.Elapsed);
+ }
else
- triangles.Velocity = (float)Interpolation.Damp(triangles.Velocity, 1, 0.995f, Time.Elapsed);
+ {
+ triangles.Velocity = paused_velocity;
+ }
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs
index 0f6c5984c4..d21be71785 100644
--- a/osu.Game/Screens/Play/KeyCounterCollection.cs
+++ b/osu.Game/Screens/Play/KeyCounterCollection.cs
@@ -28,6 +28,8 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
+ if (key == null) throw new ArgumentNullException(nameof(key));
+
base.Add(key);
key.IsCounting = IsCounting;
key.FadeTime = FadeTime;
diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs
index 408dbd8f16..fcf87de655 100644
--- a/osu.Game/Screens/ScreenWhiteBox.cs
+++ b/osu.Game/Screens/ScreenWhiteBox.cs
@@ -100,7 +100,7 @@ namespace osu.Game.Screens
Colour = getColourFor(GetType()),
Alpha = 0.2f,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
},
textContainer = new FillFlowContainer
{
diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs
index 47d25585ad..a676516300 100644
--- a/osu.Game/Screens/Select/BeatmapDetailArea.cs
+++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
@@ -10,6 +11,8 @@ namespace osu.Game.Screens.Select
{
public class BeatmapDetailArea : Container
{
+ private const float details_padding = 10;
+
private readonly Container content;
protected override Container Content => content;
@@ -66,9 +69,8 @@ namespace osu.Game.Screens.Select
Details = new BeatmapDetails
{
RelativeSizeAxes = Axes.X,
- Masking = true,
- Height = 352,
Alpha = 0,
+ Margin = new MarginPadding { Top = details_padding },
},
Leaderboard = new Leaderboard
{
@@ -76,5 +78,12 @@ namespace osu.Game.Screens.Select
}
});
}
+
+ protected override void UpdateAfterChildren()
+ {
+ base.UpdateAfterChildren();
+
+ Details.Height = Math.Min(DrawHeight - details_padding * 3 - BeatmapDetailAreaTabControl.HEIGHT, 450);
+ }
}
}
diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs
index a5486efa96..a98362e89c 100644
--- a/osu.Game/Screens/Select/BeatmapDetails.cs
+++ b/osu.Game/Screens/Select/BeatmapDetails.cs
@@ -9,71 +9,189 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
-using System.Globalization;
using System.Linq;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Framework.Threading;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Game.Screens.Select.Details;
using osu.Game.Beatmaps;
namespace osu.Game.Screens.Select
{
public class BeatmapDetails : Container
{
- private readonly MetadataSegment description;
- private readonly MetadataSegment source;
- private readonly MetadataSegment tags;
+ private const float spacing = 10;
+ private const float transition_duration = 250;
- private readonly DifficultyRow circleSize;
- private readonly DifficultyRow drainRate;
- private readonly DifficultyRow overallDifficulty;
- private readonly DifficultyRow approachRate;
- private readonly DifficultyRow stars;
+ private readonly FillFlowContainer top, statsFlow;
+ private readonly AdvancedStats advanced;
+ private readonly DetailBox ratingsContainer;
+ private readonly UserRatings ratings;
+ private readonly ScrollContainer metadataScroll;
+ private readonly MetadataSection description, source, tags;
+ private readonly Container failRetryContainer;
+ private readonly FailRetryGraph failRetryGraph;
+ private readonly DimmedLoadingAnimation loading;
- private readonly Container ratingsContainer;
- private readonly Bar ratingsBar;
- private readonly OsuSpriteText negativeRatings;
- private readonly OsuSpriteText positiveRatings;
- private readonly BarGraph ratingsGraph;
-
- private readonly FillFlowContainer retryFailContainer;
- private readonly BarGraph retryGraph;
- private readonly BarGraph failGraph;
+ private APIAccess api;
private ScheduledDelegate pendingBeatmapSwitch;
- private BeatmapInfo beatmap;
+ private BeatmapInfo beatmap;
public BeatmapInfo Beatmap
{
get { return beatmap; }
-
set
{
- if (beatmap == value) return;
-
+ if (value == beatmap) return;
beatmap = value;
pendingBeatmapSwitch?.Cancel();
- pendingBeatmapSwitch = Schedule(updateStats);
+ pendingBeatmapSwitch = Schedule(updateStatistics);
}
}
- private void updateStats()
+ public BeatmapDetails()
{
- if (beatmap == null) return;
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black.Opacity(0.5f),
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Horizontal = spacing },
+ Children = new Drawable[]
+ {
+ top = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Horizontal,
+ Children = new Drawable[]
+ {
+ statsFlow = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Width = 0.5f,
+ Spacing = new Vector2(spacing),
+ Padding = new MarginPadding { Right = spacing / 2 },
+ Children = new[]
+ {
+ new DetailBox
+ {
+ Child = advanced = new AdvancedStats
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = new MarginPadding { Horizontal = spacing, Top = spacing * 2, Bottom = spacing },
+ },
+ },
+ ratingsContainer = new DetailBox
+ {
+ Child = ratings = new UserRatings
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 134,
+ Padding = new MarginPadding { Horizontal = spacing, Top = spacing },
+ },
+ },
+ },
+ },
+ metadataScroll = new ScrollContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ Width = 0.5f,
+ ScrollbarVisible = false,
+ Padding = new MarginPadding { Left = spacing / 2 },
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ LayoutDuration = transition_duration,
+ Spacing = new Vector2(spacing * 2),
+ Margin = new MarginPadding { Top = spacing * 2 },
+ Children = new[]
+ {
+ description = new MetadataSection("Description")
+ {
+ TextColour = Color4.White.Opacity(0.75f),
+ },
+ source = new MetadataSection("Source")
+ {
+ TextColour = Color4.White.Opacity(0.75f),
+ },
+ tags = new MetadataSection("Tags"),
+ },
+ },
+ },
+ },
+ },
+ failRetryContainer = new Container
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ RelativeSizeAxes = Axes.X,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = "Points of Failure",
+ Font = @"Exo2.0-Bold",
+ TextSize = 14,
+ },
+ failRetryGraph = new FailRetryGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Top = 14 + spacing / 2 },
+ },
+ },
+ },
+ },
+ },
+ loading = new DimmedLoadingAnimation
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ };
+ }
- description.Text = beatmap.Version;
- source.Text = beatmap.Metadata.Source;
- tags.Text = beatmap.Metadata.Tags;
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours, APIAccess api)
+ {
+ this.api = api;
+ tags.TextColour = colours.Yellow;
+ }
- circleSize.Value = beatmap.Difficulty.CircleSize;
- drainRate.Value = beatmap.Difficulty.DrainRate;
- overallDifficulty.Value = beatmap.Difficulty.OverallDifficulty;
- approachRate.Value = beatmap.Difficulty.ApproachRate;
- stars.Value = (float)beatmap.StarDifficulty;
+ protected override void UpdateAfterChildren()
+ {
+ base.UpdateAfterChildren();
- var requestedBeatmap = beatmap;
+ metadataScroll.Height = statsFlow.DrawHeight;
+ failRetryContainer.Height = DrawHeight - Padding.TotalVertical - (top.DrawHeight + spacing / 2);
+ }
+
+ private void updateStatistics()
+ {
+ if (Beatmap == null)
+ {
+ clearStats();
+ return;
+ }
+
+ ratingsContainer.FadeIn(transition_duration);
+ advanced.Beatmap = Beatmap;
+ description.Text = Beatmap.Version;
+ source.Text = Beatmap.Metadata.Source;
+ tags.Text = Beatmap.Metadata.Tags;
+
+ var requestedBeatmap = Beatmap;
if (requestedBeatmap.Metrics == null)
{
var lookup = new GetBeatmapDetailsRequest(requestedBeatmap);
@@ -84,413 +202,195 @@ namespace osu.Game.Screens.Select
return;
requestedBeatmap.Metrics = res;
- Schedule(() => updateMetrics(res));
+ Schedule(() => displayMetrics(res));
};
- lookup.Failure += e => Schedule(() => updateMetrics(null));
+ lookup.Failure += e => Schedule(() => displayMetrics(null));
api.Queue(lookup);
loading.Show();
}
- updateMetrics(requestedBeatmap.Metrics, false);
+ displayMetrics(requestedBeatmap.Metrics, false);
}
- ///
- /// Update displayed metrics.
- ///
- /// New metrics to overwrite the existing display. Can be null.
- /// Whether to hide the display on null or empty metrics. If false, we will dim as if waiting for further updates.
- private void updateMetrics(BeatmapMetrics metrics, bool failOnMissing = true)
+ private void displayMetrics(BeatmapMetrics metrics, bool failOnMissing = true)
{
- var hasRatings = metrics?.Ratings.Any() ?? false;
- var hasRetriesFails = (metrics?.Retries.Any() ?? false) && metrics.Fails.Any();
+ var hasRatings = metrics?.Ratings?.Any() ?? false;
+ var hasRetriesFails = (metrics?.Retries?.Any() ?? false) && (metrics.Fails?.Any() ?? false);
- if (failOnMissing)
- loading.Hide();
+ if (failOnMissing) loading.Hide();
if (hasRatings)
{
- var ratings = metrics.Ratings.ToList();
- ratingsContainer.Show();
-
- negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2).Sum().ToString();
- positiveRatings.Text = ratings.GetRange(ratings.Count / 2, ratings.Count / 2).Sum().ToString();
- ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2).Sum() / ratings.Sum();
-
- ratingsGraph.Values = ratings.Select(rating => (float)rating);
-
- ratingsContainer.FadeColour(Color4.White, 500, Easing.Out);
+ ratings.Metrics = metrics;
+ ratings.FadeIn(transition_duration);
}
else if (failOnMissing)
- ratingsGraph.Values = new float[10];
+ {
+ ratings.Metrics = new BeatmapMetrics
+ {
+ Ratings = new int[10],
+ };
+ }
else
- ratingsContainer.FadeColour(Color4.Gray, 500, Easing.Out);
+ {
+ ratings.FadeTo(0.25f, transition_duration);
+ }
if (hasRetriesFails)
{
- var retries = metrics.Retries;
- var fails = metrics.Fails;
- retryFailContainer.Show();
-
- float maxValue = fails.Zip(retries, (fail, retry) => fail + retry).Max();
- failGraph.MaxValue = maxValue;
- retryGraph.MaxValue = maxValue;
-
- failGraph.Values = fails.Select(fail => (float)fail);
- retryGraph.Values = retries.Zip(fails, (retry, fail) => retry + MathHelper.Clamp(fail, 0, maxValue));
-
- retryFailContainer.FadeColour(Color4.White, 500, Easing.Out);
+ failRetryGraph.Metrics = metrics;
+ failRetryContainer.FadeIn(transition_duration);
}
else if (failOnMissing)
{
- failGraph.Values = new float[100];
- retryGraph.Values = new float[100];
+ failRetryGraph.Metrics = new BeatmapMetrics
+ {
+ Fails = new int[100],
+ Retries = new int[100],
+ };
}
else
- retryFailContainer.FadeColour(Color4.Gray, 500, Easing.Out);
+ {
+ failRetryContainer.FadeTo(0.25f, transition_duration);
+ }
}
- public BeatmapDetails()
+ private void clearStats()
{
- Children = new Drawable[]
+ description.Text = null;
+ source.Text = null;
+ tags.Text = null;
+ advanced.Beatmap = new BeatmapInfo
{
- new Box
+ StarDifficulty = 0,
+ Difficulty = new BeatmapDifficulty
{
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
- Alpha = 0.5f,
+ CircleSize = 0,
+ DrainRate = 0,
+ OverallDifficulty = 0,
+ ApproachRate = 0,
},
- new FillFlowContainer
- {
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Width = 0.4f,
- Direction = FillDirection.Vertical,
- LayoutDuration = 200,
- LayoutEasing = Easing.OutQuint,
- Children = new[]
- {
- description = new MetadataSegment("Description"),
- source = new MetadataSegment("Source"),
- tags = new MetadataSegment("Tags")
- },
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Width = 0.6f,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 15),
- Padding = new MarginPadding(10) { Top = 0 },
- Children = new Drawable[]
- {
- new Container
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
- Alpha = 0.5f,
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 5),
- Padding = new MarginPadding(10),
- Children = new[]
- {
- circleSize = new DifficultyRow("Circle Size", 7),
- drainRate = new DifficultyRow("HP Drain"),
- overallDifficulty = new DifficultyRow("Accuracy"),
- approachRate = new DifficultyRow("Approach Rate"),
- stars = new DifficultyRow("Star Difficulty"),
- },
- },
- },
- },
- ratingsContainer = new Container
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Alpha = 0,
- AlwaysPresent = true,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
- Alpha = 0.5f,
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Padding = new MarginPadding
- {
- Top = 25,
- Left = 15,
- Right = 15,
- },
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = "User Rating",
- Font = @"Exo2.0-Medium",
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- },
- ratingsBar = new Bar
- {
- RelativeSizeAxes = Axes.X,
- Height = 5,
- },
- new Container
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Children = new[]
- {
- negativeRatings = new OsuSpriteText
- {
- Font = @"Exo2.0-Regular",
- Text = "0",
- },
- positiveRatings = new OsuSpriteText
- {
- Font = @"Exo2.0-Regular",
- Text = "0",
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- },
- },
- },
- new OsuSpriteText
- {
- Text = "Rating Spread",
- TextSize = 14,
- Font = @"Exo2.0-Regular",
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- },
- ratingsGraph = new BarGraph
- {
- RelativeSizeAxes = Axes.X,
- Height = 50,
- },
- },
- },
- },
- },
- retryFailContainer = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Alpha = 0,
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = "Points of Failure",
- Font = @"Exo2.0-Regular",
- },
- new Container
- {
- RelativeSizeAxes = Axes.X,
- Size = new Vector2(1 / 0.6f, 50),
- Children = new[]
- {
- retryGraph = new BarGraph
- {
- RelativeSizeAxes = Axes.Both,
- },
- failGraph = new BarGraph
- {
- RelativeSizeAxes = Axes.Both,
- },
- },
- },
- }
- },
- },
- },
- loading = new LoadingAnimation()
};
+
+ loading.Hide();
+ ratingsContainer.FadeOut(transition_duration);
+ failRetryContainer.FadeOut(transition_duration);
}
- private APIAccess api;
- private readonly LoadingAnimation loading;
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colour, APIAccess api)
+ private class DetailBox : Container
{
- this.api = api;
+ private readonly Container content;
+ protected override Container Content => content;
- description.AccentColour = colour.GrayB;
- source.AccentColour = colour.GrayB;
- tags.AccentColour = colour.YellowLight;
-
- stars.AccentColour = colour.Yellow;
-
- ratingsBar.BackgroundColour = colour.Green;
- ratingsBar.AccentColour = colour.YellowDark;
- ratingsGraph.Colour = colour.BlueDark;
-
- failGraph.Colour = colour.YellowDarker;
- retryGraph.Colour = colour.Yellow;
- }
-
- private class DifficultyRow : Container, IHasAccentColour
- {
- private readonly OsuSpriteText name;
- private readonly Bar bar;
- private readonly OsuSpriteText valueText;
-
- private readonly float maxValue;
-
- private float difficultyValue;
- public float Value
+ public DetailBox()
{
- get
- {
- return difficultyValue;
- }
- set
- {
- difficultyValue = value;
- bar.Length = value / maxValue;
- valueText.Text = value.ToString("N1", CultureInfo.CurrentCulture);
- }
- }
-
- public Color4 AccentColour
- {
- get
- {
- return bar.AccentColour;
- }
- set
- {
- bar.AccentColour = value;
- }
- }
-
- public DifficultyRow(string difficultyName, float maxValue = 10)
- {
- this.maxValue = maxValue;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
- Children = new Drawable[]
+
+ InternalChildren = new Drawable[]
{
- name = new OsuSpriteText
+ new Box
{
- Font = @"Exo2.0-Regular",
- Text = difficultyName,
- },
- bar = new Bar
- {
- Origin = Anchor.CentreLeft,
- Anchor = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
- Size = new Vector2(1, 0.35f),
- Padding = new MarginPadding { Left = 100, Right = 25 },
+ Colour = Color4.Black.Opacity(0.5f),
},
- valueText = new OsuSpriteText
+ content = new Container
{
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- Font = @"Exo2.0-Regular",
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
},
};
}
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colour)
- {
- name.Colour = colour.GrayB;
- bar.BackgroundColour = colour.Gray7;
- valueText.Colour = colour.GrayB;
- }
}
- private class MetadataSegment : Container, IHasAccentColour
+ private class MetadataSection : Container
{
- private readonly OsuSpriteText header;
- private readonly FillFlowContainer content;
+ private readonly TextFlowContainer textFlow;
public string Text
{
set
{
if (string.IsNullOrEmpty(value))
- Hide();
- else
{
- Show();
- if (header.Text == "Tags")
- content.ChildrenEnumerable = value.Split(' ').Select(text => new OsuSpriteText
- {
- Text = text,
- Font = "Exo2.0-Regular",
- });
- else
- content.Children = new[]
- {
- new OsuSpriteText
- {
- Text = value,
- Font = "Exo2.0-Regular",
- }
- };
+ this.FadeOut(transition_duration);
+ return;
}
+
+ this.FadeIn(transition_duration);
+ textFlow.Clear();
+ textFlow.AddText(value, s => s.TextSize = 14);
}
}
- public Color4 AccentColour
+ public Color4 TextColour
{
- get
- {
- return content.Colour;
- }
- set
- {
- content.Colour = value;
- }
+ get { return textFlow.Colour; }
+ set { textFlow.Colour = value; }
}
- public MetadataSegment(string headerText)
+ public MetadataSection(string title)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
- Margin = new MarginPadding { Top = 10 };
+
+ InternalChild = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(spacing / 2),
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Child = new OsuSpriteText
+ {
+ Text = title,
+ Font = @"Exo2.0-Bold",
+ TextSize = 14,
+ },
+ },
+ textFlow = new TextFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ },
+ },
+ };
+ }
+ }
+
+ private class DimmedLoadingAnimation : VisibilityContainer
+ {
+ private readonly LoadingAnimation loading;
+
+ public DimmedLoadingAnimation()
+ {
Children = new Drawable[]
{
- header = new OsuSpriteText
+ new Box
{
- Font = @"Exo2.0-Bold",
- Text = headerText,
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black.Opacity(0.5f),
},
- content = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Full,
- Spacing = new Vector2(5, 0),
- Margin = new MarginPadding { Top = header.TextSize }
- }
+ loading = new LoadingAnimation(),
};
}
+
+ protected override void PopIn()
+ {
+ this.FadeIn(transition_duration, Easing.OutQuint);
+ loading.State = Visibility.Visible;
+ }
+
+ protected override void PopOut()
+ {
+ this.FadeOut(transition_duration, Easing.OutQuint);
+ loading.State = Visibility.Hidden;
+ }
}
}
}
diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs
new file mode 100644
index 0000000000..d92c8ed509
--- /dev/null
+++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs
@@ -0,0 +1,152 @@
+// 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.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using System;
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Screens.Select.Details
+{
+ public class AdvancedStats : Container
+ {
+ private readonly StatisticRow firstValue, hpDrain, accuracy, approachRate, starDifficulty;
+
+ private BeatmapInfo beatmap;
+ public BeatmapInfo Beatmap
+ {
+ get { return beatmap; }
+ set
+ {
+ if (value == beatmap) return;
+ beatmap = value;
+
+ //mania specific
+ if ((Beatmap?.Ruleset?.ID ?? 0) == 3)
+ {
+ firstValue.Title = "Key Amount";
+ firstValue.Value = (int)Math.Round(Beatmap?.Difficulty?.CircleSize ?? 0);
+ }
+ else
+ {
+ firstValue.Title = "Circle Size";
+ firstValue.Value = Beatmap?.Difficulty?.CircleSize ?? 0;
+ }
+
+ hpDrain.Value = beatmap.Difficulty.DrainRate;
+ accuracy.Value = beatmap.Difficulty.OverallDifficulty;
+ approachRate.Value = beatmap.Difficulty.ApproachRate;
+ starDifficulty.Value = (float)beatmap.StarDifficulty;
+ }
+ }
+
+ public AdvancedStats()
+ {
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(4f),
+ Children = new[]
+ {
+ firstValue = new StatisticRow(), //circle size/key amount
+ hpDrain = new StatisticRow { Title = "HP Drain" },
+ accuracy = new StatisticRow { Title = "Accuracy" },
+ approachRate = new StatisticRow { Title = "Approach Rate" },
+ starDifficulty = new StatisticRow(10, true) { Title = "Star Difficulty" },
+ },
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ starDifficulty.AccentColour = colours.Yellow;
+ }
+
+ private class StatisticRow : Container, IHasAccentColour
+ {
+ private const float value_width = 25;
+ private const float name_width = 70;
+
+ private readonly float maxValue;
+ private readonly bool forceDecimalPlaces;
+ private readonly OsuSpriteText name, value;
+ private readonly Bar bar;
+
+ public string Title
+ {
+ get { return name.Text; }
+ set { name.Text = value; }
+ }
+
+ private float difficultyValue;
+ public float Value
+ {
+ get { return difficultyValue; }
+ set
+ {
+ difficultyValue = value;
+ bar.Length = value / maxValue;
+ this.value.Text = value.ToString(forceDecimalPlaces ? "0.00" : "0.##");
+ }
+ }
+
+ public Color4 AccentColour
+ {
+ get { return bar.AccentColour; }
+ set { bar.AccentColour = value; }
+ }
+
+ public StatisticRow(float maxValue = 10, bool forceDecimalPlaces = false)
+ {
+ this.maxValue = maxValue;
+ this.forceDecimalPlaces = forceDecimalPlaces;
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ Width = name_width,
+ AutoSizeAxes = Axes.Y,
+ Child = name = new OsuSpriteText
+ {
+ TextSize = 13,
+ },
+ },
+ bar = new Bar
+ {
+ Origin = Anchor.CentreLeft,
+ Anchor = Anchor.CentreLeft,
+ RelativeSizeAxes = Axes.X,
+ Height = 5,
+ BackgroundColour = Color4.White.Opacity(0.5f),
+ Padding = new MarginPadding { Left = name_width + 10, Right = value_width + 10 },
+ },
+ new Container
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Width = value_width,
+ RelativeSizeAxes = Axes.Y,
+ Child = value = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ TextSize = 13,
+ },
+ },
+ };
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Select/Details/FailRetryGraph.cs b/osu.Game/Screens/Select/Details/FailRetryGraph.cs
new file mode 100644
index 0000000000..4d75c49d17
--- /dev/null
+++ b/osu.Game/Screens/Select/Details/FailRetryGraph.cs
@@ -0,0 +1,62 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+using System.Linq;
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Screens.Select.Details
+{
+ public class FailRetryGraph : Container
+ {
+ private readonly BarGraph retryGraph, failGraph;
+
+ private BeatmapMetrics metrics;
+ public BeatmapMetrics Metrics
+ {
+ get { return metrics; }
+ set
+ {
+ if (value == metrics) return;
+ metrics = value;
+
+ var retries = Metrics.Retries;
+ var fails = Metrics.Fails;
+
+ float maxValue = fails.Zip(retries, (fail, retry) => fail + retry).Max();
+ failGraph.MaxValue = maxValue;
+ retryGraph.MaxValue = maxValue;
+
+ failGraph.Values = fails.Select(f => (float)f);
+ retryGraph.Values = retries.Zip(fails, (retry, fail) => retry + MathHelper.Clamp(fail, 0, maxValue));
+ }
+ }
+
+ public FailRetryGraph()
+ {
+ Children = new[]
+ {
+ retryGraph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ failGraph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ retryGraph.Colour = colours.Yellow;
+ failGraph.Colour = colours.YellowDarker;
+ }
+ }
+}
diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs
new file mode 100644
index 0000000000..db6d932464
--- /dev/null
+++ b/osu.Game/Screens/Select/Details/UserRatings.cs
@@ -0,0 +1,122 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using System.Linq;
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Screens.Select.Details
+{
+ public class UserRatings : Container
+ {
+ private readonly FillFlowContainer header;
+ private readonly Bar ratingsBar;
+ private readonly OsuSpriteText negativeRatings, positiveRatings;
+ private readonly Container graphContainer;
+ private readonly BarGraph graph;
+
+ private BeatmapMetrics metrics;
+ public BeatmapMetrics Metrics
+ {
+ get { return metrics; }
+ set
+ {
+ if (value == metrics) return;
+ metrics = value;
+
+ var ratings = Metrics.Ratings.ToList();
+ negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2).Sum().ToString();
+ positiveRatings.Text = ratings.GetRange(ratings.Count / 2, ratings.Count / 2).Sum().ToString();
+ ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2).Sum() / ratings.Sum();
+ graph.Values = Metrics.Ratings.Select(r => (float)r);
+ }
+ }
+
+ public UserRatings()
+ {
+ Children = new Drawable[]
+ {
+ header = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = "User Rating",
+ TextSize = 13,
+ },
+ ratingsBar = new Bar
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 5,
+ Margin = new MarginPadding { Top = 5 },
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new[]
+ {
+ negativeRatings = new OsuSpriteText
+ {
+ Text = "0",
+ TextSize = 13,
+ },
+ positiveRatings = new OsuSpriteText
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Text = @"0",
+ TextSize = 13,
+ },
+ },
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = "Rating Spread",
+ TextSize = 13,
+ Margin = new MarginPadding { Top = 10, Bottom = 5 },
+ },
+ },
+ },
+ graphContainer = new Container
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ RelativeSizeAxes = Axes.Both,
+ Child = graph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ },
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ ratingsBar.BackgroundColour = colours.Green;
+ ratingsBar.AccentColour = colours.Yellow;
+ graph.Colour = colours.BlueDark;
+ }
+
+ protected override void UpdateAfterChildren()
+ {
+ base.UpdateAfterChildren();
+
+ graphContainer.Padding = new MarginPadding { Top = header.DrawHeight };
+ }
+ }
+}
diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs
index 5a375e55d4..0506784614 100644
--- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs
@@ -1,15 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using System.Collections.Generic;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
-using System;
-using osu.Framework.Allocation;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
index 2987f4476c..de381cd2dc 100644
--- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
@@ -4,17 +4,19 @@
using System;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Input;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Users;
-using osu.Framework;
-using osu.Game.Rulesets.Scoring;
using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.UI;
+using osu.Game.Users;
namespace osu.Game.Screens.Select.Leaderboards
{
@@ -41,7 +43,7 @@ namespace osu.Game.Screens.Select.Leaderboards
private readonly ScoreComponentLabel maxCombo;
private readonly ScoreComponentLabel accuracy;
private readonly Container flagBadgeContainer;
- private readonly FillFlowContainer modsContainer;
+ private readonly FillFlowContainer modsContainer;
private Visibility state;
@@ -247,7 +249,7 @@ namespace osu.Game.Screens.Select.Leaderboards
},
},
},
- modsContainer = new FillFlowContainer
+ modsContainer = new FillFlowContainer
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
@@ -260,13 +262,13 @@ namespace osu.Game.Screens.Select.Leaderboards
},
};
- if (Score.Mods != null)
+ foreach (Mod mod in Score.Mods)
{
- foreach (Mod mod in Score.Mods)
+ modsContainer.Add(new ModIcon(mod)
{
- // TODO: Get actual mod colours
- modsContainer.Add(new ScoreModIcon(mod.Icon, OsuColour.FromHex(@"ffcc22")));
- }
+ AutoSizeAxes = Axes.Both,
+ Scale = new Vector2(0.375f)
+ });
}
}
@@ -275,13 +277,13 @@ namespace osu.Game.Screens.Select.Leaderboards
public override void Hide() => State = Visibility.Hidden;
public override void Show() => State = Visibility.Visible;
- protected override bool OnHover(Framework.Input.InputState state)
+ protected override bool OnHover(InputState state)
{
background.FadeTo(0.5f, 300, Easing.OutQuint);
return base.OnHover(state);
}
- protected override void OnHoverLost(Framework.Input.InputState state)
+ protected override void OnHoverLost(InputState state)
{
background.FadeTo(background_alpha, 200, Easing.OutQuint);
base.OnHoverLost(state);
@@ -302,7 +304,7 @@ namespace osu.Game.Screens.Select.Leaderboards
BlurSigma = new Vector2(4),
CacheDrawnFrameBuffer = true,
RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Size = new Vector2(3f),
Children = new[]
{
@@ -311,8 +313,8 @@ namespace osu.Game.Screens.Select.Leaderboards
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = font,
- TextSize = textSize,
FixedWidth = true,
+ TextSize = textSize,
Text = text,
Colour = glowColour,
Shadow = false,
@@ -334,36 +336,6 @@ namespace osu.Game.Screens.Select.Leaderboards
}
}
- private class ScoreModIcon : Container
- {
- public ScoreModIcon(FontAwesome icon, Color4 colour)
- {
- AutoSizeAxes = Axes.Both;
-
- Children = new[]
- {
- new SpriteIcon
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- Icon = FontAwesome.fa_osu_mod_bg,
- Colour = colour,
- Shadow = true,
- Size = new Vector2(30),
- },
- new SpriteIcon
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- Icon = icon,
- Colour = OsuColour.Gray(84),
- Size = new Vector2(18),
- Position = new Vector2(0f, 2f),
- },
- };
- }
- }
-
private class ScoreComponentLabel : Container
{
public ScoreComponentLabel(FontAwesome icon, string value)
diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs
index 306e7fb3dc..5f1bdcc9bb 100644
--- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs
+++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs
@@ -119,7 +119,7 @@ namespace osu.Game.Screens.Select.Options
{
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(1.5f, 0),
- BlendingMode = BlendingMode.Additive,
+ Blending = BlendingMode.Additive,
Colour = Color4.White,
Alpha = 0,
},
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 8bdc229d70..8602ab0382 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -9,7 +9,7 @@
Properties
osu.Game
osu.Game
- v4.5
+ v4.6.1
512
@@ -101,6 +101,7 @@
+
@@ -135,6 +136,10 @@
+
+
+
+
@@ -212,7 +217,6 @@
-
@@ -536,6 +540,9 @@
+
+
+
diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings
index 06d160ad31..0b8c196ec8 100644
--- a/osu.sln.DotSettings
+++ b/osu.sln.DotSettings
@@ -190,6 +190,7 @@
IPC
LTRB
MD5
+ RGB
RNG
SHA
SRGB