diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-stage-left.png b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-stage-left.png
new file mode 100644
index 0000000000..03ca371c4e
Binary files /dev/null and b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-stage-left.png differ
diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-stage-right.png b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-stage-right.png
new file mode 100644
index 0000000000..45b7be0255
Binary files /dev/null and b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-stage-right.png differ
diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs
index 7680526ac4..f177284399 100644
--- a/osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs
+++ b/osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs
@@ -52,10 +52,10 @@ namespace osu.Game.Rulesets.Mania.Skinning
base.Update();
if (leftSprite?.Height > 0)
- leftSprite.Scale = new Vector2(DrawHeight / leftSprite.Height);
+ leftSprite.Scale = new Vector2(1, DrawHeight / leftSprite.Height);
if (rightSprite?.Height > 0)
- rightSprite.Scale = new Vector2(DrawHeight / rightSprite.Height);
+ rightSprite.Scale = new Vector2(1, DrawHeight / rightSprite.Height);
}
}
}
diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
index 8b9f531417..c25fb03fd0 100644
--- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs
+++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
@@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Edit
/// The ruleset used to construct its drawable counterpart.
/// The loaded beatmap.
/// The mods to be applied.
- /// An editor-relevant .
+ /// An editor-relevant .
protected virtual DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null)
=> (DrawableRuleset)ruleset.CreateDrawableRulesetWith(beatmap, mods);
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
index cd2f9f88b8..c522dc623c 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
@@ -9,7 +9,10 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Objects.Legacy
{
- internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset
+ internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset,
+#pragma warning disable 618
+ IHasCurve
+#pragma warning restore 618
{
///
/// Scoring distance with a speed-adjusted beat length of 1 second.
diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs
new file mode 100644
index 0000000000..26f50ffa31
--- /dev/null
+++ b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osuTK;
+
+namespace osu.Game.Rulesets.Objects.Types
+{
+ [Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
+ public interface IHasCurve : IHasDistance, IHasRepeats
+ {
+ ///
+ /// The curve.
+ ///
+ SliderPath Path { get; }
+ }
+
+#pragma warning disable 618
+ [Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
+ public static class HasCurveExtensions
+ {
+ ///
+ /// Computes the position on the curve relative to how much of the has been completed.
+ ///
+ /// The curve.
+ /// [0, 1] where 0 is the start time of the and 1 is the end time of the .
+ /// The position on the curve.
+ public static Vector2 CurvePositionAt(this IHasCurve obj, double progress)
+ => obj.Path.PositionAt(obj.ProgressAt(progress));
+
+ ///
+ /// Computes the progress along the curve relative to how much of the has been completed.
+ ///
+ /// The curve.
+ /// [0, 1] where 0 is the start time of the and 1 is the end time of the .
+ /// [0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.
+ public static double ProgressAt(this IHasCurve obj, double progress)
+ {
+ double p = progress * obj.SpanCount() % 1;
+ if (obj.SpanAt(progress) % 2 == 1)
+ p = 1 - p;
+ return p;
+ }
+
+ ///
+ /// Determines which span of the curve the progress point is on.
+ ///
+ /// The curve.
+ /// [0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.
+ /// [0, SpanCount) where 0 is the first run.
+ public static int SpanAt(this IHasCurve obj, double progress)
+ => (int)(progress * obj.SpanCount());
+ }
+#pragma warning restore 618
+}
diff --git a/osu.Game/Rulesets/Objects/Types/IHasPathWithRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasPathWithRepeats.cs
index fba0fd7aff..279946b44e 100644
--- a/osu.Game/Rulesets/Objects/Types/IHasPathWithRepeats.cs
+++ b/osu.Game/Rulesets/Objects/Types/IHasPathWithRepeats.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using osuTK;
namespace osu.Game.Rulesets.Objects.Types
@@ -9,15 +8,11 @@ namespace osu.Game.Rulesets.Objects.Types
///
/// A HitObject that has a curve.
///
+ // ReSharper disable once RedundantExtendsListEntry
public interface IHasPathWithRepeats : IHasPath, IHasRepeats
{
}
- [Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
- public interface IHasCurve : IHasPathWithRepeats
- {
- }
-
public static class HasPathWithRepeatsExtensions
{
///