diff --git a/.vscode/launch.json b/.vscode/launch.json
index b981556649..c836ff97bc 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -11,7 +11,7 @@
"preLaunchTask": "build",
"runtimeExecutable": null,
"env": {},
- "externalConsole": false
+ "console": "internalConsole"
},
{
"name": "Launch Desktop",
@@ -23,7 +23,7 @@
"preLaunchTask": "build",
"runtimeExecutable": null,
"env": {},
- "externalConsole": false
+ "console": "internalConsole"
},
{
"name": "Attach",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 0c0e79f7fb..03f5bc4c6c 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -2,25 +2,23 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
- "windows": {
- "command": "msbuild"
- },
- "linux": {
- "command": "xbuild"
- },
- "args": [
- // Ask msbuild to generate full paths for file names.
- "/property:GenerateFullPaths=true"
- ],
"taskSelector": "/t:",
- "showOutput": "silent",
"tasks": [
{
"taskName": "build",
- // Show the output window only if unrecognized errors occur.
+ "isShellCommand": true,
"showOutput": "silent",
+ "command": "xbuild",
+ "windows": {
+ "command": "msbuild"
+ },
+ "args": [
+ // Ask msbuild to generate full paths for file names.
+ "/property:GenerateFullPaths=true"
+ ],
// Use the standard MS compiler pattern to detect errors, warnings and infos
- "problemMatcher": "$msCompile"
+ "problemMatcher": "$msCompile",
+ "isBuildCommand": true
}
]
}
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index 0d5878aa77..cc6dfb9c88 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -10,7 +10,7 @@ install:
- cmd: git submodule update --init --recursive
- cmd: choco install resharper-clt -y
- cmd: choco install nvika -y
- - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.1/CodeFileSanity.exe
+ - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.2/CodeFileSanity.exe
before_build:
- cmd: CodeFileSanity.exe
- cmd: nuget restore
diff --git a/osu-framework b/osu-framework
index bf6a3dc401..2234013e59 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit bf6a3dc40176ee4f921012808070e014fc4a5779
+Subproject commit 2234013e59a99116ee9f9e56a95ff8a6667db2a7
diff --git a/osu-resources b/osu-resources
index 12bbab717d..0cba3cbc16 160000
--- a/osu-resources
+++ b/osu-resources
@@ -1 +1 @@
-Subproject commit 12bbab717d372dadbd3220d38da862276ac97e98
+Subproject commit 0cba3cbc167cfe94e07fe5b629c925e190be939e
diff --git a/osu.Desktop.Deploy/App.config b/osu.Desktop.Deploy/App.config
index d1da144f50..45685a74a8 100644
--- a/osu.Desktop.Deploy/App.config
+++ b/osu.Desktop.Deploy/App.config
@@ -21,4 +21,16 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/Properties/AssemblyInfo.cs b/osu.Desktop.Deploy/Properties/AssemblyInfo.cs
index 8df81400c1..5841c1b082 100644
--- a/osu.Desktop.Deploy/Properties/AssemblyInfo.cs
+++ b/osu.Desktop.Deploy/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Desktop.Deploy")]
@@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
index 7a3719a25b..901117b026 100644
--- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
+++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
@@ -68,9 +68,8 @@
$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll
True
-
- $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ $(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll
@@ -120,7 +119,7 @@
-
-
-
+
+
diff --git a/osu.Desktop.VisualTests/Beatmaps/TestWorkingBeatmap.cs b/osu.Desktop.VisualTests/Beatmaps/TestWorkingBeatmap.cs
index f135a6affa..5e3f5b5133 100644
--- a/osu.Desktop.VisualTests/Beatmaps/TestWorkingBeatmap.cs
+++ b/osu.Desktop.VisualTests/Beatmaps/TestWorkingBeatmap.cs
@@ -16,7 +16,7 @@ namespace osu.Desktop.VisualTests.Beatmaps
}
private readonly Beatmap beatmap;
-
+
protected override Beatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetTrack() => null;
diff --git a/osu.Desktop.VisualTests/Platform/TestStorage.cs b/osu.Desktop.VisualTests/Platform/TestStorage.cs
index c5502d5d5d..f711ddac24 100644
--- a/osu.Desktop.VisualTests/Platform/TestStorage.cs
+++ b/osu.Desktop.VisualTests/Platform/TestStorage.cs
@@ -15,7 +15,7 @@ namespace osu.Desktop.VisualTests.Platform
public TestStorage(string baseName) : base(baseName)
{
}
-
+
public override SQLiteConnection GetDatabase(string name)
{
ISQLitePlatform platform;
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs
new file mode 100644
index 0000000000..4a59ad9534
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.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.Graphics;
+using osu.Framework.Graphics.Primitives;
+using osu.Framework.Testing;
+using osu.Game.Database;
+using osu.Game.Screens.Select;
+using System.Linq;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseBeatmapDetails : TestCase
+ {
+ public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
+
+ private BeatmapDetails details;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ Add(details = new BeatmapDetails
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(150),
+ Beatmap = new BeatmapInfo
+ {
+ 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),
+ },
+ },
+ });
+
+ AddRepeatStep("fail values", newRetryAndFailValues, 10);
+ }
+
+ private int lastRange = 1;
+
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseChatDisplay.cs b/osu.Desktop.VisualTests/Tests/TestCaseChatDisplay.cs
index 2cb63ba7a0..2663c952cf 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseChatDisplay.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseChatDisplay.cs
@@ -3,15 +3,12 @@
using osu.Framework.Testing;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Threading;
using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseChatDisplay : TestCase
{
- private ScheduledDelegate messageRequest;
-
public override string Description => @"Testing chat api and overlay";
public override void Reset()
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs b/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
new file mode 100644
index 0000000000..7ac795f6f9
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
@@ -0,0 +1,42 @@
+// 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.Framework.Testing;
+using osu.Game.Graphics.UserInterface;
+using System.Linq;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseGraph : TestCase
+ {
+ public override string Description => "graph";
+
+ private BarGraph graph;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ Children = new[]
+ {
+ graph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(0.5f),
+ },
+ };
+
+ AddStep("values from 1-10", () => graph.Values = Enumerable.Range(1,10).Select(i => (float)i));
+ AddStep("values from 1-100", () => graph.Values = Enumerable.Range(1, 100).Select(i => (float)i));
+ AddStep("reversed values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Reverse().Select(i => (float)i));
+ AddStep("Bottom to top", () => graph.Direction = BarDirection.BottomToTop);
+ AddStep("Top to bottom", () => graph.Direction = BarDirection.TopToBottom);
+ AddStep("Left to right", () => graph.Direction = BarDirection.LeftToRight);
+ AddStep("Right to left", () => graph.Direction = BarDirection.RightToLeft);
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
index cb7a3e3f84..3d9f3aad79 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
@@ -99,6 +99,7 @@ namespace osu.Desktop.VisualTests.Tests
AddToggleStep(@"auto", state => { auto = state; load(mode); });
+ BasicSliderBar sliderBar;
Add(new Container
{
Anchor = Anchor.TopRight,
@@ -107,16 +108,17 @@ namespace osu.Desktop.VisualTests.Tests
Children = new Drawable[]
{
new SpriteText { Text = "Playback Speed" },
- new BasicSliderBar
+ sliderBar = new BasicSliderBar
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
- Bindable = playbackSpeed
}
}
});
+ sliderBar.Current.BindTo(playbackSpeed);
+
framedClock.ProcessFrame();
var clockAdjustContainer = new Container
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs
index 3dba201f5d..b1b9ddbcda 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs
@@ -44,6 +44,8 @@ namespace osu.Desktop.VisualTests.Tests
kc.Add(new KeyCounterKeyboard(key));
});
+ TestSliderBar sliderBar;
+
Add(new Container
{
Anchor = Anchor.TopRight,
@@ -52,16 +54,17 @@ namespace osu.Desktop.VisualTests.Tests
Children = new Drawable[]
{
new SpriteText { Text = "FadeTime" },
- new TestSliderBar
+ sliderBar =new TestSliderBar
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
- Bindable = bindable
}
}
});
+ sliderBar.Current.BindTo(bindable);
+
Add(kc);
}
private class TestSliderBar : SliderBar where T : struct
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs b/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs
new file mode 100644
index 0000000000..acf98ea86b
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs
@@ -0,0 +1,59 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Logging;
+using osu.Framework.Testing;
+using osu.Game.Screens.Play;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseMenuOverlays : TestCase
+ {
+ public override string Description => @"Tests pause and fail overlays";
+
+ private PauseOverlay pauseOverlay;
+ private FailOverlay failOverlay;
+ private int retryCount;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ retryCount = 0;
+
+ Add(pauseOverlay = new PauseOverlay
+ {
+ OnResume = () => Logger.Log(@"Resume"),
+ OnRetry = () => Logger.Log(@"Retry"),
+ OnQuit = () => Logger.Log(@"Quit"),
+ });
+ Add(failOverlay = new FailOverlay
+ {
+ OnRetry = () => Logger.Log(@"Retry"),
+ OnQuit = () => Logger.Log(@"Quit"),
+ });
+
+ AddStep(@"Pause", delegate {
+ if(failOverlay.State == Visibility.Visible)
+ {
+ failOverlay.Hide();
+ }
+ pauseOverlay.Show();
+ });
+ AddStep("Fail", delegate {
+ if (pauseOverlay.State == Visibility.Visible)
+ {
+ pauseOverlay.Hide();
+ }
+ failOverlay.Show();
+ });
+ AddStep("Add Retry", delegate
+ {
+ retryCount++;
+ pauseOverlay.Retries = retryCount;
+ failOverlay.Retries = retryCount;
+ });
+ }
+ }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs b/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs
index c0c17cd50e..5665bf859a 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs
@@ -30,7 +30,9 @@ namespace osu.Desktop.VisualTests.Tests
Anchor = Anchor.Centre
};
Add(mc);
- AddToggleStep(@"Show", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
+
+ AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
+ AddStep(@"show", () => mc.State = Visibility.Visible);
}
}
}
diff --git a/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs b/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs
deleted file mode 100644
index ebf6e0c350..0000000000
--- a/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Logging;
-using osu.Framework.Testing;
-using osu.Game.Screens.Play;
-
-namespace osu.Desktop.VisualTests.Tests
-{
- internal class TestCasePauseOverlay : TestCase
- {
- public override string Description => @"Tests the pause overlay";
-
- private PauseOverlay pauseOverlay;
- private int retryCount;
-
- public override void Reset()
- {
- base.Reset();
-
- Add(pauseOverlay = new PauseOverlay
- {
- Depth = -1,
- OnResume = () => Logger.Log(@"Resume"),
- OnRetry = () => Logger.Log(@"Retry"),
- OnQuit = () => Logger.Log(@"Quit")
- });
- AddStep("Pause", pauseOverlay.Show);
- AddStep("Add Retry", delegate
- {
- retryCount++;
- pauseOverlay.Retries = retryCount;
- });
-
- retryCount = 0;
- }
- }
-}
diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs b/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs
index aedab7e895..1a43425dda 100644
--- a/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs
@@ -14,7 +14,7 @@ namespace osu.Desktop.VisualTests.Tests
{
internal class TestCasePlaySongSelect : TestCase
{
- private BeatmapDatabase db, oldDb;
+ private BeatmapDatabase db;
private TestStorage storage;
private PlaySongSelect songSelect;
@@ -44,13 +44,13 @@ namespace osu.Desktop.VisualTests.Tests
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
}
- protected override void Dispose(bool isDisposing)
- {
- if (oldDb != null)
- db = null;
+ //protected override void Dispose(bool isDisposing)
+ //{
+ // if (oldDb != null)
+ // db = null;
- base.Dispose(isDisposing);
- }
+ // base.Dispose(isDisposing);
+ //}
private BeatmapSetInfo createTestBeatmapSet(int i)
{
diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
index f36889b02a..624723ed35 100644
--- a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
@@ -83,10 +83,7 @@ namespace osu.Desktop.VisualTests.Tests
Colour = Color4.Black,
});
- Add(new PlayerLoader(Player = CreatePlayer(beatmap))
- {
- Beatmap = beatmap
- });
+ Add(Player = CreatePlayer(beatmap));
}
protected virtual Player CreatePlayer(WorkingBeatmap beatmap)
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs b/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs
index c36fc0a47d..ffdca25bb3 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs
@@ -1,24 +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.Input.Handlers;
using osu.Game.Beatmaps;
using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Mods;
using osu.Game.Screens.Play;
-using System;
-using System.IO;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseReplay : TestCasePlayer
{
- private WorkingBeatmap beatmap;
-
- private InputHandler replay;
-
- private Func getReplayStream;
-
public override string Description => @"Testing replay playback.";
protected override Player CreatePlayer(WorkingBeatmap beatmap)
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
index 55fc969217..f3cca16678 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
@@ -22,8 +22,6 @@ namespace osu.Desktop.VisualTests.Tests
int numerator = 0, denominator = 0;
- bool maniaHold = false;
-
ScoreCounter score = new ScoreCounter(7)
{
Origin = Anchor.TopRight,
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs b/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs
index 23e7f8a74d..b72abd1992 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs
@@ -36,9 +36,9 @@ namespace osu.Desktop.VisualTests.Tests
filter.PinItem(GroupMode.All);
filter.PinItem(GroupMode.RecentlyPlayed);
- filter.ItemChanged += (sender, mode) =>
+ filter.Current.ValueChanged += newFilter =>
{
- text.Text = "Currently Selected: " + mode.ToString();
+ text.Text = "Currently Selected: " + newFilter.ToString();
};
}
}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs
index 4005c94b5a..b3cb8c3457 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs
@@ -1,13 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System.Linq;
using OpenTK;
using OpenTK.Graphics;
-using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
-using osu.Game.Graphics;
-using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Desktop.VisualTests.Tests
{
@@ -24,13 +23,12 @@ namespace osu.Desktop.VisualTests.Tests
AddToggleStep("Kiai", b =>
{
kiai = !kiai;
- Reset();
+ updateKiaiState();
});
Add(new CirclePiece
{
Position = new Vector2(100, 100),
- Width = 0,
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
@@ -39,10 +37,9 @@ namespace osu.Desktop.VisualTests.Tests
}
});
- Add(new StrongCirclePiece
+ Add(new CirclePiece(true)
{
Position = new Vector2(350, 100),
- Width = 0,
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
@@ -54,7 +51,6 @@ namespace osu.Desktop.VisualTests.Tests
Add(new CirclePiece
{
Position = new Vector2(100, 300),
- Width = 0,
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
@@ -63,10 +59,9 @@ namespace osu.Desktop.VisualTests.Tests
}
});
- Add(new StrongCirclePiece
+ Add(new CirclePiece(true)
{
Position = new Vector2(350, 300),
- Width = 0,
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
@@ -78,7 +73,6 @@ namespace osu.Desktop.VisualTests.Tests
Add(new CirclePiece
{
Position = new Vector2(100, 500),
- Width = 0,
AccentColour = Color4.Orange,
KiaiMode = kiai,
Children = new[]
@@ -87,37 +81,29 @@ namespace osu.Desktop.VisualTests.Tests
}
});
- Add(new DrumRollCircle(new CirclePiece
+ Add(new ElongatedCirclePiece
{
- KiaiMode = kiai
- })
- {
- Width = 250,
- Position = new Vector2(575, 100)
+ Position = new Vector2(575, 100),
+ AccentColour = Color4.Orange,
+ KiaiMode = kiai,
+ Length = 0.10f,
+ PlayfieldLengthReference = () => DrawSize.X
});
- Add(new DrumRollCircle(new StrongCirclePiece
+ Add(new ElongatedCirclePiece(true)
{
- KiaiMode = kiai
- })
- {
- Width = 250,
- Position = new Vector2(575, 300)
+ Position = new Vector2(575, 300),
+ AccentColour = Color4.Orange,
+ KiaiMode = kiai,
+ Length = 0.10f,
+ PlayfieldLengthReference = () => DrawSize.X
});
}
- private class DrumRollCircle : BaseCircle
+ private void updateKiaiState()
{
- public DrumRollCircle(CirclePiece piece)
- : base(piece)
- {
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- Piece.AccentColour = colours.YellowDark;
- }
+ foreach (var c in Children.OfType())
+ c.KiaiMode = kiai;
}
private abstract class BaseCircle : Container
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
index c0aa3af176..4e9ff4980e 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
@@ -1,24 +1,33 @@
// 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.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Primitives;
using osu.Framework.MathUtils;
using osu.Framework.Testing;
+using osu.Framework.Timing;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
-using osu.Game.Modes.Taiko.Objects.Drawable;
+using osu.Game.Modes.Taiko.Objects.Drawables;
using osu.Game.Modes.Taiko.UI;
+using System;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseTaikoPlayfield : TestCase
{
+ private const double default_duration = 300;
+ private const float scroll_time = 1000;
+
public override string Description => "Taiko playfield";
+ protected override double TimePerAction => default_duration * 2;
+
+ private readonly Random rng = new Random(1337);
private TaikoPlayfield playfield;
+ private Container playfieldContainer;
public override void Reset()
{
@@ -26,17 +35,31 @@ namespace osu.Desktop.VisualTests.Tests
AddStep("Hit!", addHitJudgement);
AddStep("Miss :(", addMissJudgement);
- AddStep("Swell", addSwell);
+ AddStep("DrumRoll", () => addDrumRoll(false));
+ AddStep("Strong DrumRoll", () => addDrumRoll(true));
+ AddStep("Swell", () => addSwell());
AddStep("Centre", () => addCentreHit(false));
AddStep("Strong Centre", () => addCentreHit(true));
AddStep("Rim", () => addRimHit(false));
AddStep("Strong Rim", () => addRimHit(true));
+ AddStep("Add bar line", () => addBarLine(false));
+ AddStep("Add major bar line", () => addBarLine(true));
+ AddStep("Height test 1", () => changePlayfieldSize(1));
+ AddStep("Height test 2", () => changePlayfieldSize(2));
+ AddStep("Height test 3", () => changePlayfieldSize(3));
+ AddStep("Height test 4", () => changePlayfieldSize(4));
+ AddStep("Height test 5", () => changePlayfieldSize(5));
+ AddStep("Reset height", () => changePlayfieldSize(6));
- Add(new Container
+ var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
+
+ Add(playfieldContainer = new Container
{
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
- Y = 200,
- Padding = new MarginPadding { Left = 200 },
+ Height = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT,
+ Clock = new FramedClock(rateAdjustClock),
Children = new[]
{
playfield = new TaikoPlayfield()
@@ -44,21 +67,63 @@ namespace osu.Desktop.VisualTests.Tests
});
}
+ private void changePlayfieldSize(int step)
+ {
+ // Add new hits
+ switch (step)
+ {
+ case 1:
+ addCentreHit(false);
+ break;
+ case 2:
+ addCentreHit(true);
+ break;
+ case 3:
+ addDrumRoll(false);
+ break;
+ case 4:
+ addDrumRoll(true);
+ break;
+ case 5:
+ addSwell(1000);
+ playfieldContainer.Delay(scroll_time - 100);
+ break;
+ }
+
+ // Tween playfield height
+ switch (step)
+ {
+ default:
+ playfieldContainer.ResizeTo(new Vector2(1, rng.Next(25, 400)), 500);
+ break;
+ case 6:
+ playfieldContainer.ResizeTo(new Vector2(1, TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT), 500);
+ break;
+ }
+ }
+
private void addHitJudgement()
{
TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great;
- playfield.OnJudgement(new DrawableTestHit(new Hit())
+ var h = new DrawableTestHit(new 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,
- SecondHit = RNG.Next(10) == 0
+ TimeOffset = 0
}
- });
+ };
+
+ playfield.OnJudgement(h);
+
+ if (RNG.Next(10) == 0)
+ {
+ h.Judgement.SecondHit = true;
+ playfield.OnJudgement(h);
+ }
}
private void addMissJudgement()
@@ -73,26 +138,53 @@ namespace osu.Desktop.VisualTests.Tests
});
}
- private void addSwell()
+ private void addBarLine(bool major, double delay = scroll_time)
+ {
+ BarLine bl = new BarLine
+ {
+ StartTime = playfield.Time.Current + delay,
+ ScrollTime = scroll_time
+ };
+
+ playfield.AddBarLine(major ? new DrawableBarLineMajor(bl) : new DrawableBarLine(bl));
+ }
+
+ private void addSwell(double duration = default_duration)
{
playfield.Add(new DrawableSwell(new Swell
{
- StartTime = Time.Current + 1000,
- EndTime = Time.Current + 5000,
- PreEmpt = 1000
+ StartTime = playfield.Time.Current + scroll_time,
+ Duration = duration,
+ ScrollTime = scroll_time
}));
}
+ private void addDrumRoll(bool strong, double duration = default_duration)
+ {
+ addBarLine(true);
+ addBarLine(true, scroll_time + duration);
+
+ var d = new DrumRoll
+ {
+ StartTime = playfield.Time.Current + scroll_time,
+ IsStrong = strong,
+ Duration = duration,
+ ScrollTime = scroll_time,
+ };
+
+ playfield.Add(new DrawableDrumRoll(d));
+ }
+
private void addCentreHit(bool strong)
{
Hit h = new Hit
{
- StartTime = Time.Current + 1000,
- PreEmpt = 1000
+ StartTime = playfield.Time.Current + scroll_time,
+ ScrollTime = scroll_time
};
if (strong)
- playfield.Add(new DrawableStrongCentreHit(h));
+ playfield.Add(new DrawableCentreHitStrong(h));
else
playfield.Add(new DrawableCentreHit(h));
}
@@ -101,12 +193,12 @@ namespace osu.Desktop.VisualTests.Tests
{
Hit h = new Hit
{
- StartTime = Time.Current + 1000,
- PreEmpt = 1000
+ StartTime = playfield.Time.Current + scroll_time,
+ ScrollTime = scroll_time
};
if (strong)
- playfield.Add(new DrawableStrongRimHit(h));
+ playfield.Add(new DrawableRimHitStrong(h));
else
playfield.Add(new DrawableRimHit(h));
}
diff --git a/osu.Desktop.VisualTests/VisualTestGame.cs b/osu.Desktop.VisualTests/VisualTestGame.cs
index 0392dc5443..e0d168390b 100644
--- a/osu.Desktop.VisualTests/VisualTestGame.cs
+++ b/osu.Desktop.VisualTests/VisualTestGame.cs
@@ -14,7 +14,7 @@ namespace osu.Desktop.VisualTests
{
base.LoadComplete();
- new BackgroundScreenDefault { Depth = 10 }.LoadAsync(this, AddInternal);
+ LoadComponentAsync(new BackgroundScreenDefault { Depth = 10 }, AddInternal);
// Have to construct this here, rather than in the constructor, because
// we depend on some dependencies to be loaded within OsuGameBase.load().
diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
index b117515433..bfabf0081c 100644
--- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
+++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
@@ -83,22 +83,20 @@
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+
+ $(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
-
- ..\packages\SharpCompress.0.15.1\lib\net45\SharpCompress.dll
- True
+
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+
+ $(SolutionDir)\packages\SharpCompress.0.15.2\lib\net45\SharpCompress.dll
False
$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll
-
- $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
-
$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll
@@ -187,8 +185,11 @@
+
+
+
@@ -207,7 +208,6 @@
-
diff --git a/osu.Desktop.VisualTests/packages.config b/osu.Desktop.VisualTests/packages.config
index 5a30c50600..cad2ffff0d 100644
--- a/osu.Desktop.VisualTests/packages.config
+++ b/osu.Desktop.VisualTests/packages.config
@@ -4,9 +4,9 @@ Copyright (c) 2007-2017 ppy Pty Ltd .
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
-
-
-
+
+
+
diff --git a/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs b/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs
index 0ef448cafe..abc45d82ec 100644
--- a/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs
+++ b/osu.Desktop/Beatmaps/IO/LegacyFilesystemReader.cs
@@ -3,10 +3,7 @@
using System.IO;
using System.Linq;
-using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
-using osu.Game.Beatmaps;
-using osu.Game.Database;
namespace osu.Desktop.Beatmaps.IO
{
@@ -18,20 +15,17 @@ namespace osu.Desktop.Beatmaps.IO
public static void Register() => AddReader((storage, path) => Directory.Exists(path));
private string basePath { get; }
- private Beatmap firstMap { get; }
public LegacyFilesystemReader(string path)
{
basePath = path;
+
BeatmapFilenames = Directory.GetFiles(basePath, @"*.osu").Select(Path.GetFileName).ToArray();
+
if (BeatmapFilenames.Length == 0)
throw new FileNotFoundException(@"This directory contains no beatmaps");
+
StoryboardFilename = Directory.GetFiles(basePath, @"*.osb").Select(Path.GetFileName).FirstOrDefault();
- using (var stream = new StreamReader(GetStream(BeatmapFilenames[0])))
- {
- var decoder = BeatmapDecoder.GetDecoder(stream);
- firstMap = decoder.Decode(stream);
- }
}
public override Stream GetStream(string name)
@@ -39,11 +33,6 @@ namespace osu.Desktop.Beatmaps.IO
return File.OpenRead(Path.Combine(basePath, name));
}
- public override BeatmapMetadata ReadMetadata()
- {
- return firstMap.BeatmapInfo.Metadata;
- }
-
public override void Dispose()
{
// no-op
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 95870125e3..c2bb39ac4a 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -29,7 +29,7 @@ namespace osu.Desktop
{
base.LoadComplete();
- versionManager.LoadAsync(this);
+ LoadComponentAsync(versionManager);
ScreenChanged += s =>
{
if (!versionManager.IsAlive && s is Intro)
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index 70925f6cf4..9532652bfe 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -189,19 +189,24 @@ namespace osu.Desktop.Overlays
private class UpdateProgressNotification : ProgressNotification
{
+ private OsuGame game;
+
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification()
{
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
- UpdateManager.RestartApp();
+ UpdateManager.RestartAppWhenExited();
+ game.GracefullyExit();
return true;
}
};
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OsuColour colours, OsuGame game)
{
+ this.game = game;
+
IconContent.Add(new Drawable[]
{
new Box
diff --git a/osu.Desktop/Properties/AssemblyInfo.cs b/osu.Desktop/Properties/AssemblyInfo.cs
index eacfc996d5..fe7ad20124 100644
--- a/osu.Desktop/Properties/AssemblyInfo.cs
+++ b/osu.Desktop/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu!lazer")]
@@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index fbc342d695..dbd26b4640 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -124,8 +124,7 @@
True
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll
diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config
index be9b65f0c6..60e8182c82 100644
--- a/osu.Desktop/packages.config
+++ b/osu.Desktop/packages.config
@@ -7,7 +7,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Catch/Properties/AssemblyInfo.cs b/osu.Game.Modes.Catch/Properties/AssemblyInfo.cs
index 07a088e1e9..1d25411e73 100644
--- a/osu.Game.Modes.Catch/Properties/AssemblyInfo.cs
+++ b/osu.Game.Modes.Catch/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Catch")]
@@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/osu.Game.Modes.Catch/UI/CatchPlayfield.cs b/osu.Game.Modes.Catch/UI/CatchPlayfield.cs
index cf1a665470..f8792a7fd5 100644
--- a/osu.Game.Modes.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Modes.Catch/UI/CatchPlayfield.cs
@@ -14,8 +14,7 @@ namespace osu.Game.Modes.Catch.UI
{
public CatchPlayfield()
{
- RelativeSizeAxes = Axes.Y;
- Size = new Vector2(512, 0.9f);
+ Size = new Vector2(1, 0.9f);
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
diff --git a/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj b/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj
index 593d8db4f6..50b1a095af 100644
--- a/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj
+++ b/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj
@@ -33,8 +33,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -84,7 +83,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Mania/Properties/AssemblyInfo.cs b/osu.Game.Modes.Mania/Properties/AssemblyInfo.cs
index 6cfa3c42b3..11c8290f1b 100644
--- a/osu.Game.Modes.Mania/Properties/AssemblyInfo.cs
+++ b/osu.Game.Modes.Mania/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Mania")]
@@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs b/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs
index 670d18f71f..deb4ebac25 100644
--- a/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs
@@ -15,8 +15,7 @@ namespace osu.Game.Modes.Mania.UI
{
public ManiaPlayfield(int columns)
{
- RelativeSizeAxes = Axes.Both;
- Size = new Vector2(columns / 20f, 1f);
+ Size = new Vector2(0.8f, 1f);
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
diff --git a/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj b/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj
index cc925d417a..896e9c68c6 100644
--- a/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj
+++ b/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj
@@ -33,8 +33,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -89,7 +88,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Modes.Osu/Beatmaps/OsuBeatmapConverter.cs
index fec675be54..bae12a98e3 100644
--- a/osu.Game.Modes.Osu/Beatmaps/OsuBeatmapConverter.cs
+++ b/osu.Game.Modes.Osu/Beatmaps/OsuBeatmapConverter.cs
@@ -43,7 +43,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Slider
{
StartTime = original.StartTime,
- Sample = original.Sample,
+ Samples = original.Samples,
CurveObject = curveData,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
@@ -55,7 +55,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Spinner
{
StartTime = original.StartTime,
- Sample = original.Sample,
+ Samples = original.Samples,
Position = new Vector2(512, 384) / 2,
EndTime = endTimeData.EndTime
};
@@ -64,7 +64,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new HitCircle
{
StartTime = original.StartTime,
- Sample = original.Sample,
+ Samples = original.Samples,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
};
diff --git a/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs
index efbd5b291a..7815e3ba41 100644
--- a/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs
+++ b/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Connections
Colour = Color4.White.Opacity(0.2f),
Radius = 4,
};
-
+
Children = new Drawable[]
{
new Box
diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs
index e8f2154d7f..be326751ba 100644
--- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ComboIndex = s.ComboIndex,
Scale = s.Scale,
ComboColour = s.ComboColour,
- Sample = s.Sample,
+ Samples = s.Samples,
}),
};
@@ -111,7 +111,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
if (repeat > currentRepeat)
{
if (repeat < slider.RepeatCount && ball.Tracking)
- PlaySample();
+ PlaySamples();
currentRepeat = repeat;
}
diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs
index be66689054..188306c857 100644
--- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -2,12 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
-using osu.Framework.Allocation;
-using osu.Framework.Audio;
-using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
@@ -53,22 +49,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
};
}
- private SampleChannel sample;
-
- [BackgroundDependencyLoader]
- private void load(AudioManager audio)
- {
- string sampleSet = (HitObject.Sample?.Set ?? SampleSet.Normal).ToString().ToLower();
-
- sample = audio.Sample.Get($@"Gameplay/{sampleSet}-slidertick");
- }
-
- protected override void PlaySample()
- {
- sample?.Play();
- }
-
-
protected override void CheckJudgement(bool userTriggered)
{
if (Judgement.TimeOffset >= 0)
@@ -77,7 +57,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Judgement.Score = Tracking ? OsuScoreResult.SliderTick : OsuScoreResult.Miss;
}
}
-
+
protected override void UpdatePreemptState()
{
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);
diff --git a/osu.Game.Modes.Osu/Objects/Slider.cs b/osu.Game.Modes.Osu/Objects/Slider.cs
index 213a4a7bee..a01c517cb2 100644
--- a/osu.Game.Modes.Osu/Objects/Slider.cs
+++ b/osu.Game.Modes.Osu/Objects/Slider.cs
@@ -2,18 +2,24 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using osu.Game.Modes.Objects;
using osu.Game.Database;
+using System.Linq;
+using osu.Game.Audio;
namespace osu.Game.Modes.Osu.Objects
{
public class Slider : OsuHitObject, IHasCurve
{
+ ///
+ /// Scoring distance with a speed-adjusted beat length of 1 second.
+ ///
+ private const float base_scoring_distance = 100;
+
public IHasCurve CurveObject { get; set; }
public SliderCurve Curve => CurveObject.Curve;
@@ -51,13 +57,10 @@ namespace osu.Game.Modes.Osu.Objects
{
base.ApplyDefaults(timing, difficulty);
- ControlPoint overridePoint;
- ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
- var velocityAdjustment = overridePoint?.VelocityAdjustment ?? 1;
- var baseVelocity = 100 * difficulty.SliderMultiplier / velocityAdjustment;
+ double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / timing.SpeedMultiplierAt(StartTime);
- Velocity = baseVelocity / timingPoint.BeatLength;
- TickDistance = baseVelocity / difficulty.SliderTickRate;
+ Velocity = scoringDistance / timing.BeatLengthAt(StartTime);
+ TickDistance = scoringDistance / difficulty.SliderTickRate;
}
public IEnumerable Ticks
@@ -93,11 +96,12 @@ namespace osu.Game.Modes.Osu.Objects
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
- Sample = new HitSampleInfo
+ Samples = Samples.Select(s => new SampleInfo
{
- Type = SampleType.None,
- Set = SampleSet.Soft,
- },
+ Bank = s.Bank,
+ Name = @"slidertick",
+ Volume = s.Volume
+ }).ToList()
};
}
}
diff --git a/osu.Game.Modes.Osu/OsuKeyConversionInputManager.cs b/osu.Game.Modes.Osu/OsuKeyConversionInputManager.cs
index 986240b37f..567c7a35b1 100644
--- a/osu.Game.Modes.Osu/OsuKeyConversionInputManager.cs
+++ b/osu.Game.Modes.Osu/OsuKeyConversionInputManager.cs
@@ -42,14 +42,14 @@ namespace osu.Game.Modes.Osu
{
if (mouseDisabled.Value)
{
- mouse.PressedButtons.Remove(MouseButton.Left);
- mouse.PressedButtons.Remove(MouseButton.Right);
+ mouse.SetPressed(MouseButton.Left, false);
+ mouse.SetPressed(MouseButton.Right, false);
}
if (leftViaKeyboard)
- mouse.PressedButtons.Add(MouseButton.Left);
+ mouse.SetPressed(MouseButton.Left, true);
if (rightViaKeyboard)
- mouse.PressedButtons.Add(MouseButton.Right);
+ mouse.SetPressed(MouseButton.Right, true);
}
}
}
diff --git a/osu.Game.Modes.Osu/Properties/AssemblyInfo.cs b/osu.Game.Modes.Osu/Properties/AssemblyInfo.cs
index 61e6ae6f7a..791c9b594d 100644
--- a/osu.Game.Modes.Osu/Properties/AssemblyInfo.cs
+++ b/osu.Game.Modes.Osu/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Mode.Osu")]
@@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs
index 0bd587e8ea..3b798a2fad 100644
--- a/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs
+++ b/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs
@@ -35,11 +35,9 @@ namespace osu.Game.Modes.Osu.Scoring
switch (judgement.Result)
{
case HitResult.Hit:
- Combo.Value++;
Health.Value += 0.1f;
break;
case HitResult.Miss:
- Combo.Value = 0;
Health.Value -= 0.2f;
break;
}
diff --git a/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs b/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs
index ca9ff6fc61..7e314c5ba1 100644
--- a/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs
+++ b/osu.Game.Modes.Osu/UI/OsuHitRenderer.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 OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Beatmaps;
@@ -46,5 +47,7 @@ namespace osu.Game.Modes.Osu.UI
return new DrawableSpinner(spinner);
return null;
}
+
+ protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
}
}
diff --git a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs
index 8090263fe1..4164607b4d 100644
--- a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs
@@ -21,6 +21,8 @@ namespace osu.Game.Modes.Osu.UI
private readonly Container judgementLayer;
private readonly ConnectionRenderer connectionLayer;
+ public override bool ProvidingUserCursor => true;
+
public override Vector2 Size
{
get
@@ -36,8 +38,6 @@ namespace osu.Game.Modes.Osu.UI
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
- RelativeSizeAxes = Axes.Both;
- Size = new Vector2(0.75f);
Add(new Drawable[]
{
diff --git a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj
index 55322e855e..21f0f03d8c 100644
--- a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj
+++ b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj
@@ -34,8 +34,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -104,7 +103,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs
index cc361628a3..aee06ad796 100644
--- a/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs
+++ b/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs
@@ -2,96 +2,160 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
-using osu.Game.Beatmaps.Legacy;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Taiko.Objects;
+using System;
using System.Collections.Generic;
using System.Linq;
+using osu.Game.Database;
+using osu.Game.IO.Serialization;
+using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Beatmaps
{
internal class TaikoBeatmapConverter : IBeatmapConverter
{
- private const float legacy_velocity_scale = 1.4f;
- private const float bash_convert_factor = 1.65f;
+ ///
+ /// osu! is generally slower than taiko, so a factor is added to increase
+ /// speed. This must be used everywhere slider length or beat length is used.
+ ///
+ private const float legacy_velocity_multiplier = 1.4f;
+
+ ///
+ /// Because swells are easier in taiko than spinners are in osu!,
+ /// legacy taiko multiplies a factor when converting the number of required hits.
+ ///
+ private const float swell_hit_multiplier = 1.65f;
+
+ ///
+ /// Base osu! slider scoring distance.
+ ///
+ private const float osu_base_scoring_distance = 100;
+
+ ///
+ /// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
+ ///
+ private const float taiko_base_distance = 100;
public Beatmap Convert(Beatmap original)
{
- if (original is LegacyBeatmap)
- original.TimingInfo.ControlPoints.ForEach(c => c.VelocityAdjustment /= legacy_velocity_scale);
+ BeatmapInfo info = original.BeatmapInfo.DeepClone();
+ info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier;
return new Beatmap(original)
{
- HitObjects = convertHitObjects(original.HitObjects)
+ BeatmapInfo = info,
+ HitObjects = original.HitObjects.SelectMany(h => convertHitObject(h, original)).ToList()
};
}
- private List convertHitObjects(List hitObjects)
- {
- return hitObjects.Select(convertHitObject).ToList();
- }
-
- private TaikoHitObject convertHitObject(HitObject original)
+ private IEnumerable convertHitObject(HitObject obj, Beatmap beatmap)
{
// Check if this HitObject is already a TaikoHitObject, and return it if so
- TaikoHitObject originalTaiko = original as TaikoHitObject;
+ var originalTaiko = obj as TaikoHitObject;
if (originalTaiko != null)
- return originalTaiko;
+ yield return originalTaiko;
- IHasDistance distanceData = original as IHasDistance;
- IHasRepeats repeatsData = original as IHasRepeats;
- IHasEndTime endTimeData = original as IHasEndTime;
+ var distanceData = obj as IHasDistance;
+ var repeatsData = obj as IHasRepeats;
+ var endTimeData = obj as IHasEndTime;
// Old osu! used hit sounding to determine various hit type information
- SampleType sample = original.Sample?.Type ?? SampleType.None;
+ List samples = obj.Samples;
- bool strong = (sample & SampleType.Finish) > 0;
+ bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH);
if (distanceData != null)
{
- return new DrumRoll
+ int repeats = repeatsData?.RepeatCount ?? 1;
+
+ double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(obj.StartTime);
+ double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(obj.StartTime) * speedAdjustment;
+
+ // The true distance, accounting for any repeats. This ends up being the drum roll distance later
+ double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
+
+ // The velocity of the taiko hit object - calculated as the velocity of a drum roll
+ double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
+ // The duration of the taiko hit object
+ double taikoDuration = distance / taikoVelocity;
+
+ // For some reason, old osu! always uses speedAdjustment to determine the taiko velocity, but
+ // only uses it to determine osu! velocity if beatmap version < 8. Let's account for that here.
+ if (beatmap.BeatmapInfo.BeatmapVersion >= 8)
+ speedAdjustedBeatLength /= speedAdjustment;
+
+ // The velocity of the osu! hit object - calculated as the velocity of a slider
+ double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
+ // The duration of the osu! hit object
+ double osuDuration = distance / osuVelocity;
+
+ // If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
+ double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats) / 8;
+
+ if (tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
{
- StartTime = original.StartTime,
- Sample = original.Sample,
+ for (double j = obj.StartTime; j <= distanceData.EndTime + tickSpacing; j += tickSpacing)
+ {
+ // Todo: This should generate different type of hits (including strongs)
+ // depending on hitobject sound additions (not implemented fully yet)
+ yield return new CentreHit
+ {
+ StartTime = j,
+ Samples = obj.Samples,
+ IsStrong = strong,
+ };
+ }
+ }
+ else
+ {
+ yield return new DrumRoll
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
+ IsStrong = strong,
+ Duration = taikoDuration,
+ TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4,
+ };
+ }
+ }
+ else if (endTimeData != null)
+ {
+ double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier;
+
+ yield return new Swell
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
IsStrong = strong,
-
- Distance = distanceData.Distance * (repeatsData?.RepeatCount ?? 1)
+ Duration = endTimeData.Duration,
+ RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
};
}
-
- if (endTimeData != null)
+ else
{
- // We compute the end time manually to add in the Bash convert factor
- return new Swell
+ bool isRim = samples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE);
+
+ if (isRim)
{
- StartTime = original.StartTime,
- Sample = original.Sample,
- IsStrong = strong,
-
- EndTime = original.StartTime + endTimeData.Duration * bash_convert_factor
- };
- }
-
- bool isCentre = (sample & ~(SampleType.Finish | SampleType.Normal)) == 0;
-
- if (isCentre)
- {
- return new CentreHit
+ yield return new RimHit
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
+ IsStrong = strong,
+ };
+ }
+ else
{
- StartTime = original.StartTime,
- Sample = original.Sample,
- IsStrong = strong
- };
+ yield return new CentreHit
+ {
+ StartTime = obj.StartTime,
+ Samples = obj.Samples,
+ IsStrong = strong,
+ };
+ }
}
-
- return new RimHit
- {
- StartTime = original.StartTime,
- Sample = original.Sample,
- IsStrong = strong,
- };
}
}
}
diff --git a/osu.Game.Modes.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Modes.Taiko/Judgements/TaikoDrumRollTickJudgement.cs
index b6a727aeb4..6ae476b265 100644
--- a/osu.Game.Modes.Taiko/Judgements/TaikoDrumRollTickJudgement.cs
+++ b/osu.Game.Modes.Taiko/Judgements/TaikoDrumRollTickJudgement.cs
@@ -15,6 +15,8 @@ namespace osu.Game.Modes.Taiko.Judgements
///
public override string MaxResultString => string.Empty;
+ public override bool AffectsCombo => false;
+
protected override int NumericResultForScore(TaikoHitResult result)
{
switch (result)
diff --git a/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs
index f4745730db..7676ef8c29 100644
--- a/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs
+++ b/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs
@@ -3,6 +3,7 @@
using osu.Game.Modes.Judgements;
using osu.Framework.Extensions;
+using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Taiko.Judgements
{
@@ -21,12 +22,12 @@ namespace osu.Game.Modes.Taiko.Judgements
///
/// The result value for the combo portion of the score.
///
- public int ResultValueForScore => NumericResultForScore(TaikoResult);
+ public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(TaikoResult);
///
/// The result value for the accuracy portion of the score.
///
- public int ResultValueForAccuracy => NumericResultForAccuracy(TaikoResult);
+ public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(TaikoResult);
///
/// The maximum result value for the combo portion of the score.
@@ -43,7 +44,7 @@ namespace osu.Game.Modes.Taiko.Judgements
public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
///
- /// Whether this Judgement has a secondary hit in the case of finishers.
+ /// Whether this Judgement has a secondary hit in the case of strong hits.
///
public virtual bool SecondHit { get; set; }
diff --git a/osu.Game/Beatmaps/Samples/HitSampleInfo.cs b/osu.Game.Modes.Taiko/Objects/BarLine.cs
similarity index 55%
rename from osu.Game/Beatmaps/Samples/HitSampleInfo.cs
rename to osu.Game.Modes.Taiko/Objects/BarLine.cs
index c1cf1bd5e5..ae3c03de5e 100644
--- a/osu.Game/Beatmaps/Samples/HitSampleInfo.cs
+++ b/osu.Game.Modes.Taiko/Objects/BarLine.cs
@@ -1,10 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-namespace osu.Game.Beatmaps.Samples
+namespace osu.Game.Modes.Taiko.Objects
{
- public class HitSampleInfo : SampleInfo
+ public class BarLine : TaikoHitObject
{
- public SampleType Type { get; set; }
}
}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRoll.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRoll.cs
deleted file mode 100644
index 3551538fe7..0000000000
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRoll.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Modes.Objects.Drawables;
-using osu.Game.Modes.Taiko.Judgements;
-using System.Linq;
-
-namespace osu.Game.Modes.Taiko.Objects.Drawable
-{
- public class DrawableDrumRoll : DrawableTaikoHitObject
- {
- private readonly DrumRoll drumRoll;
-
- public DrawableDrumRoll(DrumRoll drumRoll)
- : base(drumRoll)
- {
- this.drumRoll = drumRoll;
-
- int tickIndex = 0;
- foreach (var tick in drumRoll.Ticks)
- {
- var newTick = new DrawableDrumRollTick(tick)
- {
- Depth = tickIndex,
- X = (float)((tick.StartTime - HitObject.StartTime) / drumRoll.Duration)
- };
-
- AddNested(newTick);
-
- tickIndex++;
- }
- }
-
- protected override void UpdateState(ArmedState state)
- {
- }
-
- protected override void CheckJudgement(bool userTriggered)
- {
- if (userTriggered)
- return;
-
- if (Judgement.TimeOffset < 0)
- return;
-
- int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
-
- if (countHit > drumRoll.RequiredGoodHits)
- {
- Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = countHit >= drumRoll.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
- }
- else
- Judgement.Result = HitResult.Miss;
- }
- }
-}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongCentreHit.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongCentreHit.cs
deleted file mode 100644
index b4ec0b108a..0000000000
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongCentreHit.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using OpenTK.Input;
-using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
-using osu.Framework.Allocation;
-using osu.Game.Graphics;
-
-namespace osu.Game.Modes.Taiko.Objects.Drawable
-{
- public class DrawableStrongCentreHit : DrawableStrongHit
- {
- protected override Key[] HitKeys { get; } = { Key.F, Key.J };
-
- private readonly CirclePiece circlePiece;
-
- public DrawableStrongCentreHit(Hit hit)
- : base(hit)
- {
- Add(circlePiece = new StrongCirclePiece
- {
- Children = new []
- {
- new CentreHitSymbolPiece()
- }
- });
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- circlePiece.AccentColour = colours.PinkDarker;
- }
- }
-}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongRimHit.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongRimHit.cs
deleted file mode 100644
index 1f77ad0409..0000000000
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongRimHit.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Allocation;
-using osu.Game.Graphics;
-using OpenTK.Input;
-using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
-
-namespace osu.Game.Modes.Taiko.Objects.Drawable
-{
- public class DrawableStrongRimHit : DrawableStrongHit
- {
- protected override Key[] HitKeys { get; } = { Key.D, Key.K };
-
- private readonly CirclePiece circlePiece;
-
- public DrawableStrongRimHit(Hit hit)
- : base(hit)
- {
- Add(circlePiece = new StrongCirclePiece
- {
- Children = new[]
- {
- new RimHitSymbolPiece()
- }
- });
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- circlePiece.AccentColour = colours.BlueDarker;
- }
- }
-}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/CirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/CirclePiece.cs
deleted file mode 100644
index 2321ad30ee..0000000000
--- a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/CirclePiece.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics.Backgrounds;
-using OpenTK.Graphics;
-using System;
-using osu.Game.Graphics;
-
-namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
-{
- ///
- /// A circle piece which is used uniformly through osu!taiko to visualise hitobjects.
- ///
- /// The body of this piece will overshoot its parent by to form
- /// a rounded (_[-Width-]_) figure such that a regular "circle" is the result of a parent with Width = 0.
- ///
- ///
- public class CirclePiece : Container, IHasAccentColour
- {
- public const float SYMBOL_SIZE = TaikoHitObject.CIRCLE_RADIUS * 2f * 0.45f;
- public const float SYMBOL_BORDER = 8;
- public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER;
-
- private Color4 accentColour;
- ///
- /// The colour of the inner circle and outer glows.
- ///
- public Color4 AccentColour
- {
- get { return accentColour; }
- set
- {
- accentColour = value;
-
- innerBackground.Colour = AccentColour;
-
- triangles.ColourLight = AccentColour;
- triangles.ColourDark = AccentColour.Darken(0.1f);
-
- resetEdgeEffects();
- }
- }
-
- private bool kiaiMode;
- ///
- /// Whether Kiai mode effects are enabled for this circle piece.
- ///
- public bool KiaiMode
- {
- get { return kiaiMode; }
- set
- {
- kiaiMode = value;
-
- resetEdgeEffects();
- }
- }
-
- public override Anchor Origin
- {
- get { return Anchor.CentreLeft; }
- set { throw new InvalidOperationException($"{nameof(CirclePiece)} must always use CentreLeft origin."); }
- }
-
- protected override Container Content => SymbolContainer;
- protected readonly Container SymbolContainer;
-
- private readonly Container innerLayer;
- private readonly Container innerCircleContainer;
- private readonly Box innerBackground;
- private readonly Triangles triangles;
-
- public CirclePiece()
- {
- RelativeSizeAxes = Axes.X;
- Height = TaikoHitObject.CIRCLE_RADIUS * 2;
-
- // The "inner layer" is the body of the CirclePiece that overshoots it by Height/2 px on both sides
- AddInternal(innerLayer = new Container
- {
- Name = "Inner Layer",
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Y,
- Children = new Framework.Graphics.Drawable[]
- {
- innerCircleContainer = new CircularContainer
- {
- Name = "Inner Circle",
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- Children = new Framework.Graphics.Drawable[]
- {
- innerBackground = new Box
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- },
- triangles = new Triangles
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- }
- }
- },
- new CircularContainer
- {
- Name = "Ring",
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- BorderThickness = 8,
- BorderColour = Color4.White,
- Masking = true,
- Children = new[]
- {
- new Box
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Alpha = 0,
- AlwaysPresent = true
- }
- }
- },
- SymbolContainer = new Container
- {
- Name = "Symbol",
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- }
- }
- });
- }
-
- protected override void Update()
- {
- // Add the overshoot to compensate for corner radius
- innerLayer.Width = DrawWidth + DrawHeight;
- }
-
- private void resetEdgeEffects()
- {
- innerCircleContainer.EdgeEffect = new EdgeEffect
- {
- Type = EdgeEffectType.Glow,
- Colour = AccentColour,
- Radius = KiaiMode ? 50 : 8
- };
- }
- }
-}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/StrongCirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/StrongCirclePiece.cs
deleted file mode 100644
index 319ca17cb8..0000000000
--- a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/StrongCirclePiece.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using OpenTK;
-
-namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
-{
- ///
- /// A type of circle piece which is drawn at a higher scale to represent a "strong" piece.
- ///
- public class StrongCirclePiece : CirclePiece
- {
- ///
- /// The amount to scale up the base circle to show it as a "strong" piece.
- ///
- private const float strong_scale = 1.5f;
-
- public StrongCirclePiece()
- {
- SymbolContainer.Scale = new Vector2(strong_scale);
- }
-
- public override Vector2 Size => new Vector2(base.Size.X, base.Size.Y * strong_scale);
- }
-}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableBarLine.cs
new file mode 100644
index 0000000000..59f8aca867
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableBarLine.cs
@@ -0,0 +1,80 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using OpenTK;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables
+{
+ ///
+ /// A line that scrolls alongside hit objects in the playfield and visualises control points.
+ ///
+ public class DrawableBarLine : Container
+ {
+ ///
+ /// The width of the line tracker.
+ ///
+ private const float tracker_width = 2f;
+
+ ///
+ /// Fade out time calibrated to a pre-empt of 1000ms.
+ ///
+ private const float base_fadeout_time = 100f;
+
+ ///
+ /// The visual line tracker.
+ ///
+ protected Box Tracker;
+
+ ///
+ /// The bar line.
+ ///
+ protected readonly BarLine BarLine;
+
+ public DrawableBarLine(BarLine barLine)
+ {
+ BarLine = barLine;
+
+ Anchor = Anchor.CentreLeft;
+ Origin = Anchor.Centre;
+
+ RelativePositionAxes = Axes.X;
+ RelativeSizeAxes = Axes.Y;
+
+ Width = tracker_width;
+
+ Children = new[]
+ {
+ Tracker = new Box
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ EdgeSmoothness = new Vector2(0.5f, 0),
+ Alpha = 0.75f
+ }
+ };
+
+ LifetimeStart = BarLine.StartTime - BarLine.ScrollTime * 2;
+ LifetimeEnd = BarLine.StartTime + BarLine.ScrollTime;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ Delay(BarLine.StartTime - Time.Current);
+ FadeOut(base_fadeout_time * BarLine.ScrollTime / 1000);
+ }
+
+ private void updateScrollPosition(double time) => MoveToX((float)((BarLine.StartTime - time) / BarLine.ScrollTime));
+
+ protected override void Update()
+ {
+ base.Update();
+
+ updateScrollPosition(Time.Current);
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableBarLineMajor.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
new file mode 100644
index 0000000000..73565e6948
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
@@ -0,0 +1,57 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using OpenTK;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables
+{
+ public class DrawableBarLineMajor : DrawableBarLine
+ {
+ ///
+ /// The vertical offset of the triangles from the line tracker.
+ ///
+ private const float triangle_offfset = 10f;
+
+ ///
+ /// The size of the triangles.
+ ///
+ private const float triangle_size = 20f;
+
+ public DrawableBarLineMajor(BarLine barLine)
+ : base(barLine)
+ {
+ Add(new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Children = new[]
+ {
+ new EquilateralTriangle
+ {
+ Name = "Top",
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Position = new Vector2(0, -triangle_offfset),
+ Size = new Vector2(-triangle_size),
+ EdgeSmoothness = new Vector2(1),
+ },
+ new EquilateralTriangle
+ {
+ Name = "Bottom",
+ Anchor = Anchor.BottomCentre,
+ Origin = Anchor.TopCentre,
+ Position = new Vector2(0, triangle_offfset),
+ Size = new Vector2(triangle_size),
+ EdgeSmoothness = new Vector2(1),
+ }
+ }
+ });
+
+ Tracker.Alpha = 1f;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableCentreHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs
similarity index 56%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableCentreHit.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs
index 683d48df10..ff5ac859b4 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableCentreHit.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs
@@ -1,35 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using OpenTK.Input;
-using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
-using osu.Game.Graphics;
using osu.Framework.Allocation;
+using osu.Game.Graphics;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+using OpenTK.Input;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableCentreHit : DrawableHit
{
protected override Key[] HitKeys { get; } = { Key.F, Key.J };
- private readonly CirclePiece circlePiece;
-
public DrawableCentreHit(Hit hit)
: base(hit)
{
- Add(circlePiece = new CirclePiece
- {
- Children = new[]
- {
- new CentreHitSymbolPiece()
- }
- });
+ MainPiece.Add(new CentreHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- circlePiece.AccentColour = colours.PinkDarker;
+ MainPiece.AccentColour = colours.PinkDarker;
}
}
}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHitStrong.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHitStrong.cs
new file mode 100644
index 0000000000..bc24e2aa65
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHitStrong.cs
@@ -0,0 +1,27 @@
+// 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.Game.Graphics;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+using OpenTK.Input;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables
+{
+ public class DrawableCentreHitStrong : DrawableHitStrong
+ {
+ protected override Key[] HitKeys { get; } = { Key.F, Key.J };
+
+ public DrawableCentreHitStrong(Hit hit)
+ : base(hit)
+ {
+ MainPiece.Add(new CentreHitSymbolPiece());
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ MainPiece.AccentColour = colours.PinkDarker;
+ }
+ }
+}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs
new file mode 100644
index 0000000000..0a0098dd34
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs
@@ -0,0 +1,109 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.MathUtils;
+using osu.Game.Graphics;
+using osu.Game.Modes.Objects.Drawables;
+using osu.Game.Modes.Taiko.Judgements;
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables
+{
+ public class DrawableDrumRoll : DrawableTaikoHitObject
+ {
+ ///
+ /// Number of rolling hits required to reach the dark/final accent colour.
+ ///
+ private const int rolling_hits_for_dark_accent = 5;
+
+ private Color4 accentDarkColour;
+
+ ///
+ /// Rolling number of tick hits. This increases for hits and decreases for misses.
+ ///
+ private int rollingHits;
+
+ public DrawableDrumRoll(DrumRoll drumRoll)
+ : base(drumRoll)
+ {
+ foreach (var tick in drumRoll.Ticks)
+ {
+ var newTick = new DrawableDrumRollTick(tick)
+ {
+ X = (float)((tick.StartTime - HitObject.StartTime) / HitObject.Duration)
+ };
+
+ newTick.OnJudgement += onTickJudgement;
+
+ AddNested(newTick);
+ MainPiece.Add(newTick);
+ }
+ }
+
+ protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = HitObject.IsStrong };
+
+ protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(HitObject.IsStrong)
+ {
+ Length = (float)(HitObject.Duration / HitObject.ScrollTime),
+ PlayfieldLengthReference = () => Parent.DrawSize.X
+ };
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ MainPiece.AccentColour = AccentColour = colours.YellowDark;
+ accentDarkColour = colours.YellowDarker;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ // This is naive, however it's based on the reasoning that the hit target
+ // is further than mid point of the play field, so the time taken to scroll in should always
+ // be greater than the time taken to scroll out to the left of the screen.
+ // Thus, using PreEmpt here is enough for the drum roll to completely scroll out.
+ LifetimeEnd = HitObject.EndTime + HitObject.ScrollTime;
+ }
+
+ private void onTickJudgement(DrawableHitObject obj)
+ {
+ if (obj.Judgement.Result == HitResult.Hit)
+ rollingHits++;
+ else
+ rollingHits--;
+
+ rollingHits = MathHelper.Clamp(rollingHits, 0, rolling_hits_for_dark_accent);
+
+ Color4 newAccent = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_dark_accent, AccentColour, accentDarkColour, 0, 1);
+ MainPiece.FadeAccent(newAccent, 100);
+ }
+
+ protected override void CheckJudgement(bool userTriggered)
+ {
+ if (userTriggered)
+ return;
+
+ if (Judgement.TimeOffset < 0)
+ return;
+
+ int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
+
+ if (countHit > HitObject.RequiredGoodHits)
+ {
+ Judgement.Result = HitResult.Hit;
+ Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
+ }
+ else
+ Judgement.Result = HitResult.Miss;
+ }
+
+ protected override void UpdateState(ArmedState state)
+ {
+ }
+ }
+}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
similarity index 58%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
index 5217fd9085..296affedaf 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
@@ -1,35 +1,39 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using OpenTK.Input;
-using osu.Game.Modes.Taiko.Judgements;
using System;
+using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
+using osu.Game.Modes.Taiko.Judgements;
+using OpenTK.Input;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
- public class DrawableDrumRollTick : DrawableTaikoHitObject
+ public class DrawableDrumRollTick : DrawableTaikoHitObject
{
- private readonly DrumRollTick tick;
-
public DrawableDrumRollTick(DrumRollTick tick)
: base(tick)
{
- this.tick = tick;
}
- protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement();
+ protected override TaikoPiece CreateMainPiece() => new TickPiece
+ {
+ Filled = HitObject.FirstTick
+ };
+
+ protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong };
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
- if (Judgement.TimeOffset > tick.HitWindow)
+ if (Judgement.TimeOffset > HitObject.HitWindow)
Judgement.Result = HitResult.Miss;
return;
}
- if (Math.Abs(Judgement.TimeOffset) < tick.HitWindow)
+ if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
@@ -38,11 +42,17 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
protected override void UpdateState(ArmedState state)
{
+ switch (state)
+ {
+ case ArmedState.Hit:
+ Content.ScaleTo(0, 100, EasingTypes.OutQuint);
+ break;
+ }
}
protected override void UpdateScrollPosition(double time)
{
- // Drum roll ticks shouldn't move
+ // Ticks don't move
}
protected override bool HandleKeyPress(Key key)
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs
similarity index 59%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs
index c8a7355e3c..167fbebd7b 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs
@@ -1,66 +1,53 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using OpenTK.Input;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Modes.Objects.Drawables;
-using osu.Game.Modes.Taiko.Judgements;
using System;
using System.Linq;
+using osu.Framework.Graphics;
+using osu.Game.Modes.Objects.Drawables;
+using osu.Game.Modes.Taiko.Judgements;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+using OpenTK.Input;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
- public abstract class DrawableHit : DrawableTaikoHitObject
+ public abstract class DrawableHit : DrawableTaikoHitObject
{
///
/// A list of keys which can result in hits for this HitObject.
///
protected abstract Key[] HitKeys { get; }
- protected override Container Content => bodyContainer;
-
- private readonly Hit hit;
-
///
/// Whether the last key pressed is a valid hit key.
///
private bool validKeyPressed;
- private readonly Container bodyContainer;
-
protected DrawableHit(Hit hit)
: base(hit)
{
- this.hit = hit;
-
- AddInternal(bodyContainer = new Container
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- });
}
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
- if (Judgement.TimeOffset > hit.HitWindowGood)
+ if (Judgement.TimeOffset > HitObject.HitWindowGood)
Judgement.Result = HitResult.Miss;
return;
}
double hitOffset = Math.Abs(Judgement.TimeOffset);
- if (hitOffset > hit.HitWindowMiss)
+ if (hitOffset > HitObject.HitWindowMiss)
return;
if (!validKeyPressed)
Judgement.Result = HitResult.Miss;
- else if (hitOffset < hit.HitWindowGood)
+ else if (hitOffset < HitObject.HitWindowGood)
{
Judgement.Result = HitResult.Hit;
- Judgement.TaikoResult = hitOffset < hit.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
+ Judgement.TaikoResult = hitOffset < HitObject.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
@@ -80,21 +67,39 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
{
Delay(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true);
+ var circlePiece = MainPiece as CirclePiece;
+
+ circlePiece?.FlashBox.Flush();
+
switch (State)
{
case ArmedState.Idle:
- Delay(hit.HitWindowMiss);
+ Delay(HitObject.HitWindowMiss);
break;
case ArmedState.Miss:
FadeOut(100);
break;
case ArmedState.Hit:
- bodyContainer.ScaleTo(0.8f, 400, EasingTypes.OutQuad);
- bodyContainer.MoveToY(-200, 250, EasingTypes.Out);
- bodyContainer.Delay(250);
- bodyContainer.MoveToY(0, 500, EasingTypes.In);
-
FadeOut(600);
+
+ var flash = circlePiece?.FlashBox;
+ if (flash != null)
+ {
+ flash.FadeTo(0.9f);
+ flash.FadeOut(300);
+ }
+
+
+ FadeOut(800);
+
+ const float gravity_time = 300;
+ const float gravity_travel_height = 200;
+
+ Content.ScaleTo(0.8f, gravity_time * 2, EasingTypes.OutQuad);
+
+ MoveToY(-gravity_travel_height, gravity_time, EasingTypes.Out);
+ Delay(gravity_time, true);
+ MoveToY(gravity_travel_height * 2, gravity_time * 2, EasingTypes.In);
break;
}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHitStrong.cs
similarity index 87%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableHitStrong.cs
index a6cb6ae7fa..4ab029acb3 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHitStrong.cs
@@ -1,16 +1,17 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using OpenTK.Input;
using System;
using System.Linq;
using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
+using OpenTK.Input;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
- public abstract class DrawableStrongHit : DrawableHit
+ public abstract class DrawableHitStrong : DrawableHit
{
///
/// The lenience for the second key press.
@@ -22,11 +23,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
private bool firstKeyHeld;
private Key firstHitKey;
- protected DrawableStrongHit(Hit hit)
+ protected DrawableHitStrong(Hit hit)
: base(hit)
{
}
+ protected override TaikoPiece CreateMainPiece() => new CirclePiece(true);
+
protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
protected override void CheckJudgement(bool userTriggered)
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableRimHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs
similarity index 55%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableRimHit.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs
index cab6819300..5a311d51ef 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableRimHit.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs
@@ -3,33 +3,25 @@
using osu.Framework.Allocation;
using osu.Game.Graphics;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
-using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableRimHit : DrawableHit
{
protected override Key[] HitKeys { get; } = { Key.D, Key.K };
- private readonly CirclePiece circlePiece;
-
public DrawableRimHit(Hit hit)
: base(hit)
{
- Add(circlePiece = new CirclePiece
- {
- Children = new[]
- {
- new RimHitSymbolPiece()
- }
- });
+ MainPiece.Add(new RimHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- circlePiece.AccentColour = colours.BlueDarker;
+ MainPiece.AccentColour = colours.BlueDarker;
}
}
}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHitStrong.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHitStrong.cs
new file mode 100644
index 0000000000..5789dfb140
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHitStrong.cs
@@ -0,0 +1,27 @@
+// 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.Game.Graphics;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+using OpenTK.Input;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables
+{
+ public class DrawableRimHitStrong : DrawableHitStrong
+ {
+ protected override Key[] HitKeys { get; } = { Key.D, Key.K };
+
+ public DrawableRimHitStrong(Hit hit)
+ : base(hit)
+ {
+ MainPiece.Add(new RimHitSymbolPiece());
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ MainPiece.AccentColour = colours.BlueDarker;
+ }
+ }
+}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs
similarity index 85%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs
index ccd6380542..1e440df69a 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs
@@ -1,9 +1,8 @@
// 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 OpenTK.Input;
+using System;
+using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -12,13 +11,14 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
-using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
-using System;
-using System.Linq;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+using OpenTK;
+using OpenTK.Graphics;
+using OpenTK.Input;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
- public class DrawableSwell : DrawableTaikoHitObject
+ public class DrawableSwell : DrawableTaikoHitObject
{
///
/// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime.
@@ -31,8 +31,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
private const float target_ring_scale = 5f;
private const float inner_ring_alpha = 0.65f;
- private readonly Swell swell;
-
private readonly Container bodyContainer;
private readonly CircularContainer targetRing;
private readonly CircularContainer expandingRing;
@@ -54,13 +52,12 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
public DrawableSwell(Swell swell)
: base(swell)
{
- this.swell = swell;
-
- Children = new Framework.Graphics.Drawable[]
+ Children = new Drawable[]
{
bodyContainer = new Container
{
- Children = new Framework.Graphics.Drawable[]
+ AutoSizeAxes = Axes.Both,
+ Children = new Drawable[]
{
expandingRing = new CircularContainer
{
@@ -68,7 +65,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Alpha = 0,
- Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
+ Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
BlendingMode = BlendingMode.Additive,
Masking = true,
Children = new []
@@ -85,11 +82,11 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
Name = "Target ring (thick border)",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
+ Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
Masking = true,
BorderThickness = target_ring_thick_border,
BlendingMode = BlendingMode.Additive,
- Children = new Framework.Graphics.Drawable[]
+ Children = new Drawable[]
{
new Box
{
@@ -120,6 +117,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
},
circlePiece = new CirclePiece
{
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
Children = new []
{
symbol = new SwellSymbolPiece()
@@ -128,6 +127,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
}
}
};
+
+ circlePiece.KiaiMode = HitObject.Kiai;
}
[BackgroundDependencyLoader]
@@ -144,18 +145,18 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
{
userHits++;
- var completion = (float)userHits / swell.RequiredHits;
+ var completion = (float)userHits / HitObject.RequiredHits;
expandingRing.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50);
expandingRing.Delay(50);
expandingRing.FadeTo(completion / 8, 2000, EasingTypes.OutQuint);
expandingRing.DelayReset();
- symbol.RotateTo((float)(completion * swell.Duration / 8), 4000, EasingTypes.OutQuint);
+ symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, EasingTypes.OutQuint);
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);
- if (userHits == swell.RequiredHits)
+ if (userHits == HitObject.RequiredHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
@@ -167,7 +168,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
return;
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
- if (userHits > swell.RequiredHits / 2)
+ if (userHits > HitObject.RequiredHits / 2)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Good;
@@ -187,7 +188,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
Delay(preempt, true);
- Delay(Judgement.TimeOffset + swell.Duration, true);
+ Delay(Judgement.TimeOffset + HitObject.Duration, true);
const float out_transition_time = 300;
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableTaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
similarity index 55%
rename from osu.Game.Modes.Taiko/Objects/Drawable/DrawableTaikoHitObject.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index 5d6d669dc1..f15f2bd152 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableTaikoHitObject.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -1,16 +1,20 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using OpenTK.Input;
+using System.Collections.Generic;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
-using System.Collections.Generic;
-using osu.Framework.Input;
+using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
+using OpenTK;
+using OpenTK.Input;
-namespace osu.Game.Modes.Taiko.Objects.Drawable
+namespace osu.Game.Modes.Taiko.Objects.Drawables
{
- public abstract class DrawableTaikoHitObject : DrawableHitObject
+ public abstract class DrawableTaikoHitObject : DrawableHitObject
+ where TaikoHitType : TaikoHitObject
{
///
/// A list of keys which this hit object will accept. These are the standard Taiko keys for now.
@@ -18,33 +22,52 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
///
private readonly List validKeys = new List(new[] { Key.D, Key.F, Key.J, Key.K });
- protected DrawableTaikoHitObject(TaikoHitObject hitObject)
+ public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
+
+ protected override Container Content => bodyContainer;
+
+ protected readonly TaikoPiece MainPiece;
+
+ private readonly Container bodyContainer;
+
+ public new TaikoHitType HitObject;
+
+ protected DrawableTaikoHitObject(TaikoHitType hitObject)
: base(hitObject)
{
+ HitObject = hitObject;
+
Anchor = Anchor.CentreLeft;
- Origin = Anchor.Centre;
+ Origin = Anchor.Custom;
+
+ AutoSizeAxes = Axes.Both;
RelativePositionAxes = Axes.X;
- }
- protected override void LoadComplete()
- {
- LifetimeStart = HitObject.StartTime - HitObject.PreEmpt * 2;
+ AddInternal(bodyContainer = new Container
+ {
+ AutoSizeAxes = Axes.Both,
+ Children = new[]
+ {
+ MainPiece = CreateMainPiece()
+ }
+ });
- base.LoadComplete();
+ MainPiece.KiaiMode = HitObject.Kiai;
+
+ LifetimeStart = HitObject.StartTime - HitObject.ScrollTime * 2;
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
+ protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(HitObject.IsStrong);
+
///
/// Sets the scroll position of the DrawableHitObject relative to the offset between
/// a time value and the HitObject's StartTime.
///
///
- protected virtual void UpdateScrollPosition(double time)
- {
- MoveToX((float)((HitObject.StartTime - time) / HitObject.PreEmpt));
- }
+ protected virtual void UpdateScrollPosition(double time) => X = (float)((HitObject.StartTime - time) / HitObject.ScrollTime);
protected override void Update()
{
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/CentreHitSymbolPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs
similarity index 90%
rename from osu.Game.Modes.Taiko/Objects/Drawable/Pieces/CentreHitSymbolPiece.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs
index e62ca6b073..0cf4e97b41 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/CentreHitSymbolPiece.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
-namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
///
/// The symbol used for centre hit pieces.
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
new file mode 100644
index 0000000000..216e05ebc4
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.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 osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics.Backgrounds;
+using OpenTK.Graphics;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
+{
+ ///
+ /// A circle piece which is used uniformly through osu!taiko to visualise hitobjects.
+ ///
+ /// Note that this can actually be non-circle if the width is changed. See
+ /// for a usage example.
+ ///
+ ///
+ public class CirclePiece : TaikoPiece
+ {
+ public const float SYMBOL_SIZE = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER * 0.45f;
+ public const float SYMBOL_BORDER = 8;
+ public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER;
+
+ ///
+ /// The colour of the inner circle and outer glows.
+ ///
+ public override Color4 AccentColour
+ {
+ get { return base.AccentColour; }
+ set
+ {
+ base.AccentColour = value;
+
+ background.Colour = AccentColour;
+
+ resetEdgeEffects();
+ }
+ }
+
+ ///
+ /// Whether Kiai mode effects are enabled for this circle piece.
+ ///
+ public override bool KiaiMode
+ {
+ get { return base.KiaiMode; }
+ set
+ {
+ base.KiaiMode = value;
+
+ resetEdgeEffects();
+ }
+ }
+
+ protected override Container Content => content;
+
+ private readonly Container content;
+
+ private readonly Container background;
+
+ public Box FlashBox;
+
+ public CirclePiece(bool isStrong = false)
+ {
+ AddInternal(new Drawable[]
+ {
+ background = new CircularContainer
+ {
+ Name = "Background",
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new Triangles
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ ColourLight = Color4.White,
+ ColourDark = Color4.White.Darken(0.1f)
+ }
+ }
+ },
+ new CircularContainer
+ {
+ Name = "Ring",
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ BorderThickness = 8,
+ BorderColour = Color4.White,
+ Masking = true,
+ Children = new[]
+ {
+ FlashBox = new Box
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.White,
+ BlendingMode = BlendingMode.Additive,
+ Alpha = 0,
+ AlwaysPresent = true
+ }
+ }
+ },
+ content = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Name = "Content",
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ }
+ });
+
+ if (isStrong)
+ {
+ Size *= TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE;
+
+ //default for symbols etc.
+ Content.Scale *= TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE;
+ }
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ //we want to allow for width of content to remain mapped to the area inside us, regardless of the scale applied above.
+ Content.Width = 1 / Content.Scale.X;
+ }
+
+ private void resetEdgeEffects()
+ {
+ background.EdgeEffect = new EdgeEffect
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = AccentColour,
+ Radius = KiaiMode ? 50 : 8
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs
new file mode 100644
index 0000000000..5431507614
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs
@@ -0,0 +1,41 @@
+// 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.Primitives;
+using osu.Game.Modes.Taiko.UI;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
+{
+ public class ElongatedCirclePiece : CirclePiece
+ {
+ ///
+ /// As we are being used to define the absolute size of hits, we need to be given a relative reference of our containing .
+ ///
+ public Func PlayfieldLengthReference;
+
+ ///
+ /// The length of this piece as a multiple of the value returned by
+ ///
+ public float Length;
+
+ public ElongatedCirclePiece(bool isStrong = false) : base(isStrong)
+ {
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ var padding = Content.DrawHeight * Content.Width / 2;
+
+ Content.Padding = new MarginPadding
+ {
+ Left = padding,
+ Right = padding,
+ };
+
+ Width = (PlayfieldLengthReference?.Invoke() ?? 0) * Length + DrawHeight;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/RimHitSymbolPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.cs
similarity index 91%
rename from osu.Game.Modes.Taiko/Objects/Drawable/Pieces/RimHitSymbolPiece.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.cs
index 6999634108..6e19497978 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/RimHitSymbolPiece.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.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.Containers;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
-namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
///
/// The symbol used for rim hit pieces.
diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/SwellSymbolPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs
similarity index 88%
rename from osu.Game.Modes.Taiko/Objects/Drawable/Pieces/SwellSymbolPiece.cs
rename to osu.Game.Modes.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs
index 2bd86406a7..e491793902 100644
--- a/osu.Game.Modes.Taiko/Objects/Drawable/Pieces/SwellSymbolPiece.cs
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs
@@ -1,10 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Graphics;
using osu.Framework.Graphics;
+using osu.Game.Graphics;
-namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
///
/// The symbol used for swell pieces.
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs
new file mode 100644
index 0000000000..2220438a4a
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs
@@ -0,0 +1,45 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
+{
+ public class TaikoPiece : Container, IHasAccentColour
+ {
+ private Color4 accentColour;
+ ///
+ /// The colour of the inner circle and outer glows.
+ ///
+ public virtual Color4 AccentColour
+ {
+ get { return accentColour; }
+ set
+ {
+ accentColour = value;
+ }
+ }
+
+ private bool kiaiMode;
+ ///
+ /// Whether Kiai mode effects are enabled for this circle piece.
+ ///
+ public virtual bool KiaiMode
+ {
+ get { return kiaiMode; }
+ set
+ {
+ kiaiMode = value;
+ }
+ }
+
+ public TaikoPiece()
+ {
+ //just a default
+ Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER);
+ }
+ }
+}
diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs
new file mode 100644
index 0000000000..53e795e2e2
--- /dev/null
+++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs
@@ -0,0 +1,60 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
+{
+ public class TickPiece : TaikoPiece
+ {
+ ///
+ /// Any tick that is not the first for a drumroll is not filled, but is instead displayed
+ /// as a hollow circle. This is what controls the border width of that circle.
+ ///
+ private const float tick_border_width = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 16;
+
+ ///
+ /// The size of a tick.
+ ///
+ private const float tick_size = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 4;
+
+ private bool filled;
+ public bool Filled
+ {
+ get { return filled; }
+ set
+ {
+ filled = value;
+ fillBox.Alpha = filled ? 1 : 0;
+ }
+ }
+
+ private readonly Box fillBox;
+
+ public TickPiece()
+ {
+ Size = new Vector2(tick_size);
+
+ Add(new CircularContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ BorderThickness = tick_border_width,
+ BorderColour = Color4.White,
+ Children = new[]
+ {
+ fillBox = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ AlwaysPresent = true
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game.Modes.Taiko/Objects/DrumRoll.cs b/osu.Game.Modes.Taiko/Objects/DrumRoll.cs
index 1f9241268b..4f26ffd3a1 100644
--- a/osu.Game.Modes.Taiko/Objects/DrumRoll.cs
+++ b/osu.Game.Modes.Taiko/Objects/DrumRoll.cs
@@ -1,37 +1,31 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
+using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Objects
{
- public class DrumRoll : TaikoHitObject, IHasDistance
+ public class DrumRoll : TaikoHitObject, IHasEndTime
{
- public double EndTime => StartTime + Distance / Velocity;
+ ///
+ /// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
+ ///
+ private const float base_distance = 100;
- public double Duration => EndTime - StartTime;
+ public double EndTime => StartTime + Duration;
+
+ public double Duration { get; set; }
///
- /// Raw length of the drum roll in positional length units.
+ /// Numer of ticks per beat length.
///
- public double Distance { get; set; }
-
- ///
- /// Velocity of the drum roll in positional length units per millisecond.
- ///
- public double Velocity { get; protected set; }
-
- ///
- /// The distance between ticks of this drumroll.
- /// Half of this value is the hit window of the ticks.
- ///
- public double TickTimeDistance { get; protected set; }
+ public int TickRate = 1;
///
/// Number of drum roll ticks required for a "Good" hit.
@@ -55,18 +49,17 @@ namespace osu.Game.Modes.Taiko.Objects
private List ticks;
+ ///
+ /// The length (in milliseconds) between ticks of this drumroll.
+ /// Half of this value is the hit window of the ticks.
+ ///
+ private double tickSpacing = 100;
+
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
- Velocity = timing.SliderVelocityAt(StartTime) * difficulty.SliderMultiplier / 1000;
- TickTimeDistance = timing.BeatLengthAt(StartTime);
-
- //TODO: move this to legacy conversion code to allow for direct division without special case.
- if (difficulty.SliderTickRate == 3)
- TickTimeDistance /= 3;
- else
- TickTimeDistance /= 4;
+ tickSpacing = timing.BeatLengthAt(StartTime) / TickRate;
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
@@ -76,23 +69,25 @@ namespace osu.Game.Modes.Taiko.Objects
{
var ret = new List();
- if (TickTimeDistance == 0)
+ if (tickSpacing == 0)
return ret;
bool first = true;
- for (double t = StartTime; t < EndTime + (int)TickTimeDistance; t += TickTimeDistance)
+ for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing)
{
ret.Add(new DrumRollTick
{
FirstTick = first,
- PreEmpt = PreEmpt,
- TickTimeDistance = TickTimeDistance,
+ ScrollTime = ScrollTime,
+ TickSpacing = tickSpacing,
StartTime = t,
- Sample = new HitSampleInfo
+ IsStrong = IsStrong,
+ Samples = Samples.Select(s => new SampleInfo
{
- Type = SampleType.None,
- Set = SampleSet.Soft
- }
+ Bank = s.Bank,
+ Name = @"slidertick",
+ Volume = s.Volume
+ }).ToList()
});
first = false;
diff --git a/osu.Game.Modes.Taiko/Objects/DrumRollTick.cs b/osu.Game.Modes.Taiko/Objects/DrumRollTick.cs
index 2ca0d71fc1..32e8851b66 100644
--- a/osu.Game.Modes.Taiko/Objects/DrumRollTick.cs
+++ b/osu.Game.Modes.Taiko/Objects/DrumRollTick.cs
@@ -11,14 +11,14 @@ namespace osu.Game.Modes.Taiko.Objects
public bool FirstTick;
///
- /// The distance between this tick and the next in milliseconds.
+ /// The length (in milliseconds) between this tick and the next.
/// Half of this value is the hit window of the tick.
///
- public double TickTimeDistance;
+ public double TickSpacing;
///
/// The time allowed to hit this tick.
///
- public double HitWindow => TickTimeDistance / 2;
+ public double HitWindow => TickSpacing / 2;
}
}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/Swell.cs b/osu.Game.Modes.Taiko/Objects/Swell.cs
index 4cbb5904c7..97101ea797 100644
--- a/osu.Game.Modes.Taiko/Objects/Swell.cs
+++ b/osu.Game.Modes.Taiko/Objects/Swell.cs
@@ -1,30 +1,19 @@
// 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.Beatmaps.Timing;
-using osu.Game.Database;
using osu.Game.Modes.Objects.Types;
namespace osu.Game.Modes.Taiko.Objects
{
public class Swell : TaikoHitObject, IHasEndTime
{
- public double EndTime { get; set; }
+ public double EndTime => StartTime + Duration;
- public double Duration => EndTime - StartTime;
+ public double Duration { get; set; }
///
/// The number of hits required to complete the swell successfully.
///
- public int RequiredHits { get; protected set; } = 10;
-
- public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
- {
- base.ApplyDefaults(timing, difficulty);
-
- double spinnerRotationRatio = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5);
- RequiredHits = (int)Math.Max(1, Duration / 1000f * spinnerRotationRatio);
- }
+ public int RequiredHits = 10;
}
}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs
index ac47a3bc88..ebc9b19d3a 100644
--- a/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs
+++ b/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs
@@ -4,20 +4,41 @@
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Modes.Objects;
+using osu.Game.Modes.Taiko.UI;
namespace osu.Game.Modes.Taiko.Objects
{
public abstract class TaikoHitObject : HitObject
{
///
- /// HitCircle radius.
+ /// Diameter of a circle relative to the size of the .
///
- public const float CIRCLE_RADIUS = 42f;
+ public const float PLAYFIELD_RELATIVE_DIAMETER = 0.5f;
///
- /// The time to scroll in the HitObject.
+ /// Scale multiplier for a strong circle.
///
- public double PreEmpt;
+ public const float STRONG_CIRCLE_DIAMETER_SCALE = 1.5f;
+
+ ///
+ /// Default circle diameter.
+ ///
+ public const float DEFAULT_CIRCLE_DIAMETER = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT * PLAYFIELD_RELATIVE_DIAMETER;
+
+ ///
+ /// Default strong circle diameter.
+ ///
+ public const float DEFAULT_STRONG_CIRCLE_DIAMETER = DEFAULT_CIRCLE_DIAMETER * STRONG_CIRCLE_DIAMETER_SCALE;
+
+ ///
+ /// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a of 1000ms.
+ ///
+ private const double scroll_time = 6000;
+
+ ///
+ /// Our adjusted taking into consideration local and other speed multipliers.
+ ///
+ public double ScrollTime;
///
/// Whether this HitObject is a "strong" type.
@@ -34,7 +55,7 @@ namespace osu.Game.Modes.Taiko.Objects
{
base.ApplyDefaults(timing, difficulty);
- PreEmpt = 600 / (timing.SliderVelocityAt(StartTime) * difficulty.SliderMultiplier) * 1000;
+ ScrollTime = scroll_time * (timing.BeatLengthAt(StartTime) * timing.SpeedMultiplierAt(StartTime) / 1000) / difficulty.SliderMultiplier;
ControlPoint overridePoint;
Kiai = timing.TimingPointAt(StartTime, out overridePoint).KiaiMode;
diff --git a/osu.Game.Modes.Taiko/Properties/AssemblyInfo.cs b/osu.Game.Modes.Taiko/Properties/AssemblyInfo.cs
index 61eca30b5f..94ec895707 100644
--- a/osu.Game.Modes.Taiko/Properties/AssemblyInfo.cs
+++ b/osu.Game.Modes.Taiko/Properties/AssemblyInfo.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Taiko")]
@@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/osu.Game.Modes.Taiko/Replays/TaikoAutoReplay.cs b/osu.Game.Modes.Taiko/Replays/TaikoAutoReplay.cs
index c8a93c9068..89d974baf9 100644
--- a/osu.Game.Modes.Taiko/Replays/TaikoAutoReplay.cs
+++ b/osu.Game.Modes.Taiko/Replays/TaikoAutoReplay.cs
@@ -72,14 +72,9 @@ namespace osu.Game.Modes.Taiko.Replays
}
else if (drumRoll != null)
{
- double delay = drumRoll.TickTimeDistance;
-
- double time = drumRoll.StartTime;
-
- for (int j = 0; j < drumRoll.TotalTicks; j++)
+ foreach (var tick in drumRoll.Ticks)
{
- Frames.Add(new ReplayFrame((int)time, 0, 0, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2));
- time += delay;
+ Frames.Add(new ReplayFrame(tick.StartTime, 0, 0, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2));
hitButton = !hitButton;
}
}
diff --git a/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs
index fa7e18cadb..987c3181a4 100644
--- a/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs
+++ b/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs
@@ -187,10 +187,6 @@ namespace osu.Game.Modes.Taiko.Scoring
if (!isTick)
totalHits++;
- // Apply combo changes, must be done before the hit score is added
- if (!isTick && judgement.Result == HitResult.Hit)
- Combo.Value++;
-
// Apply score changes
addHitScore(judgement);
@@ -261,7 +257,7 @@ namespace osu.Game.Modes.Taiko.Scoring
foreach (var j in Judgements)
{
scoreForAccuracy += j.ResultValueForAccuracy;
- maxScoreForAccuracy = j.MaxResultValueForAccuracy;
+ maxScoreForAccuracy += j.MaxResultValueForAccuracy;
}
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;
diff --git a/osu.Game.Modes.Taiko/UI/HitExplosion.cs b/osu.Game.Modes.Taiko/UI/HitExplosion.cs
index 94938a700d..e4e329523f 100644
--- a/osu.Game.Modes.Taiko/UI/HitExplosion.cs
+++ b/osu.Game.Modes.Taiko/UI/HitExplosion.cs
@@ -18,14 +18,18 @@ namespace osu.Game.Modes.Taiko.UI
///
internal class HitExplosion : CircularContainer
{
- private readonly TaikoJudgement judgement;
+ ///
+ /// The judgement this hit explosion visualises.
+ ///
+ public readonly TaikoJudgement Judgement;
+
private readonly Box innerFill;
public HitExplosion(TaikoJudgement judgement)
{
- this.judgement = judgement;
+ Judgement = judgement;
- Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2);
+ Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
@@ -50,10 +54,7 @@ namespace osu.Game.Modes.Taiko.UI
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- if (judgement.SecondHit)
- Size *= 1.5f;
-
- switch (judgement.TaikoResult)
+ switch (Judgement.TaikoResult)
{
case TaikoHitResult.Good:
innerFill.Colour = colours.Green;
@@ -73,5 +74,13 @@ namespace osu.Game.Modes.Taiko.UI
Expire();
}
+
+ ///
+ /// Transforms this hit explosion to visualise a secondary hit.
+ ///
+ public void VisualiseSecondHit()
+ {
+ ResizeTo(Size * TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE, 50);
+ }
}
}
diff --git a/osu.Game.Modes.Taiko/UI/HitTarget.cs b/osu.Game.Modes.Taiko/UI/HitTarget.cs
index 32b2877545..b22dc1d647 100644
--- a/osu.Game.Modes.Taiko/UI/HitTarget.cs
+++ b/osu.Game.Modes.Taiko/UI/HitTarget.cs
@@ -15,16 +15,6 @@ namespace osu.Game.Modes.Taiko.UI
///
internal class HitTarget : Container
{
- ///
- /// Diameter of normal hit object circles.
- ///
- private const float normal_diameter = TaikoHitObject.CIRCLE_RADIUS * 2;
-
- ///
- /// Diameter of finisher hit object circles.
- ///
- private const float finisher_diameter = normal_diameter * 1.5f;
-
///
/// The 1px inner border of the taiko playfield.
///
@@ -37,7 +27,7 @@ namespace osu.Game.Modes.Taiko.UI
public HitTarget()
{
- RelativeSizeAxes = Axes.Y;
+ Size = new Vector2(TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT);
Children = new Drawable[]
{
@@ -47,15 +37,15 @@ namespace osu.Game.Modes.Taiko.UI
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = border_offset,
- Size = new Vector2(border_thickness, (TaikoPlayfield.PLAYFIELD_HEIGHT - finisher_diameter) / 2f - border_offset),
+ Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER) / 2f - border_offset),
Alpha = 0.1f
},
new CircularContainer
{
- Name = "Finisher Ring",
+ Name = "Strong Hit Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Size = new Vector2(finisher_diameter),
+ Size = new Vector2(TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER),
Masking = true,
BorderColour = Color4.White,
BorderThickness = border_thickness,
@@ -72,10 +62,10 @@ namespace osu.Game.Modes.Taiko.UI
},
new CircularContainer
{
- Name = "Normal Ring",
+ Name = "Normal Hit Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Size = new Vector2(normal_diameter),
+ Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
Masking = true,
BorderColour = Color4.White,
BorderThickness = border_thickness,
@@ -96,7 +86,7 @@ namespace osu.Game.Modes.Taiko.UI
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Y = -border_offset,
- Size = new Vector2(border_thickness, (TaikoPlayfield.PLAYFIELD_HEIGHT - finisher_diameter) / 2f - border_offset),
+ Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER) / 2f - border_offset),
Alpha = 0.1f
},
};
diff --git a/osu.Game.Modes.Taiko/UI/InputDrum.cs b/osu.Game.Modes.Taiko/UI/InputDrum.cs
index e7470ee913..d238c38e74 100644
--- a/osu.Game.Modes.Taiko/UI/InputDrum.cs
+++ b/osu.Game.Modes.Taiko/UI/InputDrum.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Modes.Taiko.UI
{
public InputDrum()
{
- Size = new Vector2(TaikoPlayfield.PLAYFIELD_HEIGHT);
+ Size = new Vector2(TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT);
const float middle_split = 10;
@@ -60,7 +60,7 @@ namespace osu.Game.Modes.Taiko.UI
/// The key to be used for the rim of the half-drum.
///
public Key RimKey;
-
+
///
/// The key to be used for the centre of the half-drum.
///
@@ -128,17 +128,36 @@ namespace osu.Game.Modes.Taiko.UI
return false;
Drawable target = null;
+ Drawable back = null;
if (args.Key == CentreKey)
+ {
target = centreHit;
+ back = centre;
+ }
else if (args.Key == RimKey)
+ {
target = rimHit;
+ back = rim;
+ }
if (target != null)
{
- target.FadeTo(Math.Min(target.Alpha + 0.4f, 1), 40, EasingTypes.OutQuint);
- target.Delay(40);
- target.FadeOut(1000, EasingTypes.OutQuint);
+ const float scale_amount = 0.05f;
+ const float alpha_amount = 0.5f;
+
+ const float down_time = 40;
+ const float up_time = 1000;
+
+ back.ScaleTo(target.Scale.X - scale_amount, down_time, EasingTypes.OutQuint);
+ back.Delay(down_time);
+ back.ScaleTo(1, up_time, EasingTypes.OutQuint);
+
+ target.ScaleTo(target.Scale.X - scale_amount, down_time, EasingTypes.OutQuint);
+ target.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, EasingTypes.OutQuint);
+ target.Delay(down_time);
+ target.ScaleTo(1, up_time, EasingTypes.OutQuint);
+ target.FadeOut(up_time, EasingTypes.OutQuint);
}
return false;
diff --git a/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs b/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs
index e70e2d3811..32476dff7f 100644
--- a/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs
+++ b/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs
@@ -1,16 +1,23 @@
// 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.MathUtils;
+using osu.Framework.Graphics;
using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Timing;
using osu.Game.Modes.Objects.Drawables;
+using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Replays;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.Taiko.Beatmaps;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
-using osu.Game.Modes.Taiko.Replays;
+using osu.Game.Modes.Taiko.Objects.Drawables;
using osu.Game.Modes.Taiko.Scoring;
using osu.Game.Modes.UI;
+using osu.Game.Modes.Taiko.Replays;
+using OpenTK;
namespace osu.Game.Modes.Taiko.UI
{
@@ -21,15 +28,132 @@ namespace osu.Game.Modes.Taiko.UI
{
}
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ loadBarLines();
+ }
+
+ private void loadBarLines()
+ {
+ var taikoPlayfield = Playfield as TaikoPlayfield;
+
+ if (taikoPlayfield == null)
+ return;
+
+ TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
+ double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
+
+ var timingPoints = Beatmap.TimingInfo.ControlPoints.FindAll(cp => cp.TimingChange);
+
+ if (timingPoints.Count == 0)
+ return;
+
+ int currentIndex = 0;
+
+ while (currentIndex < timingPoints.Count && Precision.AlmostEquals(timingPoints[currentIndex].BeatLength, 0))
+ currentIndex++;
+
+ double time = timingPoints[currentIndex].Time;
+ double measureLength = timingPoints[currentIndex].BeatLength * (int)timingPoints[currentIndex].TimeSignature;
+
+ // Find the bar line time closest to 0
+ time -= measureLength * (int)(time / measureLength);
+
+ // Always start barlines from a positive time
+ while (time < 0)
+ time += measureLength;
+
+ int currentBeat = 0;
+ while (time <= lastHitTime)
+ {
+ ControlPoint current = timingPoints[currentIndex];
+
+ if (time > current.Time || current.OmitFirstBarLine)
+ {
+ bool isMajor = currentBeat % (int)current.TimeSignature == 0;
+
+ var barLine = new BarLine
+ {
+ StartTime = time,
+ };
+
+ barLine.ApplyDefaults(Beatmap.TimingInfo, Beatmap.BeatmapInfo.Difficulty);
+
+ taikoPlayfield.AddBarLine(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine));
+
+ currentBeat++;
+ }
+
+ double bl = current.BeatLength;
+
+ if (bl < 800)
+ bl *= (int)current.TimeSignature;
+
+ time += bl;
+
+ if (currentIndex + 1 >= timingPoints.Count || time < timingPoints[currentIndex + 1].Time)
+ continue;
+
+ currentBeat = 0;
+ currentIndex++;
+ time = timingPoints[currentIndex].Time;
+ }
+ }
+
+ protected override Vector2 GetPlayfieldAspectAdjust()
+ {
+ const float default_relative_height = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT / 768;
+ const float default_aspect = 16f / 9f;
+
+ float aspectAdjust = MathHelper.Clamp(DrawWidth / DrawHeight, 0.4f, 4) / default_aspect;
+
+ return new Vector2(1, default_relative_height * aspectAdjust);
+ }
+
+
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
protected override IBeatmapConverter CreateBeatmapConverter() => new TaikoBeatmapConverter();
protected override IBeatmapProcessor CreateBeatmapProcessor() => new TaikoBeatmapProcessor();
- protected override Playfield CreatePlayfield() => new TaikoPlayfield();
+ protected override Playfield CreatePlayfield() => new TaikoPlayfield
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft
+ };
- protected override DrawableHitObject GetVisualRepresentation(TaikoHitObject h) => null;
+ protected override DrawableHitObject GetVisualRepresentation(TaikoHitObject h)
+ {
+ var centreHit = h as CentreHit;
+ if (centreHit != null)
+ {
+ if (h.IsStrong)
+ return new DrawableCentreHitStrong(centreHit);
+ return new DrawableCentreHit(centreHit);
+ }
+
+ var rimHit = h as RimHit;
+ if (rimHit != null)
+ {
+ if (h.IsStrong)
+ return new DrawableRimHitStrong(rimHit);
+ return new DrawableRimHit(rimHit);
+ }
+
+ var drumRoll = h as DrumRoll;
+ if (drumRoll != null)
+ {
+ return new DrawableDrumRoll(drumRoll);
+ }
+
+ var swell = h as Swell;
+ if (swell != null)
+ return new DrawableSwell(swell);
+
+ return null;
+ }
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay);
}
diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs
index b6165b785b..db3a1bc84e 100644
--- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs
@@ -14,22 +14,23 @@ using osu.Game.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Primitives;
-using osu.Game.Modes.Taiko.Objects.Drawable;
+using System.Linq;
+using osu.Game.Modes.Taiko.Objects.Drawables;
+using System;
namespace osu.Game.Modes.Taiko.UI
{
public class TaikoPlayfield : Playfield
{
///
- /// The play field height. This is relative to the size of hit objects
- /// such that the playfield is just a bit larger than finishers.
+ /// The default play field height.
///
- public const float PLAYFIELD_HEIGHT = TaikoHitObject.CIRCLE_RADIUS * 2 * 2;
+ public const float DEFAULT_PLAYFIELD_HEIGHT = 168f;
///
/// The offset from which the center of the hit target lies at.
///
- private const float hit_target_offset = TaikoHitObject.CIRCLE_RADIUS * 1.5f + 40;
+ private const float hit_target_offset = TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER / 2f + 40;
///
/// The size of the left area of the playfield. This area contains the input drum.
@@ -39,7 +40,7 @@ namespace osu.Game.Modes.Taiko.UI
protected override Container Content => hitObjectContainer;
private readonly Container hitExplosionContainer;
- //private Container barLineContainer;
+ private readonly Container barLineContainer;
private readonly Container judgementContainer;
private readonly Container hitObjectContainer;
@@ -51,13 +52,11 @@ namespace osu.Game.Modes.Taiko.UI
public TaikoPlayfield()
{
- RelativeSizeAxes = Axes.X;
- Height = PLAYFIELD_HEIGHT;
-
AddInternal(new Drawable[]
{
rightBackgroundContainer = new Container
{
+ Name = "Transparent playfield background",
RelativeSizeAxes = Axes.Both,
BorderThickness = 2,
Masking = true,
@@ -76,76 +75,88 @@ namespace osu.Game.Modes.Taiko.UI
},
}
},
- new Container
+ new ScaleFixContainer
{
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Left = left_area_size },
- Children = new Drawable[]
+ RelativeSizeAxes = Axes.X,
+ Height = DEFAULT_PLAYFIELD_HEIGHT,
+ Children = new[]
{
new Container
{
- Padding = new MarginPadding { Left = hit_target_offset },
+ Name = "Transparent playfield elements",
RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Left = left_area_size },
Children = new Drawable[]
{
- hitExplosionContainer = new Container
+ new Container
{
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.Centre,
- Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
- BlendingMode = BlendingMode.Additive
+ Name = "Hit target container",
+ X = hit_target_offset,
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ hitExplosionContainer = new Container
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Y,
+ BlendingMode = BlendingMode.Additive
+ },
+ barLineContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ new HitTarget
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.Centre,
+ },
+ hitObjectContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ judgementContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Y,
+ BlendingMode = BlendingMode.Additive
+ },
+ },
},
- //barLineContainer = new Container
- //{
- // RelativeSizeAxes = Axes.Both,
- //},
- new HitTarget
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.Centre,
- },
- hitObjectContainer = new Container
+ }
+ },
+ leftBackgroundContainer = new Container
+ {
+ Name = "Left overlay",
+ Size = new Vector2(left_area_size, DEFAULT_PLAYFIELD_HEIGHT),
+ BorderThickness = 1,
+ Children = new Drawable[]
+ {
+ leftBackground = new Box
{
RelativeSizeAxes = Axes.Both,
},
- judgementContainer = new Container
+ new InputDrum
{
- RelativeSizeAxes = Axes.Both,
- BlendingMode = BlendingMode.Additive
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativePositionAxes = Axes.X,
+ Position = new Vector2(0.10f, 0),
+ Scale = new Vector2(0.9f)
},
- },
- },
- }
- },
- leftBackgroundContainer = new Container
- {
- Size = new Vector2(left_area_size, PLAYFIELD_HEIGHT),
- BorderThickness = 1,
- Children = new Drawable[]
- {
- leftBackground = new Box
- {
- RelativeSizeAxes = Axes.Both,
- },
- new InputDrum
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.X,
- Position = new Vector2(0.10f, 0),
- Scale = new Vector2(0.9f)
- },
- new Box
- {
- Anchor = Anchor.TopRight,
- RelativeSizeAxes = Axes.Y,
- Width = 10,
- ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
+ new Box
+ {
+ Anchor = Anchor.TopRight,
+ RelativeSizeAxes = Axes.Y,
+ Width = 10,
+ ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
+ },
+ }
},
}
},
topLevelHitContainer = new Container
{
+ Name = "Top level hit objects",
RelativeSizeAxes = Axes.Both,
}
});
@@ -173,12 +184,15 @@ namespace osu.Game.Modes.Taiko.UI
swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy());
}
+ public void AddBarLine(DrawableBarLine barLine)
+ {
+ barLineContainer.Add(barLine);
+ }
+
public override void OnJudgement(DrawableHitObject judgedObject)
{
bool wasHit = judgedObject.Judgement.Result == HitResult.Hit;
-
- if (wasHit)
- hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement));
+ bool secondHit = judgedObject.Judgement.SecondHit;
judgementContainer.Add(new DrawableTaikoJudgement(judgedObject.Judgement)
{
@@ -187,6 +201,73 @@ namespace osu.Game.Modes.Taiko.UI
RelativePositionAxes = Axes.X,
X = wasHit ? judgedObject.Position.X : 0,
});
+
+ if (!wasHit)
+ return;
+
+ if (!secondHit)
+ {
+ if (judgedObject.X >= -0.05f && !(judgedObject is DrawableSwell))
+ {
+ // If we're far enough away from the left stage, we should bring outselves in front of it
+ topLevelHitContainer.Add(judgedObject.CreateProxy());
+ }
+
+ hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement));
+ }
+ else
+ hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit();
+ }
+
+ ///
+ /// This is a very special type of container. It serves a similar purpose to , however unlike ,
+ /// this will only adjust the scale relative to the height of its parent and will maintain the original width relative to its parent.
+ ///
+ ///
+ /// By adjusting the scale relative to the height of its parent, the aspect ratio of this container's children is maintained, however this is undesirable
+ /// in the case where the hit object container should not have its width adjusted by scale. To counteract this, another container is nested inside this
+ /// container which takes care of reversing the width adjustment while appearing transparent to the user.
+ ///
+ ///
+ private class ScaleFixContainer : Container
+ {
+ protected override Container Content => widthAdjustmentContainer;
+ private readonly WidthAdjustmentContainer widthAdjustmentContainer;
+
+ ///
+ /// We only want to apply DrawScale in the Y-axis to preserve aspect ratio and doesn't care about having its width adjusted.
+ ///
+ protected override Vector2 DrawScale => Scale * RelativeToAbsoluteFactor.Y / DrawHeight;
+
+ public ScaleFixContainer()
+ {
+ AddInternal(widthAdjustmentContainer = new WidthAdjustmentContainer { ParentDrawScaleReference = () => DrawScale.X });
+ }
+
+ ///
+ /// The container type that reverses the width adjustment.
+ ///
+ private class WidthAdjustmentContainer : Container
+ {
+ ///
+ /// This container needs to know its parent's so it can reverse the width adjustment caused by .
+ ///
+ public Func ParentDrawScaleReference;
+
+ public WidthAdjustmentContainer()
+ {
+ // This container doesn't care about height, it should always fill its parent
+ RelativeSizeAxes = Axes.Y;
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ // Reverse the DrawScale adjustment
+ Width = Parent.DrawSize.X / ParentDrawScaleReference();
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
index 917be7a084..19ba5c77e4 100644
--- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
+++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
@@ -33,8 +33,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -53,22 +52,27 @@
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -107,7 +111,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs
index 356fa5a6c1..8183bc952e 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs
@@ -6,11 +6,12 @@ using NUnit.Framework;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Formats;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Modes;
using osu.Game.Tests.Resources;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Objects.Legacy;
+using System.Linq;
+using osu.Game.Audio;
namespace osu.Game.Tests.Beatmaps.Formats
{
@@ -55,7 +56,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo;
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(false, beatmapInfo.Countdown);
- Assert.AreEqual(SampleSet.Soft, beatmapInfo.SampleSet);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode);
@@ -137,12 +137,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(slider);
Assert.AreEqual(new Vector2(192, 168), slider.Position);
Assert.AreEqual(956, slider.StartTime);
- Assert.AreEqual(SampleType.None, slider.Sample.Type);
+ Assert.IsTrue(slider.Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
var hit = beatmap.HitObjects[1] as LegacyHit;
Assert.IsNotNull(hit);
Assert.AreEqual(new Vector2(304, 56), hit.Position);
Assert.AreEqual(1285, hit.StartTime);
- Assert.AreEqual(SampleType.Clap, hit.Sample.Type);
+ Assert.IsTrue(hit.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
}
}
}
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 39fb1bfa8a..5d15b43761 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -97,7 +97,7 @@ namespace osu.Game.Tests.Beatmaps.IO
ensureLoaded(osu);
Assert.IsTrue(File.Exists(temp));
-
+
File.Delete(temp);
Assert.IsFalse(File.Exists(temp));
diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
index 2a69be92ca..b9c4cf780a 100644
--- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
@@ -7,6 +7,8 @@ using osu.Game.Beatmaps.IO;
using osu.Game.Modes;
using osu.Game.Modes.Osu;
using osu.Game.Tests.Resources;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.Database;
namespace osu.Game.Tests.Beatmaps.IO
{
@@ -53,7 +55,11 @@ namespace osu.Game.Tests.Beatmaps.IO
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
{
var reader = new OszArchiveReader(osz);
- var meta = reader.ReadMetadata();
+
+ BeatmapMetadata meta;
+ using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
+ meta = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
+
Assert.AreEqual(241526, meta.OnlineBeatmapSetID);
Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode);
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index d01aa77e02..2844528d0c 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -29,13 +29,11 @@
false
-
- $(SolutionDir)\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll
- True
+
+ $(SolutionDir)\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config
index ca53ef08b0..9972fb41a1 100644
--- a/osu.Game.Tests/packages.config
+++ b/osu.Game.Tests/packages.config
@@ -1,12 +1,11 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs
new file mode 100644
index 0000000000..171a1bdf75
--- /dev/null
+++ b/osu.Game/Audio/SampleInfo.cs
@@ -0,0 +1,28 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Audio
+{
+ public class SampleInfo
+ {
+ public const string HIT_WHISTLE = @"hitwhistle";
+ public const string HIT_FINISH = @"hitfinish";
+ public const string HIT_NORMAL = @"hitnormal";
+ public const string HIT_CLAP = @"hitclap";
+
+ ///
+ /// The bank to load the sample from.
+ ///
+ public string Bank;
+
+ ///
+ /// The name of the sample to load.
+ ///
+ public string Name;
+
+ ///
+ /// The sample volume.
+ ///
+ public int Volume;
+ }
+}
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs
index ac0ab9966f..8c1378cae4 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Beatmaps.Drawables
GainedSelection = headerGainedSelection,
RelativeSizeAxes = Axes.X,
};
-
+
BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.OrderBy(b => b.StarDifficulty).ToList();
BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b)
{
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
index e26dcac16b..534578337f 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
@@ -22,8 +22,9 @@ namespace osu.Game.Beatmaps.Drawables
public Action GainedSelection;
private readonly SpriteText title;
private readonly SpriteText artist;
- private OsuConfigManager config;
+
private Bindable preferUnicode;
+
private readonly WorkingBeatmap beatmap;
private readonly FillFlowContainer difficultyIcons;
@@ -33,19 +34,15 @@ namespace osu.Game.Beatmaps.Drawables
Children = new Drawable[]
{
- new DelayedLoadContainer
- {
- RelativeSizeAxes = Axes.Both,
- TimeBeforeLoad = 300,
- FinishedLoading = d => d.FadeInFromZero(400, EasingTypes.Out),
- Children = new[]
+ new DelayedLoadWrapper(
+ new PanelBackground(beatmap)
{
- new PanelBackground(beatmap)
- {
- RelativeSizeAxes = Axes.Both,
- Depth = 1,
- }
+ RelativeSizeAxes = Axes.Both,
+ OnLoadComplete = d => d.FadeInFromZero(400, EasingTypes.Out),
}
+ )
+ {
+ TimeBeforeLoad = 300,
},
new FillFlowContainer
{
@@ -87,24 +84,13 @@ namespace osu.Game.Beatmaps.Drawables
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
- this.config = config;
-
preferUnicode = config.GetBindable(OsuConfig.ShowUnicode);
- preferUnicode.ValueChanged += preferUnicode_changed;
- preferUnicode_changed(preferUnicode, null);
- }
-
- private void preferUnicode_changed(object sender, EventArgs e)
- {
- title.Text = config.GetUnicodeString(beatmap.BeatmapSetInfo.Metadata.Title, beatmap.BeatmapSetInfo.Metadata.TitleUnicode);
- artist.Text = config.GetUnicodeString(beatmap.BeatmapSetInfo.Metadata.Artist, beatmap.BeatmapSetInfo.Metadata.ArtistUnicode);
- }
-
- protected override void Dispose(bool isDisposing)
- {
- if (preferUnicode != null)
- preferUnicode.ValueChanged -= preferUnicode_changed;
- base.Dispose(isDisposing);
+ preferUnicode.ValueChanged += unicode =>
+ {
+ title.Text = unicode ? beatmap.BeatmapSetInfo.Metadata.TitleUnicode : beatmap.BeatmapSetInfo.Metadata.Title;
+ artist.Text = unicode ? beatmap.BeatmapSetInfo.Metadata.ArtistUnicode : beatmap.BeatmapSetInfo.Metadata.Artist;
+ };
+ preferUnicode.TriggerChange();
}
private class PanelBackground : BufferedContainer
diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
index 425c6cc5dc..452bd595c7 100644
--- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs
@@ -13,13 +13,13 @@ namespace osu.Game.Beatmaps.Formats
{
private static Dictionary decoders { get; } = new Dictionary();
- public static BeatmapDecoder GetDecoder(TextReader stream)
+ public static BeatmapDecoder GetDecoder(StreamReader stream)
{
- var line = stream.ReadLine()?.Trim();
+ string line = stream.ReadLine()?.Trim();
if (line == null || !decoders.ContainsKey(line))
throw new IOException(@"Unknown file format");
- return (BeatmapDecoder)Activator.CreateInstance(decoders[line]);
+ return (BeatmapDecoder)Activator.CreateInstance(decoders[line], line);
}
protected static void AddDecoder(string magic) where T : BeatmapDecoder
@@ -27,17 +27,17 @@ namespace osu.Game.Beatmaps.Formats
decoders[magic] = typeof(T);
}
- public virtual Beatmap Decode(TextReader stream)
+ public virtual Beatmap Decode(StreamReader stream)
{
return ParseFile(stream);
}
- public virtual void Decode(TextReader stream, Beatmap beatmap)
+ public virtual void Decode(StreamReader stream, Beatmap beatmap)
{
ParseFile(stream, beatmap);
}
- protected virtual Beatmap ParseFile(TextReader stream)
+ protected virtual Beatmap ParseFile(StreamReader stream)
{
var beatmap = new Beatmap
{
@@ -48,9 +48,11 @@ namespace osu.Game.Beatmaps.Formats
Difficulty = new BeatmapDifficulty(),
},
};
+
ParseFile(stream, beatmap);
return beatmap;
}
- protected abstract void ParseFile(TextReader stream, Beatmap beatmap);
+
+ protected abstract void ParseFile(StreamReader stream, Beatmap beatmap);
}
}
diff --git a/osu.Game/Beatmaps/Formats/ConstructableBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/ConstructableBeatmapDecoder.cs
deleted file mode 100644
index 3e7dbb4d1b..0000000000
--- a/osu.Game/Beatmaps/Formats/ConstructableBeatmapDecoder.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.IO;
-
-namespace osu.Game.Beatmaps.Formats
-{
- public class ConstructableBeatmapDecoder : BeatmapDecoder
- {
- protected override void ParseFile(TextReader stream, Beatmap beatmap)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
index 20b977499e..35d81311d2 100644
--- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
@@ -6,7 +6,6 @@ using System.Globalization;
using System.IO;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Events;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes;
using osu.Game.Modes.Objects;
@@ -31,6 +30,20 @@ namespace osu.Game.Beatmaps.Formats
// TODO: Not sure how far back to go, or differences between versions
}
+ private LegacySampleBank defaultSampleBank;
+ private int defaultSampleVolume = 100;
+
+ private readonly int beatmapVersion;
+
+ public OsuLegacyDecoder()
+ {
+ }
+
+ public OsuLegacyDecoder(string header)
+ {
+ beatmapVersion = int.Parse(header.Substring(17));
+ }
+
private enum Section
{
None,
@@ -62,7 +75,10 @@ namespace osu.Game.Beatmaps.Formats
beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
break;
case @"SampleSet":
- beatmap.BeatmapInfo.SampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val);
+ defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), val);
+ break;
+ case @"SampleVolume":
+ defaultSampleVolume = int.Parse(val);
break;
case @"StackLeniency":
beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
@@ -192,28 +208,56 @@ namespace osu.Game.Beatmaps.Formats
private void handleTimingPoints(Beatmap beatmap, string val)
{
- ControlPoint cp = null;
-
string[] split = val.Split(',');
- if (split.Length > 2)
+ double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
+ double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
+
+ TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
+ if (split.Length >= 3)
+ timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]);
+
+ LegacySampleBank sampleSet = defaultSampleBank;
+ if (split.Length >= 4)
+ sampleSet = (LegacySampleBank)int.Parse(split[3]);
+
+ //SampleBank sampleBank = SampleBank.Default;
+ //if (split.Length >= 5)
+ // sampleBank = (SampleBank)int.Parse(split[4]);
+
+ int sampleVolume = defaultSampleVolume;
+ if (split.Length >= 6)
+ sampleVolume = int.Parse(split[5]);
+
+ bool timingChange = true;
+ if (split.Length >= 7)
+ timingChange = split[6][0] == '1';
+
+ bool kiaiMode = false;
+ bool omitFirstBarSignature = false;
+ if (split.Length >= 8)
{
- int effectFlags = split.Length > 7 ? Convert.ToInt32(split[7], NumberFormatInfo.InvariantInfo) : 0;
- double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
- cp = new ControlPoint
- {
- Time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo),
- BeatLength = beatLength > 0 ? beatLength : 0,
- VelocityAdjustment = beatLength < 0 ? -beatLength / 100.0 : 1,
- TimingChange = split.Length <= 6 || split[6][0] == '1',
- KiaiMode = (effectFlags & 1) > 0,
- OmitFirstBarLine = (effectFlags & 8) > 0,
- TimeSignature = (TimeSignatures)int.Parse(split[2])
- };
+ int effectFlags = int.Parse(split[7]);
+ kiaiMode = (effectFlags & 1) > 0;
+ omitFirstBarSignature = (effectFlags & 8) > 0;
}
- if (cp != null)
- beatmap.TimingInfo.ControlPoints.Add(cp);
+ string stringSampleSet = sampleSet.ToString().ToLower();
+ if (stringSampleSet == @"none")
+ stringSampleSet = @"normal";
+
+ beatmap.TimingInfo.ControlPoints.Add(new ControlPoint
+ {
+ Time = time,
+ BeatLength = beatLength,
+ SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
+ TimingChange = timingChange,
+ TimeSignature = timeSignature,
+ SampleBank = stringSampleSet,
+ SampleVolume = sampleVolume,
+ KiaiMode = kiaiMode,
+ OmitFirstBarLine = omitFirstBarSignature
+ });
}
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
@@ -246,32 +290,36 @@ namespace osu.Game.Beatmaps.Formats
}
}
- protected override Beatmap ParseFile(TextReader stream)
+ protected override Beatmap ParseFile(StreamReader stream)
{
return new LegacyBeatmap(base.ParseFile(stream));
}
- public override Beatmap Decode(TextReader stream)
+ public override Beatmap Decode(StreamReader stream)
{
return new LegacyBeatmap(base.Decode(stream));
}
- protected override void ParseFile(TextReader stream, Beatmap beatmap)
+ protected override void ParseFile(StreamReader stream, Beatmap beatmap)
{
- HitObjectParser parser = null;
+ beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion;
+ HitObjectParser parser = new LegacyHitObjectParser();
+
+ Section section = Section.None;
bool hasCustomColours = false;
- var section = Section.None;
- while (true)
+ string line;
+ while ((line = stream.ReadLine()) != null)
{
- var line = stream.ReadLine();
- if (line == null)
- break;
if (string.IsNullOrEmpty(line))
continue;
+
if (line.StartsWith(@"osu file format v"))
+ {
+ beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17));
continue;
+ }
if (line.StartsWith(@"[") && line.EndsWith(@"]"))
{
@@ -290,7 +338,6 @@ namespace osu.Game.Beatmaps.Formats
{
case Section.General:
handleGeneral(beatmap, key, val);
- parser = new LegacyHitObjectParser();
break;
case Section.Editor:
handleEditor(beatmap, key, val);
@@ -311,7 +358,7 @@ namespace osu.Game.Beatmaps.Formats
handleColours(beatmap, key, val, ref hasCustomColours);
break;
case Section.HitObjects:
- var obj = parser?.Parse(val);
+ var obj = parser.Parse(val);
if (obj != null)
beatmap.HitObjects.Add(obj);
@@ -320,5 +367,13 @@ namespace osu.Game.Beatmaps.Formats
}
}
}
+
+ internal enum LegacySampleBank
+ {
+ None = 0,
+ Normal = 1,
+ Soft = 2,
+ Drum = 3
+ }
}
}
diff --git a/osu.Game/Beatmaps/IBeatmapCoverter.cs b/osu.Game/Beatmaps/IBeatmapConverter.cs
similarity index 100%
rename from osu.Game/Beatmaps/IBeatmapCoverter.cs
rename to osu.Game/Beatmaps/IBeatmapConverter.cs
diff --git a/osu.Game/Beatmaps/IO/ArchiveReader.cs b/osu.Game/Beatmaps/IO/ArchiveReader.cs
index bbf4de20f5..6c6b6be23c 100644
--- a/osu.Game/Beatmaps/IO/ArchiveReader.cs
+++ b/osu.Game/Beatmaps/IO/ArchiveReader.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.IO;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
-using osu.Game.Database;
namespace osu.Game.Beatmaps.IO
{
@@ -35,11 +34,6 @@ namespace osu.Game.Beatmaps.IO
readers.Add(new Reader { Test = test, Type = typeof(T) });
}
- ///
- /// Reads the beatmap metadata from this archive.
- ///
- public abstract BeatmapMetadata ReadMetadata();
-
///
/// Gets a list of beatmap file names.
///
diff --git a/osu.Game/Beatmaps/IO/OszArchiveReader.cs b/osu.Game/Beatmaps/IO/OszArchiveReader.cs
index 5c0f29fb86..6c550def8d 100644
--- a/osu.Game/Beatmaps/IO/OszArchiveReader.cs
+++ b/osu.Game/Beatmaps/IO/OszArchiveReader.cs
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using Ionic.Zip;
using osu.Game.Beatmaps.Formats;
-using osu.Game.Database;
namespace osu.Game.Beatmaps.IO
{
@@ -23,23 +22,18 @@ namespace osu.Game.Beatmaps.IO
private readonly Stream archiveStream;
private readonly ZipFile archive;
- private readonly Beatmap firstMap;
public OszArchiveReader(Stream archiveStream)
{
this.archiveStream = archiveStream;
archive = ZipFile.Read(archiveStream);
- BeatmapFilenames = archive.Entries.Where(e => e.FileName.EndsWith(@".osu"))
- .Select(e => e.FileName).ToArray();
+
+ BeatmapFilenames = archive.Entries.Where(e => e.FileName.EndsWith(@".osu")).Select(e => e.FileName).ToArray();
+
if (BeatmapFilenames.Length == 0)
throw new FileNotFoundException(@"This directory contains no beatmaps");
- StoryboardFilename = archive.Entries.Where(e => e.FileName.EndsWith(@".osb"))
- .Select(e => e.FileName).FirstOrDefault();
- using (var stream = new StreamReader(GetStream(BeatmapFilenames[0])))
- {
- var decoder = BeatmapDecoder.GetDecoder(stream);
- firstMap = decoder.Decode(stream);
- }
+
+ StoryboardFilename = archive.Entries.Where(e => e.FileName.EndsWith(@".osb")).Select(e => e.FileName).FirstOrDefault();
}
public override Stream GetStream(string name)
@@ -50,11 +44,6 @@ namespace osu.Game.Beatmaps.IO
return entry.OpenReader();
}
- public override BeatmapMetadata ReadMetadata()
- {
- return firstMap.BeatmapInfo.Metadata;
- }
-
public override void Dispose()
{
archive.Dispose();
diff --git a/osu.Game/Beatmaps/Samples/SampleBank.cs b/osu.Game/Beatmaps/Samples/SampleBank.cs
deleted file mode 100644
index 2154713cff..0000000000
--- a/osu.Game/Beatmaps/Samples/SampleBank.cs
+++ /dev/null
@@ -1,12 +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.Beatmaps.Samples
-{
- public enum SampleBank
- {
- Default = 0,
- Custom1 = 1,
- Custom2 = 2
- }
-}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Samples/SampleInfo.cs b/osu.Game/Beatmaps/Samples/SampleInfo.cs
deleted file mode 100644
index 5f9572c871..0000000000
--- a/osu.Game/Beatmaps/Samples/SampleInfo.cs
+++ /dev/null
@@ -1,11 +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.Beatmaps.Samples
-{
- public class SampleInfo
- {
- public SampleBank Bank;
- public SampleSet Set;
- }
-}
diff --git a/osu.Game/Beatmaps/Samples/SampleSet.cs b/osu.Game/Beatmaps/Samples/SampleSet.cs
deleted file mode 100644
index 72f97d9e0e..0000000000
--- a/osu.Game/Beatmaps/Samples/SampleSet.cs
+++ /dev/null
@@ -1,13 +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.Beatmaps.Samples
-{
- public enum SampleSet
- {
- None = 0,
- Normal = 1,
- Soft = 2,
- Drum = 3
- }
-}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Samples/SampleType.cs b/osu.Game/Beatmaps/Samples/SampleType.cs
deleted file mode 100644
index 0a18a65201..0000000000
--- a/osu.Game/Beatmaps/Samples/SampleType.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-
-namespace osu.Game.Beatmaps.Samples
-{
- [Flags]
- public enum SampleType
- {
- None = 0,
- Normal = 1,
- Whistle = 2,
- Finish = 4,
- Clap = 8
- };
-}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Timing/ControlPoint.cs b/osu.Game/Beatmaps/Timing/ControlPoint.cs
index 40320a88d7..ea152ccb39 100644
--- a/osu.Game/Beatmaps/Timing/ControlPoint.cs
+++ b/osu.Game/Beatmaps/Timing/ControlPoint.cs
@@ -5,18 +5,16 @@ namespace osu.Game.Beatmaps.Timing
{
public class ControlPoint
{
- public static ControlPoint Default = new ControlPoint
- {
- BeatLength = 500,
- TimingChange = true,
- };
-
+ public string SampleBank;
+ public int SampleVolume;
public TimeSignatures TimeSignature;
public double Time;
- public double BeatLength;
- public double VelocityAdjustment;
- public bool TimingChange;
+ public double BeatLength = 500;
+ public double SpeedMultiplier = 1;
+ public bool TimingChange = true;
public bool KiaiMode;
public bool OmitFirstBarLine;
+
+ public ControlPoint Clone() => (ControlPoint)MemberwiseClone();
}
}
diff --git a/osu.Game/Beatmaps/Timing/SampleChange.cs b/osu.Game/Beatmaps/Timing/SampleChange.cs
deleted file mode 100644
index 2946fd749b..0000000000
--- a/osu.Game/Beatmaps/Timing/SampleChange.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps.Samples;
-
-namespace osu.Game.Beatmaps.Timing
-{
- public class SampleChange : ControlPoint
- {
- public SampleInfo Sample;
- }
-}
diff --git a/osu.Game/Beatmaps/Timing/TimingChange.cs b/osu.Game/Beatmaps/Timing/TimingChange.cs
deleted file mode 100644
index b759fcd01c..0000000000
--- a/osu.Game/Beatmaps/Timing/TimingChange.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
-
-namespace osu.Game.Beatmaps.Timing
-{
- internal class TimingChange : ControlPoint
- {
- public TimingChange(double beatLength)
- {
- BeatLength = beatLength;
- }
-
- public double BPM => 60000 / BeatLength;
- }
-}
diff --git a/osu.Game/Beatmaps/Timing/TimingInfo.cs b/osu.Game/Beatmaps/Timing/TimingInfo.cs
index 0e47ba983b..19cb0816ba 100644
--- a/osu.Game/Beatmaps/Timing/TimingInfo.cs
+++ b/osu.Game/Beatmaps/Timing/TimingInfo.cs
@@ -10,8 +10,8 @@ namespace osu.Game.Beatmaps.Timing
{
public readonly List ControlPoints = new List();
- public double BPMMaximum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderBy(c => c.BeatLength).FirstOrDefault() ?? ControlPoint.Default).BeatLength;
- public double BPMMinimum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? ControlPoint.Default).BeatLength;
+ public double BPMMaximum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderBy(c => c.BeatLength).FirstOrDefault() ?? new ControlPoint()).BeatLength;
+ public double BPMMinimum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new ControlPoint()).BeatLength;
public double BPMMode => BPMAt(ControlPoints.Where(c => c.BeatLength != 0).GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).First().First().Time);
public double BPMAt(double time)
@@ -20,23 +20,23 @@ namespace osu.Game.Beatmaps.Timing
}
///
- /// Finds the BPM multiplier at a time.
+ /// Finds the speed multiplier at a time.
///
- /// The time to find the BPM multiplier at.
- /// The BPM multiplier.
- public double BPMMultiplierAt(double time)
+ /// The time to find the speed multiplier at.
+ /// The speed multiplier.
+ public double SpeedMultiplierAt(double time)
{
ControlPoint overridePoint;
ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
- return overridePoint?.VelocityAdjustment ?? timingPoint?.VelocityAdjustment ?? 1;
+ return overridePoint?.SpeedMultiplier ?? timingPoint?.SpeedMultiplier ?? 1;
}
///
- /// Finds the beat length at a time.
+ /// Finds the beat length at a time. This is expressed in milliseconds.
///
/// The time to find the beat length at.
- /// The beat length in milliseconds.
+ /// The beat length.
public double BeatLengthAt(double time)
{
ControlPoint overridePoint;
@@ -45,32 +45,6 @@ namespace osu.Game.Beatmaps.Timing
return timingPoint.BeatLength;
}
- ///
- /// Finds the beat velocity at a time.
- ///
- /// The time to find the velocity at.
- /// The velocity.
- public double BeatVelocityAt(double time)
- {
- ControlPoint overridePoint;
- ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
-
- return overridePoint?.VelocityAdjustment ?? timingPoint?.VelocityAdjustment ?? 1;
- }
-
- ///
- /// Finds the beat length at a time.
- ///
- /// The time to find the beat length at.
- /// The beat length in positional length units.
- public double BeatDistanceAt(double time)
- {
- ControlPoint overridePoint;
- ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
-
- return (timingPoint?.BeatLength ?? 1) * (overridePoint?.VelocityAdjustment ?? timingPoint?.VelocityAdjustment ?? 1);
- }
-
///
/// Finds the timing point at a time.
///
@@ -100,23 +74,7 @@ namespace osu.Game.Beatmaps.Timing
else break;
}
- return timingPoint ?? ControlPoint.Default;
- }
-
- ///
- /// Finds the slider velocity at a time.
- ///
- /// The time to find the slider velocity at.
- /// The slider velocity in milliseconds.
- public double SliderVelocityAt(double time)
- {
- const double base_scoring_distance = 100;
-
- double beatDistance = BeatDistanceAt(time);
-
- if (beatDistance > 0)
- return base_scoring_distance / beatDistance * 1000;
- return base_scoring_distance;
+ return timingPoint ?? new ControlPoint();
}
}
}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 74c8866596..5bea1d0986 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Beatmaps
protected abstract Beatmap GetBeatmap();
protected abstract Texture GetBackground();
protected abstract Track GetTrack();
-
+
private Beatmap beatmap;
private readonly object beatmapLock = new object();
public Beatmap Beatmap
@@ -53,7 +53,7 @@ namespace osu.Game.Beatmaps
}
}
}
-
+
private readonly object backgroundLock = new object();
private Texture background;
public Texture Background
@@ -87,7 +87,7 @@ namespace osu.Game.Beatmaps
if (track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo))
other.track = track;
}
-
+
public virtual void Dispose()
{
track?.Dispose();
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 6190678e1e..e2f33479c0 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Configuration
protected override void InitialiseDefaults()
{
#pragma warning disable CS0612 // Type or member is obsolete
-
+
Set(OsuConfig.Username, string.Empty);
Set(OsuConfig.Token, string.Empty);
@@ -31,10 +31,11 @@ namespace osu.Game.Configuration
Set(OsuConfig.MouseDisableWheel, false);
Set(OsuConfig.SnakingInSliders, true);
- Set(OsuConfig.SnakingOutSliders, false);
+ Set(OsuConfig.SnakingOutSliders, true);
Set(OsuConfig.MenuParallax, true);
+ Set(OsuConfig.ShowInterface, true);
Set(OsuConfig.KeyOverlay, false);
//todo: implement all settings below this line (remove the Disabled set when doing so).
@@ -45,6 +46,7 @@ namespace osu.Game.Configuration
Set(OsuConfig.AutomaticDownload, true).Disabled = true;
Set(OsuConfig.AutomaticDownloadNoVideo, false).Disabled = true;
Set(OsuConfig.BlockNonFriendPM, false).Disabled = true;
+ Set(OsuConfig.Bloom, false).Disabled = true;
Set(OsuConfig.BloomSoftening, false).Disabled = true;
Set(OsuConfig.BossKeyFirstActivation, true).Disabled = true;
Set(OsuConfig.ChatAudibleHighlight, true).Disabled = true;
@@ -89,7 +91,6 @@ namespace osu.Game.Configuration
Set(OsuConfig.LastVersionPermissionsFailed, string.Empty).Disabled = true;
Set(OsuConfig.LoadSubmittedThread, true).Disabled = true;
Set(OsuConfig.LobbyPlayMode, -1).Disabled = true;
- Set(OsuConfig.ShowInterface, true).Disabled = true;
Set(OsuConfig.ShowInterfaceDuringRelax, false).Disabled = true;
Set(OsuConfig.LobbyShowExistingOnly, false).Disabled = true;
Set(OsuConfig.LobbyShowFriendsOnly, false).Disabled = true;
@@ -187,10 +188,6 @@ namespace osu.Game.Configuration
#pragma warning restore CS0612 // Type or member is obsolete
}
- //todo: make a UnicodeString class/struct rather than requiring this helper method.
- public string GetUnicodeString(string nonunicode, string unicode)
- => Get(OsuConfig.ShowUnicode) ? unicode ?? nonunicode : nonunicode ?? unicode;
-
public OsuConfigManager(Storage storage) : base(storage)
{
}
diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs
index dfc916a136..41ddd8df39 100644
--- a/osu.Game/Database/BeatmapDatabase.cs
+++ b/osu.Game/Database/BeatmapDatabase.cs
@@ -175,7 +175,10 @@ namespace osu.Game.Database
BeatmapMetadata metadata;
using (var reader = ArchiveReader.GetReader(storage, path))
- metadata = reader.ReadMetadata();
+ {
+ using (var stream = new StreamReader(reader.GetStream(reader.BeatmapFilenames[0])))
+ metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
+ }
if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader
{
diff --git a/osu.Game/Database/BaseDifficulty.cs b/osu.Game/Database/BeatmapDifficulty.cs
similarity index 78%
rename from osu.Game/Database/BaseDifficulty.cs
rename to osu.Game/Database/BeatmapDifficulty.cs
index 3db8b29644..7c9f47e7b6 100644
--- a/osu.Game/Database/BaseDifficulty.cs
+++ b/osu.Game/Database/BeatmapDifficulty.cs
@@ -9,12 +9,12 @@ namespace osu.Game.Database
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
- public float DrainRate { get; set; }
- public float CircleSize { get; set; }
- public float OverallDifficulty { get; set; }
- public float ApproachRate { get; set; }
- public float SliderMultiplier { get; set; }
- public float SliderTickRate { get; set; }
+ public float DrainRate { get; set; } = 5;
+ public float CircleSize { get; set; } = 5;
+ public float OverallDifficulty { get; set; } = 5;
+ public float ApproachRate { get; set; } = 5;
+ public float SliderMultiplier { get; set; } = 1;
+ public float SliderTickRate { get; set; } = 1;
///
/// Maps a difficulty value [0, 10] to a two-piece linear range of values.
diff --git a/osu.Game/Database/BeatmapInfo.cs b/osu.Game/Database/BeatmapInfo.cs
index cda9cba70c..3e84825919 100644
--- a/osu.Game/Database/BeatmapInfo.cs
+++ b/osu.Game/Database/BeatmapInfo.cs
@@ -1,7 +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.Beatmaps.Samples;
+using Newtonsoft.Json;
+using osu.Game.IO.Serialization;
using osu.Game.Modes;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
@@ -10,11 +11,14 @@ using System.Linq;
namespace osu.Game.Database
{
- public class BeatmapInfo : IEquatable
+ public class BeatmapInfo : IEquatable, IJsonSerializable
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
+ //TODO: should be in database
+ public int BeatmapVersion;
+
public int? OnlineBeatmapID { get; set; }
public int? OnlineBeatmapSetID { get; set; }
@@ -37,14 +41,17 @@ namespace osu.Game.Database
[OneToOne(CascadeOperations = CascadeOperation.All)]
public BeatmapDifficulty Difficulty { get; set; }
+ [Ignore]
+ public BeatmapMetrics Metrics { get; set; }
+
public string Path { get; set; }
+ [JsonProperty("file_md5")]
public string Hash { get; set; }
// General
public int AudioLeadIn { get; set; }
public bool Countdown { get; set; }
- public SampleSet SampleSet { get; set; }
public float StackLeniency { get; set; }
public bool SpecialStyle { get; set; }
public PlayMode Mode { get; set; }
@@ -54,17 +61,13 @@ namespace osu.Game.Database
// Editor
// This bookmarks stuff is necessary because DB doesn't know how to store int[]
public string StoredBookmarks { get; internal set; }
+
[Ignore]
+ [JsonIgnore]
public int[] Bookmarks
{
- get
- {
- return StoredBookmarks.Split(',').Select(int.Parse).ToArray();
- }
- set
- {
- StoredBookmarks = string.Join(",", value);
- }
+ get { return StoredBookmarks.Split(',').Select(int.Parse).ToArray(); }
+ set { StoredBookmarks = string.Join(",", value); }
}
public double DistanceSpacing { get; set; }
@@ -83,7 +86,7 @@ namespace osu.Game.Database
}
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
- BeatmapSet.Path == other.BeatmapSet.Path &&
- (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
+ BeatmapSet.Path == other.BeatmapSet.Path &&
+ (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
}
}
diff --git a/osu.Game/Database/BeatmapMetrics.cs b/osu.Game/Database/BeatmapMetrics.cs
new file mode 100644
index 0000000000..91320110d0
--- /dev/null
+++ b/osu.Game/Database/BeatmapMetrics.cs
@@ -0,0 +1,28 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+
+namespace osu.Game.Database
+{
+ ///
+ /// Beatmap metrics based on acculumated online data from community plays.
+ ///
+ public class BeatmapMetrics
+ {
+ ///
+ /// Total vote counts of user ratings on a scale of 0..length.
+ ///
+ public IEnumerable Ratings { get; set; }
+
+ ///
+ /// Points of failure on a relative time scale (usually 0..100).
+ ///
+ public IEnumerable Fails { get; set; }
+
+ ///
+ /// Points of retry on a relative time scale (usually 0..100).
+ ///
+ public IEnumerable Retries { get; set; }
+ }
+}
diff --git a/osu.Game/Database/DatabaseWorkingBeatmap.cs b/osu.Game/Database/DatabaseWorkingBeatmap.cs
index 1b37cf2fa0..9fb3bed1e7 100644
--- a/osu.Game/Database/DatabaseWorkingBeatmap.cs
+++ b/osu.Game/Database/DatabaseWorkingBeatmap.cs
@@ -34,12 +34,14 @@ namespace osu.Game.Database
using (var stream = new StreamReader(reader.GetStream(BeatmapInfo.Path)))
{
decoder = BeatmapDecoder.GetDecoder(stream);
- beatmap = decoder?.Decode(stream);
+ beatmap = decoder.Decode(stream);
}
- if (WithStoryboard && beatmap != null && BeatmapSetInfo.StoryboardFile != null)
- using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
- decoder.Decode(stream, beatmap);
+ if (beatmap == null || !WithStoryboard || BeatmapSetInfo.StoryboardFile == null)
+ return beatmap;
+
+ using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
+ decoder.Decode(stream, beatmap);
}
return beatmap;
diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs
index 5ce3ff273e..642bb4aff6 100644
--- a/osu.Game/Database/ScoreDatabase.cs
+++ b/osu.Game/Database/ScoreDatabase.cs
@@ -104,7 +104,7 @@ namespace osu.Game.Database
score.Replay = score.CreateReplay(reader);
}
}
-
+
return score;
}
}
diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs
index 8dff614f6c..830d0adc97 100644
--- a/osu.Game/Graphics/Backgrounds/Triangles.cs
+++ b/osu.Game/Graphics/Backgrounds/Triangles.cs
@@ -60,8 +60,8 @@ namespace osu.Game.Graphics.Backgrounds
protected override void LoadComplete()
{
base.LoadComplete();
- for (int i = 0; i < aimTriangleCount; i++)
- addTriangle(true);
+
+ addTriangles(true);
}
private int aimTriangleCount => (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
@@ -83,8 +83,8 @@ namespace osu.Game.Graphics.Backgrounds
t.Expire();
}
- while (CreateNewTriangles && Children.Count() < aimTriangleCount)
- addTriangle(false);
+ if (CreateNewTriangles)
+ addTriangles(false);
}
protected virtual Triangle CreateTriangle()
@@ -113,12 +113,16 @@ namespace osu.Game.Graphics.Backgrounds
protected virtual Color4 GetTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
- private void addTriangle(bool randomY)
+ private void addTriangles(bool randomY)
{
- var sprite = CreateTriangle();
- float triangleHeight = sprite.DrawHeight / DrawHeight;
- sprite.Position = new Vector2(RNG.NextSingle(), randomY ? RNG.NextSingle() * (1 + triangleHeight) - triangleHeight : 1);
- Add(sprite);
+ int addCount = aimTriangleCount - Children.Count();
+ for (int i = 0; i < addCount; i++)
+ {
+ var sprite = CreateTriangle();
+ float triangleHeight = sprite.DrawHeight / DrawHeight;
+ sprite.Position = new Vector2(RNG.NextSingle(), randomY ? RNG.NextSingle() * (1 + triangleHeight) - triangleHeight : 1);
+ Add(sprite);
+ }
}
}
}
diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs
index a143618807..8352656f8e 100644
--- a/osu.Game/Graphics/Containers/ParallaxContainer.cs
+++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs
@@ -56,8 +56,8 @@ namespace osu.Game.Graphics.Containers
{
base.Update();
- if (parallaxEnabled)
- {
+ if (parallaxEnabled)
+ {
Vector2 offset = input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2;
content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
content.Scale = new Vector2(1 + ParallaxAmount);
diff --git a/osu.Game/Graphics/Cursor/CursorTrail.cs b/osu.Game/Graphics/Cursor/CursorTrail.cs
index 4b5610e840..09d1b99d13 100644
--- a/osu.Game/Graphics/Cursor/CursorTrail.cs
+++ b/osu.Game/Graphics/Cursor/CursorTrail.cs
@@ -13,6 +13,7 @@ using osu.Framework.Graphics.OpenGL.Buffers;
using OpenTK.Graphics.ES30;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Colour;
+using osu.Framework.Timing;
namespace osu.Game.Graphics.Cursor
{
@@ -58,6 +59,9 @@ namespace osu.Game.Graphics.Cursor
public CursorTrail()
{
+ // as we are currently very dependent on having a running clock, let's make our own clock for the time being.
+ Clock = new FramedClock();
+
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
@@ -231,4 +235,4 @@ namespace osu.Game.Graphics.Cursor
}
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Graphics/Cursor/GameplayCursor.cs b/osu.Game/Graphics/Cursor/GameplayCursor.cs
index 3f94bbaddc..3f699219a4 100644
--- a/osu.Game/Graphics/Cursor/GameplayCursor.cs
+++ b/osu.Game/Graphics/Cursor/GameplayCursor.cs
@@ -12,7 +12,6 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Configuration;
-using System;
namespace osu.Game.Graphics.Cursor
{
@@ -116,14 +115,9 @@ namespace osu.Game.Graphics.Cursor
};
cursorScale = config.GetBindable(OsuConfig.GameplayCursorSize);
- cursorScale.ValueChanged += scaleChanged;
+ cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)cursorScale);
cursorScale.TriggerChange();
}
-
- private void scaleChanged(object sender, EventArgs e)
- {
- cursorContainer.Scale = new Vector2((float)cursorScale);
- }
}
}
}
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 361d0cc1ef..4d5e0848cb 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -119,14 +119,12 @@ namespace osu.Game.Graphics.Cursor
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, EasingTypes.OutQuint);
- ActiveCursor.ScaleTo(1, 1000, EasingTypes.OutElastic);
+ ActiveCursor.ScaleTo(1, 400, EasingTypes.OutQuint);
}
protected override void PopOut()
{
- ActiveCursor.FadeTo(0, 1400, EasingTypes.OutQuint);
- ActiveCursor.ScaleTo(1.1f, 100, EasingTypes.Out);
- ActiveCursor.Delay(100);
+ ActiveCursor.FadeTo(0, 900, EasingTypes.OutQuint);
ActiveCursor.ScaleTo(0, 500, EasingTypes.In);
}
@@ -175,15 +173,10 @@ namespace osu.Game.Graphics.Cursor
};
cursorScale = config.GetBindable(OsuConfig.MenuCursorSize);
- cursorScale.ValueChanged += scaleChanged;
+ cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale);
+ cursorScale.ValueChanged += newScale => Tooltip.Y = cursorContainer.Height * (float)newScale;
cursorScale.TriggerChange();
}
-
- private void scaleChanged(object sender, EventArgs e)
- {
- cursorContainer.Scale = new Vector2((float)cursorScale);
- Tooltip.Y = cursorContainer.Height * (float)cursorScale;
- }
}
}
}
diff --git a/osu.Game/Graphics/IHasAccentColour.cs b/osu.Game/Graphics/IHasAccentColour.cs
index f959bc8760..e4647f22fd 100644
--- a/osu.Game/Graphics/IHasAccentColour.cs
+++ b/osu.Game/Graphics/IHasAccentColour.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Graphics
/// The tween easing.
public static void FadeAccent(this IHasAccentColour accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
{
- accentedDrawable.TransformTo(accentedDrawable.AccentColour, newColour, duration, easing, new TransformAccent());
+ accentedDrawable.TransformTo(() => accentedDrawable.AccentColour, newColour, duration, easing, new TransformAccent());
}
}
}
diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs
new file mode 100644
index 0000000000..76b75f1084
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/Bar.cs
@@ -0,0 +1,137 @@
+// 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.Sprites;
+using System;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class Bar : Container, IHasAccentColour
+ {
+ private readonly Box background;
+ private readonly Box bar;
+
+ private const int resize_duration = 250;
+
+ private const EasingTypes easing = EasingTypes.InOutCubic;
+
+ private float length;
+ ///
+ /// Length of the bar, ranges from 0 to 1
+ ///
+ public float Length
+ {
+ get
+ {
+ return length;
+ }
+ set
+ {
+ length = MathHelper.Clamp(value, 0, 1);
+ updateBarLength();
+ }
+ }
+
+ public Color4 BackgroundColour
+ {
+ get
+ {
+ return background.Colour;
+ }
+ set
+ {
+ background.Colour = value;
+ }
+ }
+
+ public Color4 AccentColour
+ {
+ get
+ {
+ return bar.Colour;
+ }
+ set
+ {
+ bar.Colour = value;
+ }
+ }
+
+ private BarDirection direction = BarDirection.LeftToRight;
+ public BarDirection Direction
+ {
+ get
+ {
+ return direction;
+ }
+ set
+ {
+ direction = value;
+ updateBarLength();
+ }
+ }
+
+ public Bar()
+ {
+ Children = new[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = new Color4(0,0,0,0)
+ },
+ bar = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Width = 0,
+ },
+ };
+ }
+
+ private void updateBarLength()
+ {
+ switch (direction)
+ {
+ case BarDirection.LeftToRight:
+ case BarDirection.RightToLeft:
+ bar.ResizeTo(new Vector2(length, 1), resize_duration, easing);
+ break;
+
+ case BarDirection.TopToBottom:
+ case BarDirection.BottomToTop:
+ bar.ResizeTo(new Vector2(1, length), resize_duration, easing);
+ break;
+ }
+
+ switch (direction)
+ {
+ case BarDirection.LeftToRight:
+ case BarDirection.TopToBottom:
+ bar.Anchor = Anchor.TopLeft;
+ bar.Origin = Anchor.TopLeft;
+ break;
+
+ case BarDirection.RightToLeft:
+ case BarDirection.BottomToTop:
+ bar.Anchor = Anchor.BottomRight;
+ bar.Origin = Anchor.BottomRight;
+ break;
+ }
+ }
+ }
+
+ [Flags]
+ public enum BarDirection
+ {
+ LeftToRight = 1 << 0,
+ RightToLeft = 1 << 1,
+ TopToBottom = 1 << 2,
+ BottomToTop = 1 << 3,
+
+ Vertical = TopToBottom | BottomToTop,
+ Horizontal = LeftToRight | RightToLeft,
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs
new file mode 100644
index 0000000000..d0965a1861
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/BarGraph.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 OpenTK;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class BarGraph : FillFlowContainer
+ {
+ ///
+ /// Manually sets the max value, if null is instead used
+ ///
+ public float? MaxValue { get; set; }
+
+ private BarDirection direction = BarDirection.BottomToTop;
+ public new BarDirection Direction
+ {
+ get
+ {
+ return direction;
+ }
+ set
+ {
+ direction = value;
+ base.Direction = (direction & BarDirection.Horizontal) > 0 ? FillDirection.Vertical : FillDirection.Horizontal;
+ foreach (var bar in Children)
+ {
+ bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / Children.Count()) : new Vector2(1.0f / Children.Count(), 1);
+ bar.Direction = direction;
+ }
+ }
+ }
+
+ ///
+ /// A list of floats that defines the length of each
+ ///
+ public IEnumerable Values
+ {
+ set
+ {
+ List bars = Children.ToList();
+ foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
+ if (bar.Bar != null)
+ {
+ bar.Bar.Length = bar.Value / (MaxValue ?? value.Max());
+ bar.Bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / value.Count()) : new Vector2(1.0f / value.Count(), 1);
+ }
+ else
+ Add(new Bar
+ {
+ RelativeSizeAxes = Axes.Both,
+ Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / value.Count()) : new Vector2(1.0f / value.Count(), 1),
+ Length = bar.Value / (MaxValue ?? value.Max()),
+ Direction = Direction,
+ });
+ //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
+ Remove(Children.Where((bar, index) => index >= value.Count()).ToList());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs
index e150c7dc07..82ede8f079 100644
--- a/osu.Game/Graphics/UserInterface/Nub.cs
+++ b/osu.Game/Graphics/UserInterface/Nub.cs
@@ -3,8 +3,8 @@
using OpenTK;
using OpenTK.Graphics;
-using osu.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
@@ -12,18 +12,18 @@ using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
- public class Nub : CircularContainer, IStateful
+ public class Nub : CircularContainer, IHasCurrentValue
{
public const float COLLAPSED_SIZE = 20;
public const float EXPANDED_SIZE = 40;
- private readonly Box fill;
-
private const float border_width = 3;
private Color4 glowingColour, idleColour;
public Nub()
{
+ Box fill;
+
Size = new Vector2(COLLAPSED_SIZE, 12);
BorderColour = Color4.White;
@@ -40,6 +40,14 @@ namespace osu.Game.Graphics.UserInterface
AlwaysPresent = true,
},
};
+
+ Current.ValueChanged += newValue =>
+ {
+ if (newValue)
+ fill.FadeIn(200, EasingTypes.OutQuint);
+ else
+ fill.FadeTo(0.01f, 200, EasingTypes.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
+ };
}
[BackgroundDependencyLoader]
@@ -84,28 +92,6 @@ namespace osu.Game.Graphics.UserInterface
}
}
- private CheckboxState state;
-
- public CheckboxState State
- {
- get
- {
- return state;
- }
- set
- {
- state = value;
-
- switch (state)
- {
- case CheckboxState.Checked:
- fill.FadeIn(200, EasingTypes.OutQuint);
- break;
- case CheckboxState.Unchecked:
- fill.FadeTo(0.01f, 200, EasingTypes.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
- break;
- }
- }
- }
+ public Bindable Current { get; } = new Bindable();
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
index fc44d80ea6..d339388aa5 100644
--- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.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 System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@@ -24,18 +23,9 @@ namespace osu.Game.Graphics.UserInterface
{
set
{
- if (bindable != null)
- bindable.ValueChanged -= bindableValueChanged;
bindable = value;
- if (bindable != null)
- {
- bool state = State == CheckboxState.Checked;
- if (state != bindable.Value)
- State = bindable.Value ? CheckboxState.Checked : CheckboxState.Unchecked;
- bindable.ValueChanged += bindableValueChanged;
- }
-
- if (bindable?.Disabled ?? true)
+ Current.BindTo(bindable);
+ if (value?.Disabled ?? true)
Alpha = 0.3f;
}
}
@@ -84,18 +74,16 @@ namespace osu.Game.Graphics.UserInterface
Margin = new MarginPadding { Right = 5 },
}
};
- }
- private void bindableValueChanged(object sender, EventArgs e)
- {
- State = bindable.Value ? CheckboxState.Checked : CheckboxState.Unchecked;
- }
+ nub.Current.BindTo(Current);
- protected override void Dispose(bool isDisposing)
- {
- if (bindable != null)
- bindable.ValueChanged -= bindableValueChanged;
- base.Dispose(isDisposing);
+ Current.ValueChanged += newValue =>
+ {
+ if (newValue)
+ sampleChecked?.Play();
+ else
+ sampleUnchecked?.Play();
+ };
}
protected override bool OnHover(InputState state)
@@ -118,23 +106,5 @@ namespace osu.Game.Graphics.UserInterface
sampleChecked = audio.Sample.Get(@"Checkbox/check-on");
sampleUnchecked = audio.Sample.Get(@"Checkbox/check-off");
}
-
- protected override void OnChecked()
- {
- sampleChecked?.Play();
- nub.State = CheckboxState.Checked;
-
- if (bindable != null)
- bindable.Value = true;
- }
-
- protected override void OnUnchecked()
- {
- sampleUnchecked?.Play();
- nub.State = CheckboxState.Unchecked;
-
- if (bindable != null)
- bindable.Value = false;
- }
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
index 3466fb1a60..9bb0d15545 100644
--- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs
+++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface
private class OsuDropdownMenuItem : DropdownMenuItem
{
- public OsuDropdownMenuItem(string text, T value) : base(text, value)
+ public OsuDropdownMenuItem(string text, T current) : base(text, current)
{
Foreground.Padding = new MarginPadding(2);
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index 078c8564d7..180cb88707 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
-using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@@ -50,7 +49,6 @@ namespace osu.Game.Graphics.UserInterface
nub = new Nub
{
Origin = Anchor.TopCentre,
- State = CheckboxState.Unchecked,
Expanded = true,
}
};
@@ -64,15 +62,6 @@ namespace osu.Game.Graphics.UserInterface
rightBox.Colour = colours.Pink;
}
- private void playSample()
- {
- if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
- return;
- lastSampleTime = Clock.CurrentTime;
- sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
- sample.Play();
- }
-
protected override bool OnHover(InputState state)
{
nub.Glowing = true;
@@ -85,37 +74,39 @@ namespace osu.Game.Graphics.UserInterface
base.OnHoverLost(state);
}
- protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
+ protected override void OnUserChange()
{
- if (args.Key == Key.Left || args.Key == Key.Right)
- playSample();
- return base.OnKeyDown(state, args);
+ base.OnUserChange();
+ playSample();
+ }
+
+ private void playSample()
+ {
+ if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
+ return;
+ lastSampleTime = Clock.CurrentTime;
+ sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
+
+ if (NormalizedValue == 0)
+ sample.Frequency.Value -= 0.4f;
+ else if (NormalizedValue == 1)
+ sample.Frequency.Value += 0.4f;
+
+ sample.Play();
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
- nub.State = CheckboxState.Checked;
+ nub.Current.Value = true;
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
- nub.State = CheckboxState.Unchecked;
+ nub.Current.Value = false;
return base.OnMouseUp(state, args);
}
- protected override bool OnClick(InputState state)
- {
- playSample();
- return base.OnClick(state);
- }
-
- protected override bool OnDrag(InputState state)
- {
- playSample();
- return base.OnDrag(state);
- }
-
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
index 6d17d79ca1..242a9a8f6a 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface
{
protected override Dropdown CreateDropdown() => new OsuTabDropdown();
- protected override TabItem CreateTabItem(T value) => new OsuTabItem { Value = value };
+ protected override TabItem CreateTabItem(T value) => new OsuTabItem(value);
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || Dropdown.Contains(screenSpacePos);
@@ -75,16 +75,6 @@ namespace osu.Game.Graphics.UserInterface
}
}
- public new T Value
- {
- get { return base.Value; }
- set
- {
- base.Value = value;
- text.Text = (value as Enum)?.GetDescription();
- }
- }
-
public override bool Active
{
get { return base.Active; }
@@ -134,30 +124,31 @@ namespace osu.Game.Graphics.UserInterface
AccentColour = colours.Blue;
}
- public OsuTabItem()
+ public OsuTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
- text = new OsuSpriteText
- {
- Margin = new MarginPadding { Top = 5, Bottom = 5 },
- Origin = Anchor.BottomLeft,
- Anchor = Anchor.BottomLeft,
- TextSize = 14,
- Font = @"Exo2.0-Bold", // Font should only turn bold when active?
- },
- box = new Box
- {
- RelativeSizeAxes = Axes.X,
- Height = 1,
- Alpha = 0,
- Colour = Color4.White,
- Origin = Anchor.BottomLeft,
- Anchor = Anchor.BottomLeft,
- }
+ text = new OsuSpriteText
+ {
+ Margin = new MarginPadding { Top = 5, Bottom = 5 },
+ Origin = Anchor.BottomLeft,
+ Anchor = Anchor.BottomLeft,
+ Text = (value as Enum)?.GetDescription(),
+ TextSize = 14,
+ Font = @"Exo2.0-Bold", // Font should only turn bold when active?
+ },
+ box = new Box
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 1,
+ Alpha = 0,
+ Colour = Color4.White,
+ Origin = Anchor.BottomLeft,
+ Anchor = Anchor.BottomLeft,
+ }
};
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckBox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
similarity index 84%
rename from osu.Game/Graphics/UserInterface/OsuTabControlCheckBox.cs
rename to osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
index 5914d0ba4c..f732916889 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.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 System;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
@@ -24,8 +23,6 @@ namespace osu.Game.Graphics.UserInterface
private readonly SpriteText text;
private readonly TextAwesome icon;
- public event EventHandler Action;
-
private Color4? accentColour;
public Color4 AccentColour
{
@@ -34,7 +31,7 @@ namespace osu.Game.Graphics.UserInterface
{
accentColour = value;
- if (State != CheckboxState.Checked)
+ if (Current)
{
text.Colour = AccentColour;
icon.Colour = AccentColour;
@@ -48,20 +45,6 @@ namespace osu.Game.Graphics.UserInterface
set { text.Text = value; }
}
- protected override void OnChecked()
- {
- fadeIn();
- icon.Icon = FontAwesome.fa_check_circle_o;
- Action?.Invoke(this, State);
- }
-
- protected override void OnUnchecked()
- {
- fadeOut();
- icon.Icon = FontAwesome.fa_circle_o;
- Action?.Invoke(this, State);
- }
-
private const float transition_length = 500;
private void fadeIn()
@@ -84,7 +67,7 @@ namespace osu.Game.Graphics.UserInterface
protected override void OnHoverLost(InputState state)
{
- if (State == CheckboxState.Unchecked)
+ if (!Current)
fadeOut();
base.OnHoverLost(state);
@@ -134,6 +117,20 @@ namespace osu.Game.Graphics.UserInterface
Anchor = Anchor.BottomLeft,
}
};
+
+ Current.ValueChanged += v =>
+ {
+ if (v)
+ {
+ fadeIn();
+ icon.Icon = FontAwesome.fa_check_circle_o;
+ }
+ else
+ {
+ fadeOut();
+ icon.Icon = FontAwesome.fa_circle_o;
+ }
+ };
}
}
}
diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs
index a4f6092d66..869ee37e11 100644
--- a/osu.Game/Graphics/UserInterface/RollingCounter.cs
+++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs
@@ -98,21 +98,16 @@ namespace osu.Game.Graphics.UserInterface
DisplayedCount = Current;
- Current.ValueChanged += currentChanged;
- }
-
- private void currentChanged(object sender, EventArgs e)
- {
- if (IsLoaded)
- TransformCount(displayedCount, Current);
+ Current.ValueChanged += newValue =>
+ {
+ if (IsLoaded) TransformCount(displayedCount, newValue);
+ };
}
protected override void LoadComplete()
{
base.LoadComplete();
- Flush(false, TransformType);
-
DisplayedCountSpriteText.Text = FormatCount(Current);
DisplayedCountSpriteText.Anchor = Anchor;
DisplayedCountSpriteText.Origin = Origin;
@@ -208,8 +203,8 @@ namespace osu.Game.Graphics.UserInterface
? GetProportionalDuration(currentValue, newValue)
: RollingDuration;
- transform.StartTime = Time.Current;
- transform.EndTime = Time.Current + rollingTotalDuration;
+ transform.StartTime = TransformStartTime;
+ transform.EndTime = TransformStartTime + rollingTotalDuration;
transform.StartValue = currentValue;
transform.EndValue = newValue;
transform.Easing = RollingEasing;
diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
index 374385e351..4933c170e8 100644
--- a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs
+++ b/osu.Game/Graphics/UserInterface/Volume/VolumeControl.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 System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
@@ -19,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
protected override bool HideOnEscape => false;
- private void volumeChanged(object sender, EventArgs e)
+ private void volumeChanged(double newVolume)
{
Show();
schedulePopOut();
diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs
new file mode 100644
index 0000000000..33d0801e47
--- /dev/null
+++ b/osu.Game/IO/Serialization/IJsonSerializable.cs
@@ -0,0 +1,29 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using Newtonsoft.Json;
+
+namespace osu.Game.IO.Serialization
+{
+ public interface IJsonSerializable
+ {
+ }
+
+ public static class JsonSerializableExtensions
+ {
+ public static string Serialize(this IJsonSerializable obj)
+ {
+ return JsonConvert.SerializeObject(obj);
+ }
+
+ public static T Deserialize(string objString)
+ {
+ return JsonConvert.DeserializeObject(objString);
+ }
+
+ public static T DeepClone(this IJsonSerializable obj)
+ {
+ return Deserialize(Serialize(obj));
+ }
+ }
+}
diff --git a/osu.Game/Modes/Judgements/Judgement.cs b/osu.Game/Modes/Judgements/Judgement.cs
index 677ec8bca9..1bf898d25c 100644
--- a/osu.Game/Modes/Judgements/Judgement.cs
+++ b/osu.Game/Modes/Judgements/Judgement.cs
@@ -17,10 +17,7 @@ namespace osu.Game.Modes.Judgements
///
public double TimeOffset;
- ///
- /// The combo after this judgement was processed.
- ///
- public int ComboAtHit;
+ public virtual bool AffectsCombo => true;
///
/// The string representation for the result achieved.
diff --git a/osu.Game/Modes/Objects/BezierApproximator.cs b/osu.Game/Modes/Objects/BezierApproximator.cs
index ee8e9b0e06..6688e6b2ce 100644
--- a/osu.Game/Modes/Objects/BezierApproximator.cs
+++ b/osu.Game/Modes/Objects/BezierApproximator.cs
@@ -109,7 +109,7 @@ namespace osu.Game.Modes.Objects
// "toFlatten" contains all the curves which are not yet approximated well enough.
// We use a stack to emulate recursion without the risk of running into a stack overflow.
- // (More specifically, we iteratively and adaptively refine our curve with a
+ // (More specifically, we iteratively and adaptively refine our curve with a
// Depth-first search
// over the tree resulting from the subdivisions we make.)
toFlatten.Push(controlPoints.ToArray());
diff --git a/osu.Game/Modes/Objects/CircularArcApproximator.cs b/osu.Game/Modes/Objects/CircularArcApproximator.cs
index 310b923b0b..73db5fab29 100644
--- a/osu.Game/Modes/Objects/CircularArcApproximator.cs
+++ b/osu.Game/Modes/Objects/CircularArcApproximator.cs
@@ -66,7 +66,7 @@ namespace osu.Game.Modes.Objects
double dir = 1;
double thetaRange = thetaEnd - thetaStart;
- // Decide in which direction to draw the circle, depending on which side of
+ // Decide in which direction to draw the circle, depending on which side of
// AC B lies.
Vector2 orthoAtoC = c - a;
orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X);
diff --git a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs
index ed8269876e..e346a22813 100644
--- a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs
@@ -7,11 +7,11 @@ using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Judgements;
using Container = osu.Framework.Graphics.Containers.Container;
using osu.Game.Modes.Objects.Types;
using OpenTK.Graphics;
+using osu.Game.Audio;
namespace osu.Game.Modes.Objects.Drawables
{
@@ -45,25 +45,29 @@ namespace osu.Game.Modes.Objects.Drawables
UpdateState(state);
if (State == ArmedState.Hit)
- PlaySample();
+ PlaySamples();
}
}
- protected SampleChannel Sample;
+ protected List Samples = new List();
- protected virtual void PlaySample()
+ protected void PlaySamples()
{
- Sample?.Play();
+ Samples.ForEach(s => s?.Play());
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ //we may be setting a custom judgement in test cases or what not.
+ if (Judgement == null)
+ Judgement = CreateJudgement();
}
protected override void LoadComplete()
{
base.LoadComplete();
- //we may be setting a custom judgement in test cases or what not.
- if (Judgement == null)
- Judgement = CreateJudgement();
-
//force application of the state that was set before we loaded.
UpdateState(State);
}
@@ -152,13 +156,16 @@ namespace osu.Game.Modes.Objects.Drawables
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
- SampleType type = HitObject.Sample?.Type ?? SampleType.None;
- if (type == SampleType.None)
- type = SampleType.Normal;
+ foreach (SampleInfo sample in HitObject.Samples)
+ {
+ SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}");
- SampleSet sampleSet = HitObject.Sample?.Set ?? SampleSet.Normal;
+ if (channel == null)
+ continue;
- Sample = audio.Sample.Get($@"Gameplay/{sampleSet.ToString().ToLower()}-hit{type.ToString().ToLower()}");
+ channel.Volume.Value = sample.Volume;
+ Samples.Add(channel);
+ }
}
private List> nestedHitObjects;
diff --git a/osu.Game/Modes/Objects/HitObject.cs b/osu.Game/Modes/Objects/HitObject.cs
index f2712d92ba..f362d6de63 100644
--- a/osu.Game/Modes/Objects/HitObject.cs
+++ b/osu.Game/Modes/Objects/HitObject.cs
@@ -1,9 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Game.Beatmaps.Samples;
+using osu.Game.Audio;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
+using System.Collections.Generic;
namespace osu.Game.Modes.Objects
{
@@ -21,15 +22,31 @@ namespace osu.Game.Modes.Objects
public double StartTime { get; set; }
///
- /// The sample to be played when this HitObject is hit.
+ /// The samples to be played when this hit object is hit.
///
- public HitSampleInfo Sample { get; set; }
+ public List Samples = new List();
///
/// Applies default values to this HitObject.
///
/// The difficulty settings to use.
/// The timing settings to use.
- public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty) { }
+ public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
+ {
+ ControlPoint overridePoint;
+ ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
+
+ foreach (var sample in Samples)
+ {
+ if (sample.Volume == 0)
+ sample.Volume = (overridePoint ?? timingPoint)?.SampleVolume ?? 0;
+
+ // If the bank is not assigned a name, assign it from the control point
+ if (!string.IsNullOrEmpty(sample.Bank))
+ continue;
+
+ sample.Bank = (overridePoint ?? timingPoint)?.SampleBank ?? @"normal";
+ }
+ }
}
}
diff --git a/osu.Game/Modes/Objects/LegacyHitObjectParser.cs b/osu.Game/Modes/Objects/LegacyHitObjectParser.cs
index ccc5f18822..2316e5dc5d 100644
--- a/osu.Game/Modes/Objects/LegacyHitObjectParser.cs
+++ b/osu.Game/Modes/Objects/LegacyHitObjectParser.cs
@@ -2,12 +2,13 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
-using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Globalization;
using osu.Game.Modes.Objects.Legacy;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.Audio;
namespace osu.Game.Modes.Objects
{
@@ -20,6 +21,10 @@ namespace osu.Game.Modes.Objects
bool combo = type.HasFlag(LegacyHitObjectType.NewCombo);
type &= ~LegacyHitObjectType.NewCombo;
+ int sampleVolume = 0;
+ string normalSampleBank = null;
+ string addSampleBank = null;
+
HitObject result;
if ((type & LegacyHitObjectType.Circle) > 0)
@@ -29,6 +34,9 @@ namespace osu.Game.Modes.Objects
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
NewCombo = combo
};
+
+ if (split.Length > 5)
+ readCustomSampleBanks(split[5], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Slider) > 0)
{
@@ -84,6 +92,9 @@ namespace osu.Game.Modes.Objects
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
NewCombo = combo
};
+
+ if (split.Length > 10)
+ readCustomSampleBanks(split[10], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Spinner) > 0)
{
@@ -91,10 +102,17 @@ namespace osu.Game.Modes.Objects
{
EndTime = Convert.ToDouble(split[5], CultureInfo.InvariantCulture)
};
+
+ if (split.Length > 6)
+ readCustomSampleBanks(split[6], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Hold) > 0)
{
// Note: Hold is generated by BMS converts
+
+ // Todo: Apparently end time is determined by samples??
+ // Shouldn't need implementation until mania
+
result = new LegacyHold
{
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
@@ -105,15 +123,82 @@ namespace osu.Game.Modes.Objects
throw new InvalidOperationException($@"Unknown hit object type {type}");
result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
- result.Sample = new HitSampleInfo
- {
- Type = (SampleType)int.Parse(split[4]),
- Set = SampleSet.Soft,
- };
- // TODO: "addition" field
+ var soundType = (LegacySoundType)int.Parse(split[4]);
+
+ result.Samples.Add(new SampleInfo
+ {
+ Bank = normalSampleBank,
+ Name = SampleInfo.HIT_NORMAL,
+ Volume = sampleVolume
+ });
+
+ if ((soundType & LegacySoundType.Finish) > 0)
+ {
+ result.Samples.Add(new SampleInfo
+ {
+ Bank = addSampleBank,
+ Name = SampleInfo.HIT_FINISH,
+ Volume = sampleVolume
+ });
+ }
+
+ if ((soundType & LegacySoundType.Whistle) > 0)
+ {
+ result.Samples.Add(new SampleInfo
+ {
+ Bank = addSampleBank,
+ Name = SampleInfo.HIT_WHISTLE,
+ Volume = sampleVolume
+ });
+ }
+
+ if ((soundType & LegacySoundType.Clap) > 0)
+ {
+ result.Samples.Add(new SampleInfo
+ {
+ Bank = addSampleBank,
+ Name = SampleInfo.HIT_CLAP,
+ Volume = sampleVolume
+ });
+ }
return result;
}
+
+ private void readCustomSampleBanks(string str, ref string normalSampleBank, ref string addSampleBank, ref int sampleVolume)
+ {
+ if (string.IsNullOrEmpty(str))
+ return;
+
+ string[] split = str.Split(':');
+
+ var bank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
+ var addbank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
+
+ // Let's not implement this for now, because this doesn't fit nicely into the bank structure
+ //string sampleFile = split2.Length > 4 ? split2[4] : string.Empty;
+
+ string stringBank = bank.ToString().ToLower();
+ if (stringBank == @"none")
+ stringBank = null;
+ string stringAddBank = addbank.ToString().ToLower();
+ if (stringAddBank == @"none")
+ stringAddBank = null;
+
+ normalSampleBank = stringBank;
+ addSampleBank = stringAddBank;
+ sampleVolume = split.Length > 3 ? int.Parse(split[3]) : 0;
+ }
+
+ [Flags]
+ private enum LegacySoundType
+ {
+ None = 0,
+ Normal = 1,
+ Whistle = 2,
+ Finish = 4,
+ Clap = 8
+ }
}
}
diff --git a/osu.Game/Modes/Replays/FramedReplayInputHandler.cs b/osu.Game/Modes/Replays/FramedReplayInputHandler.cs
index ae20ece515..0c1e140ce4 100644
--- a/osu.Game/Modes/Replays/FramedReplayInputHandler.cs
+++ b/osu.Game/Modes/Replays/FramedReplayInputHandler.cs
@@ -136,7 +136,7 @@ namespace osu.Game.Modes.Replays
public ReplayMouseState(Vector2 position, IEnumerable list)
{
Position = position;
- list.ForEach(b => PressedButtons.Add(b));
+ list.ForEach(b => SetPressed(b, true));
}
}
@@ -148,4 +148,4 @@ namespace osu.Game.Modes.Replays
}
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Modes/Scoring/Score.cs b/osu.Game/Modes/Scoring/Score.cs
index c998b11f77..b0c123f438 100644
--- a/osu.Game/Modes/Scoring/Score.cs
+++ b/osu.Game/Modes/Scoring/Score.cs
@@ -27,7 +27,24 @@ namespace osu.Game.Modes.Scoring
public int Combo { get; set; }
public Mod[] Mods { get; set; }
- public User User { get; set; }
+ private User user;
+
+ public User User
+ {
+ get
+ {
+ return user ?? new User
+ {
+ Username = LegacyUsername,
+ Id = LegacyUserID
+ };
+ }
+
+ set
+ {
+ user = value;
+ }
+ }
[JsonProperty(@"replay_data")]
public Replay Replay;
@@ -38,10 +55,10 @@ namespace osu.Game.Modes.Scoring
public long OnlineScoreID;
[JsonProperty(@"username")]
- public string Username;
+ public string LegacyUsername;
[JsonProperty(@"user_id")]
- public long UserID;
+ public long LegacyUserID;
[JsonProperty(@"date")]
public DateTime Date;
diff --git a/osu.Game/Modes/Scoring/ScoreProcessor.cs b/osu.Game/Modes/Scoring/ScoreProcessor.cs
index a64b4d4013..ba845b84dc 100644
--- a/osu.Game/Modes/Scoring/ScoreProcessor.cs
+++ b/osu.Game/Modes/Scoring/ScoreProcessor.cs
@@ -8,6 +8,7 @@ using osu.Game.Beatmaps;
using osu.Game.Modes.Judgements;
using osu.Game.Modes.Objects;
using osu.Game.Modes.UI;
+using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Scoring
{
@@ -145,10 +146,21 @@ namespace osu.Game.Modes.Scoring
if (!exists)
{
+ if (judgement.AffectsCombo)
+ {
+ switch (judgement.Result)
+ {
+ case HitResult.Miss:
+ Combo.Value = 0;
+ break;
+ case HitResult.Hit:
+ Combo.Value++;
+ break;
+ }
+ }
+
Judgements.Add(judgement);
OnNewJudgement(judgement);
-
- judgement.ComboAtHit = Combo.Value;
}
else
OnJudgementChanged(judgement);
diff --git a/osu.Game/Modes/UI/ComboCounter.cs b/osu.Game/Modes/UI/ComboCounter.cs
index 3629634889..8c0327fa04 100644
--- a/osu.Game/Modes/UI/ComboCounter.cs
+++ b/osu.Game/Modes/UI/ComboCounter.cs
@@ -66,12 +66,7 @@ namespace osu.Game.Modes.UI
TextSize = 80;
- Current.ValueChanged += comboChanged;
- }
-
- private void comboChanged(object sender, System.EventArgs e)
- {
- updateCount(Current.Value == 0);
+ Current.ValueChanged += newValue => updateCount(newValue == 0);
}
protected override void LoadComplete()
diff --git a/osu.Game/Modes/UI/HealthDisplay.cs b/osu.Game/Modes/UI/HealthDisplay.cs
index 3471f4bc3f..4c8d7e4ab8 100644
--- a/osu.Game/Modes/UI/HealthDisplay.cs
+++ b/osu.Game/Modes/UI/HealthDisplay.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Modes.UI
protected HealthDisplay()
{
- Current.ValueChanged += (s, e) => SetHealth((float)Current);
+ Current.ValueChanged += newValue => SetHealth((float)newValue);
}
protected abstract void SetHealth(float value);
diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs
index e36d2a101c..dd5eff5a95 100644
--- a/osu.Game/Modes/UI/HitRenderer.cs
+++ b/osu.Game/Modes/UI/HitRenderer.cs
@@ -16,6 +16,7 @@ using System.Diagnostics;
using System.Linq;
using osu.Game.Modes.Replays;
using osu.Game.Modes.Scoring;
+using OpenTK;
namespace osu.Game.Modes.UI
{
@@ -32,6 +33,11 @@ namespace osu.Game.Modes.UI
///
public event Action OnAllJudged;
+ ///
+ /// Whether to apply adjustments to the child based on our own size.
+ ///
+ public bool AspectAdjust = true;
+
///
/// The input manager for this HitRenderer.
///
@@ -42,6 +48,16 @@ namespace osu.Game.Modes.UI
///
protected readonly KeyConversionInputManager KeyConversionInputManager;
+ ///
+ /// Whether we are currently providing the local user a gameplay cursor.
+ ///
+ public virtual bool ProvidingUserCursor => false;
+
+ ///
+ /// Whether we have a replay loaded currently.
+ ///
+ public bool HasReplayLoaded => InputManager.ReplayInputHandler != null;
+
///
/// Whether all the HitObjects have been judged.
///
@@ -157,6 +173,8 @@ namespace osu.Game.Modes.UI
{
public event Action OnJudgement;
+ public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
+
protected override Container Content => content;
protected override bool AllObjectsJudged => Playfield.HitObjects.Children.All(h => h.Judgement.Result != HitResult.None);
@@ -207,6 +225,19 @@ namespace osu.Game.Modes.UI
Playfield.PostProcess();
}
+ protected override void Update()
+ {
+ base.Update();
+
+ Playfield.Size = AspectAdjust ? GetPlayfieldAspectAdjust() : Vector2.One;
+ }
+
+ ///
+ /// 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.
///
diff --git a/osu.Game/Modes/UI/HudOverlay.cs b/osu.Game/Modes/UI/HudOverlay.cs
index a6c54e7f3a..355b62bc57 100644
--- a/osu.Game/Modes/UI/HudOverlay.cs
+++ b/osu.Game/Modes/UI/HudOverlay.cs
@@ -8,13 +8,19 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play;
-using System;
using osu.Game.Modes.Scoring;
+using osu.Framework.Input;
+using OpenTK.Input;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
namespace osu.Game.Modes.UI
{
public abstract class HudOverlay : Container
{
+ private const int duration = 100;
+
+ private readonly Container content;
public readonly KeyCounterCollection KeyCounter;
public readonly ComboCounter ComboCounter;
public readonly ScoreCounter ScoreCounter;
@@ -22,6 +28,9 @@ namespace osu.Game.Modes.UI
public readonly HealthDisplay HealthDisplay;
private Bindable showKeyCounter;
+ private Bindable showHud;
+
+ private static bool hasShownNotificationOnce;
protected abstract KeyCounterCollection CreateKeyCounter();
protected abstract ComboCounter CreateComboCounter();
@@ -33,36 +42,57 @@ namespace osu.Game.Modes.UI
{
RelativeSizeAxes = Axes.Both;
- Children = new Drawable[]
+ Add(content = new Container
{
- KeyCounter = CreateKeyCounter(),
- ComboCounter = CreateComboCounter(),
- ScoreCounter = CreateScoreCounter(),
- AccuracyCounter = CreateAccuracyCounter(),
- HealthDisplay = CreateHealthDisplay(),
- };
+ RelativeSizeAxes = Axes.Both,
+
+ Children = new Drawable[]
+ {
+ KeyCounter = CreateKeyCounter(),
+ ComboCounter = CreateComboCounter(),
+ ScoreCounter = CreateScoreCounter(),
+ AccuracyCounter = CreateAccuracyCounter(),
+ HealthDisplay = CreateHealthDisplay(),
+ }
+ });
}
- [BackgroundDependencyLoader]
- private void load(OsuConfigManager config)
+ [BackgroundDependencyLoader(true)]
+ private void load(OsuConfigManager config, NotificationManager notificationManager)
{
showKeyCounter = config.GetBindable(OsuConfig.KeyOverlay);
- showKeyCounter.ValueChanged += visibilityChanged;
+ showKeyCounter.ValueChanged += keyCounterVisibility =>
+ {
+ if (keyCounterVisibility)
+ KeyCounter.FadeIn(duration);
+ else
+ KeyCounter.FadeOut(duration);
+ };
showKeyCounter.TriggerChange();
- }
- private void visibilityChanged(object sender, EventArgs e)
- {
- if (showKeyCounter)
- KeyCounter.Show();
- else
- KeyCounter.Hide();
+ showHud = config.GetBindable(OsuConfig.ShowInterface);
+ showHud.ValueChanged += hudVisibility =>
+ {
+ if (hudVisibility)
+ content.FadeIn(duration);
+ else
+ content.FadeOut(duration);
+ };
+ showHud.TriggerChange();
+
+ if (!showHud && !hasShownNotificationOnce)
+ {
+ hasShownNotificationOnce = true;
+
+ notificationManager?.Post(new SimpleNotification
+ {
+ Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
+ });
+ }
}
public void BindProcessor(ScoreProcessor processor)
{
- //bind processor bindables to combocounter, score display etc.
- //TODO: these should be bindable binds, not events!
ScoreCounter?.Current.BindTo(processor.TotalScore);
AccuracyCounter?.Current.BindTo(processor.Accuracy);
ComboCounter?.Current.BindTo(processor.Combo);
@@ -73,5 +103,22 @@ namespace osu.Game.Modes.UI
{
hitRenderer.InputManager.Add(KeyCounter.GetReceptor());
}
+
+ protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
+ {
+ if (args.Repeat) return false;
+
+ if (state.Keyboard.ShiftPressed)
+ {
+ switch (args.Key)
+ {
+ case Key.Tab:
+ showHud.Value = !showHud.Value;
+ return true;
+ }
+ }
+
+ return base.OnKeyDown(state, args);
+ }
}
}
diff --git a/osu.Game/Modes/UI/ModIcon.cs b/osu.Game/Modes/UI/ModIcon.cs
index 35459985c9..1e0aa89a41 100644
--- a/osu.Game/Modes/UI/ModIcon.cs
+++ b/osu.Game/Modes/UI/ModIcon.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Modes.UI
reapplySize();
}
}
-
+
public new Color4 Colour
{
get
@@ -38,7 +38,7 @@ namespace osu.Game.Modes.UI
background.Colour = value;
}
}
-
+
public FontAwesome Icon
{
get
diff --git a/osu.Game/Modes/UI/Playfield.cs b/osu.Game/Modes/UI/Playfield.cs
index eff06ce80f..1e7cf6579c 100644
--- a/osu.Game/Modes/UI/Playfield.cs
+++ b/osu.Game/Modes/UI/Playfield.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.Modes.Objects;
@@ -22,6 +23,11 @@ namespace osu.Game.Modes.UI
internal Container ScaledContent;
+ ///
+ /// Whether we are currently providing the local user a gameplay cursor.
+ ///
+ public virtual bool ProvidingUserCursor => false;
+
protected override Container Content => content;
private readonly Container content;
@@ -33,6 +39,9 @@ namespace osu.Game.Modes.UI
{
AlwaysReceiveInput = true;
+ // Default height since we force relative size axes
+ Size = Vector2.One;
+
AddInternal(ScaledContent = new ScaledContainer
{
CustomWidth = customWidth,
@@ -58,6 +67,12 @@ namespace osu.Game.Modes.UI
Add(HitObjects);
}
+ public override Axes RelativeSizeAxes
+ {
+ get { return Axes.Both; }
+ set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
+ }
+
///
/// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield.
///
diff --git a/osu.Game/Modes/UI/StandardHudOverlay.cs b/osu.Game/Modes/UI/StandardHudOverlay.cs
index f77191adf7..f07e421f00 100644
--- a/osu.Game/Modes/UI/StandardHudOverlay.cs
+++ b/osu.Game/Modes/UI/StandardHudOverlay.cs
@@ -40,6 +40,7 @@ namespace osu.Game.Modes.UI
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding(10),
+ Y = - TwoLayerButton.SIZE_RETRACTED.Y,
};
protected override ScoreCounter CreateScoreCounter() => new ScoreCounter(6)
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 8ac86c5c67..ccea6ef458 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -150,7 +150,7 @@ namespace osu.Game
}
});
- (screenStack = new Loader()).LoadAsync(this, d =>
+ LoadComponentAsync(screenStack = new Loader(), d =>
{
screenStack.ModePushed += screenAdded;
screenStack.Exited += screenRemoved;
@@ -158,27 +158,27 @@ namespace osu.Game
});
//overlay elements
- (chat = new ChatOverlay { Depth = 0 }).LoadAsync(this, overlayContent.Add);
- (options = new OptionsOverlay { Depth = -1 }).LoadAsync(this, overlayContent.Add);
- (musicController = new MusicController
+ LoadComponentAsync(chat = new ChatOverlay { Depth = 0 }, overlayContent.Add);
+ LoadComponentAsync(options = new OptionsOverlay { Depth = -1 }, overlayContent.Add);
+ LoadComponentAsync(musicController = new MusicController
{
Depth = -2,
Position = new Vector2(0, Toolbar.HEIGHT),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
- }).LoadAsync(this, overlayContent.Add);
+ }, overlayContent.Add);
- (notificationManager = new NotificationManager
+ LoadComponentAsync(notificationManager = new NotificationManager
{
Depth = -2,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
- }).LoadAsync(this, overlayContent.Add);
+ }, overlayContent.Add);
- (dialogOverlay = new DialogOverlay
+ LoadComponentAsync(dialogOverlay = new DialogOverlay
{
Depth = -4,
- }).LoadAsync(this, overlayContent.Add);
+ }, overlayContent.Add);
Logger.NewEntry += entry =>
{
@@ -195,12 +195,12 @@ namespace osu.Game
Dependencies.Cache(notificationManager);
Dependencies.Cache(dialogOverlay);
- (Toolbar = new Toolbar
+ LoadComponentAsync(Toolbar = new Toolbar
{
Depth = -3,
OnHome = delegate { intro?.ChildScreen?.MakeCurrent(); },
OnPlayModeChange = m => PlayMode.Value = m,
- }).LoadAsync(this, t =>
+ }, t =>
{
PlayMode.ValueChanged += delegate { Toolbar.SetGameMode(PlayMode.Value); };
PlayMode.TriggerChange();
@@ -307,6 +307,18 @@ namespace osu.Game
return base.OnExiting();
}
+ ///
+ /// Use to programatically exit the game as if the user was triggering via alt-f4.
+ /// Will keep persisting until an exit occurs (exit may be blocked multiple times).
+ ///
+ public void GracefullyExit()
+ {
+ if (!OnExiting())
+ Exit();
+ else
+ Scheduler.AddDelayed(GracefullyExit, 2000);
+ }
+
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
@@ -314,7 +326,7 @@ namespace osu.Game
if (intro?.ChildScreen != null)
intro.ChildScreen.Padding = new MarginPadding { Top = Toolbar.Position.Y + Toolbar.DrawHeight };
- Cursor.State = currentScreen == null || currentScreen.HasLocalCursorDisplayed ? Visibility.Hidden : Visibility.Visible;
+ Cursor.State = currentScreen?.HasLocalCursorDisplayed == false ? Visibility.Visible : Visibility.Hidden;
}
private void screenAdded(Screen newScreen)
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index f454956de7..f95e8c3ac6 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -92,7 +92,10 @@ namespace osu.Game
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Medium"));
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-MediumItalic"));
- Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto"));
+ Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-Basic"));
+ Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-Hangul"));
+ Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-CJK-Basic"));
+ Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-CJK-Compatibility"));
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Regular"));
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-RegularItalic"));
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index 0bb3d3dc71..fc12789b05 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Overlays
{
var postText = sender.Text;
- if (!string.IsNullOrEmpty(postText))
+ if (!string.IsNullOrEmpty(postText) && api.LocalUser.Value != null)
{
//todo: actually send to server
careChannels.FirstOrDefault()?.AddNewMessages(new[]
diff --git a/osu.Game/Overlays/Dialog/PopupDialogOKButton.cs b/osu.Game/Overlays/Dialog/PopupDialogOkButton.cs
similarity index 100%
rename from osu.Game/Overlays/Dialog/PopupDialogOKButton.cs
rename to osu.Game/Overlays/Dialog/PopupDialogOkButton.cs
diff --git a/osu.Game/Overlays/DragBar.cs b/osu.Game/Overlays/DragBar.cs
index a9cf735171..53a01c9e9c 100644
--- a/osu.Game/Overlays/DragBar.cs
+++ b/osu.Game/Overlays/DragBar.cs
@@ -5,7 +5,9 @@ using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Transforms;
using osu.Framework.Input;
+using OpenTK;
namespace osu.Game.Overlays
{
@@ -14,9 +16,10 @@ namespace osu.Game.Overlays
private readonly Box fill;
public Action SeekRequested;
- private bool isDragging;
- private bool enabled;
+ public bool IsSeeking { get; private set; }
+
+ private bool enabled = true;
public bool IsEnabled
{
get { return enabled; }
@@ -46,9 +49,9 @@ namespace osu.Game.Overlays
public void UpdatePosition(float position)
{
- if (isDragging || !IsEnabled) return;
+ if (IsSeeking || !IsEnabled) return;
- fill.Width = position;
+ updatePosition(position);
}
private void seek(InputState state)
@@ -56,7 +59,13 @@ namespace osu.Game.Overlays
if (!IsEnabled) return;
float seekLocation = state.Mouse.Position.X / DrawWidth;
SeekRequested?.Invoke(seekLocation);
- fill.Width = seekLocation;
+ updatePosition(seekLocation);
+ }
+
+ private void updatePosition(float position)
+ {
+ position = MathHelper.Clamp(position, 0, 1);
+ fill.TransformTo(() => fill.Width, position, 200, EasingTypes.OutQuint, new TransformSeek());
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
@@ -71,12 +80,21 @@ namespace osu.Game.Overlays
return true;
}
- protected override bool OnDragStart(InputState state) => isDragging = true;
+ protected override bool OnDragStart(InputState state) => IsSeeking = true;
protected override bool OnDragEnd(InputState state)
{
- isDragging = false;
+ IsSeeking = false;
return true;
}
+
+ private class TransformSeek : TransformFloat
+ {
+ public override void Apply(Drawable d)
+ {
+ base.Apply(d);
+ d.Width = CurrentValue;
+ }
+ }
}
}
diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
index 0272438927..2b9f8e86a9 100644
--- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
@@ -39,9 +39,9 @@ namespace osu.Game.Overlays.Mods
public readonly Bindable PlayMode = new Bindable();
- private void modeChanged(object sender, EventArgs eventArgs)
+ private void modeChanged(PlayMode newMode)
{
- var ruleset = Ruleset.GetRuleset(PlayMode);
+ var ruleset = Ruleset.GetRuleset(newMode);
foreach (ModSection section in modSectionsContainer.Children)
section.Buttons = ruleset.GetModsFor(section.ModType).Select(m => new ModButton(m)).ToArray();
refreshSelectedMods();
@@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Mods
if (osu != null)
PlayMode.BindTo(osu.PlayMode);
PlayMode.ValueChanged += modeChanged;
- modeChanged(null, null);
+ PlayMode.TriggerChange();
}
protected override void PopOut()
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 2f8f0ab650..9d21a0341c 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Overlays
{
private Drawable currentBackground;
private DragBar progress;
- private TextAwesome playButton;
+ private Button playButton;
private SpriteText title, artist;
private List playList;
@@ -46,6 +46,10 @@ namespace osu.Game.Overlays
private Container dragContainer;
+ private const float progress_height = 10;
+
+ private const float bottom_black_area_height = 55;
+
public MusicController()
{
Width = 400;
@@ -78,8 +82,6 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader]
private void load(OsuGameBase game, OsuConfigManager config, BeatmapDatabase beatmaps, OsuColour colours)
{
- unicodeString = config.GetUnicodeString;
-
Children = new Drawable[]
{
dragContainer = new Container
@@ -117,89 +119,64 @@ namespace osu.Game.Overlays
Text = @"Nothing to play",
Font = @"Exo2.0-BoldItalic"
},
- new ClickableContainer
+ new Container
{
- AutoSizeAxes = Axes.Both,
- Origin = Anchor.Centre,
+ Padding = new MarginPadding { Bottom = progress_height },
+ Height = bottom_black_area_height,
+ RelativeSizeAxes = Axes.X,
+ Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
- Position = new Vector2(0, -30),
- Action = () =>
- {
- if (current?.Track == null) return;
- if (current.Track.IsRunning)
- current.Track.Stop();
- else
- current.Track.Start();
- },
Children = new Drawable[]
{
- playButton = new TextAwesome
+ new FillFlowContainer