diff --git a/.grenrc b/.grenrc
index 38ca32277..ded610533 100644
--- a/.grenrc
+++ b/.grenrc
@@ -10,7 +10,7 @@
"wontfix"
],
"template": {
- "issue": "- {{name}} | [{{text}}]({{url}}) by [{{user_login}}]({{user_url}})",
+ "issue": "- {{name}} | [{{text}}]({{url}})",
"group": "\n### {{heading}}\n",
"changelogTitle": ""
},
diff --git a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneBreakNote.cs b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneBreakNote.cs
index f0e5902b2..4ab1f740b 100644
--- a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneBreakNote.cs
+++ b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneBreakNote.cs
@@ -35,9 +35,6 @@ private void testSingle(bool auto = false)
{
IsBreak = true,
StartTime = Time.Current + 1000,
- Position = new Vector2(0, -66f),
- Angle = 0,
- EndPosition = new Vector2(0, -296.5f),
};
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { });
diff --git a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneHoldNote.cs b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneHoldNote.cs
index 7fb6d3d4f..5454241c7 100644
--- a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneHoldNote.cs
+++ b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneHoldNote.cs
@@ -45,9 +45,6 @@ private void testSingle(double duration, bool auto = false)
{
StartTime = Time.Current + 1000,
EndTime = Time.Current + 1000 + duration,
- Position = new Vector2(0, -66),
- EndPosition = new Vector2(0, -296.5f),
- Angle = 0f,
};
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { });
diff --git a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTapNote.cs b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTapNote.cs
index ba72248d9..442219038 100644
--- a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTapNote.cs
+++ b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTapNote.cs
@@ -34,9 +34,6 @@ private void testSingle(bool auto = false)
var circle = new Tap
{
StartTime = Time.Current + 1000,
- Position = new Vector2(0, -66f),
- Angle = 0,
- EndPosition = new Vector2(0, -296.5f),
};
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { });
diff --git a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTouchHold.cs b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTouchHold.cs
index 5f9f54fd3..4b606e088 100644
--- a/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTouchHold.cs
+++ b/osu.Game.Rulesets.Sentakki.Tests/Objects/TestSceneTouchHold.cs
@@ -34,7 +34,6 @@ private void testSingle(bool auto = false)
{
StartTime = Time.Current + 1000,
Duration = 5000,
- Position = new Vector2(0, 0)
};
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { });
diff --git a/osu.Game.Rulesets.Sentakki.Tests/Statistics/TestSceneJudgementChart.cs b/osu.Game.Rulesets.Sentakki.Tests/Statistics/TestSceneJudgementChart.cs
new file mode 100644
index 000000000..72f1afb05
--- /dev/null
+++ b/osu.Game.Rulesets.Sentakki.Tests/Statistics/TestSceneJudgementChart.cs
@@ -0,0 +1,61 @@
+using NUnit.Framework;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Sentakki.Statistics;
+using osu.Game.Rulesets.Sentakki.Objects;
+using osu.Game.Tests.Visual;
+using System.Collections.Generic;
+
+namespace osu.Game.Rulesets.Sentakki.Tests.Statistics
+{
+ [TestFixture]
+ public class TestSceneJudgementChart : OsuTestScene
+ {
+ private List testevents = new List
+ {
+ // Tap
+ new HitEvent(0,HitResult.Perfect,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Miss,new Tap(),new Tap(), null),
+ new HitEvent(0,HitResult.Miss,new Tap(),new Tap(), null),
+ // Holds
+ new HitEvent(0,HitResult.Perfect,new Hold.HoldHead(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Hold.HoldTail(),new Tap(), null),
+ // Touch
+ new HitEvent(0,HitResult.Good,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Miss,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Miss,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Touch(),new Tap(), null),
+ new HitEvent(0,HitResult.Perfect,new Touch(),new Tap(), null),
+ // Breaks
+ new HitEvent(0,HitResult.Perfect,new Tap(){IsBreak = true},new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(){IsBreak = true},new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(){IsBreak = true},new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(){IsBreak = true},new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(){IsBreak = true},new Tap(), null),
+ new HitEvent(0,HitResult.Good,new Tap(){IsBreak = true},new Tap(), null),
+ new HitEvent(0,HitResult.Meh,new Tap(){IsBreak = true},new Tap(), null),
+ };
+ public TestSceneJudgementChart()
+ {
+ Add(new JudgementChart(testevents));
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Sentakki.Tests/UI/TestSceneResumeOverlay.cs b/osu.Game.Rulesets.Sentakki.Tests/UI/TestSceneResumeOverlay.cs
new file mode 100644
index 000000000..dcde3c5a4
--- /dev/null
+++ b/osu.Game.Rulesets.Sentakki.Tests/UI/TestSceneResumeOverlay.cs
@@ -0,0 +1,31 @@
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
+using osu.Game.Rulesets.Sentakki.UI;
+using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Sentakki.Tests.UI
+{
+ public class TestSceneResumeOverlay : OsuTestScene
+ {
+ public TestSceneResumeOverlay()
+ {
+ CursorContainer cursor;
+ ResumeOverlay resume;
+
+ Children = new Drawable[]
+ {
+ cursor = new CursorContainer(),
+ resume = new SentakkiResumeOverlay
+ {
+ GameplayCursor = cursor
+ }
+ };
+
+ AddStep("Show ResumeOverlay", () => resume.Show());
+ AddAssert("Is overlay shown?", () => resume.State.Value == Visibility.Visible);
+ AddUntilStep("Wait for countdown to end", () => resume.State.Value == Visibility.Hidden);
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiBeatmapConverter.cs b/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiBeatmapConverter.cs
index a65fd5052..cfe1f50b1 100644
--- a/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiBeatmapConverter.cs
@@ -49,7 +49,7 @@ protected override IEnumerable ConvertHitObject(HitObject ori
Vector2 newPos = (original as IHasPosition)?.Position ?? Vector2.Zero;
newPos.Y = 384 - newPos.Y;
- int path = newPos.GetDegreesFromPosition(CENTRE_POINT).GetNotePathFromDegrees();
+ int lane = newPos.GetDegreesFromPosition(CENTRE_POINT).GetNoteLaneFromDegrees();
List objects = new List();
if (EnabledExperiments.Value.HasFlag(ConversionExperiments.patternv2))
@@ -65,7 +65,7 @@ protected override IEnumerable ConvertHitObject(HitObject ori
switch (original)
{
case IHasPathWithRepeats _:
- objects.AddRange(Conversions.CreateHoldNote(original, path, beatmap, random, EnabledExperiments.Value));
+ objects.AddRange(Conversions.CreateHoldNote(original, lane, beatmap, random, EnabledExperiments.Value));
break;
case IHasDuration _:
@@ -74,9 +74,9 @@ protected override IEnumerable ConvertHitObject(HitObject ori
default:
if (EnabledExperiments.Value.HasFlag(ConversionExperiments.touch) && (random2.Next() % 10 == 0))
- objects.AddRange(Conversions.CreateTouchNote(original, path, random, EnabledExperiments.Value));
+ objects.AddRange(Conversions.CreateTouchNote(original, lane, random, EnabledExperiments.Value));
else
- objects.AddRange(Conversions.CreateTapNote(original, path, random, EnabledExperiments.Value));
+ objects.AddRange(Conversions.CreateTapNote(original, lane, random, EnabledExperiments.Value));
break;
}
diff --git a/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiNoteConversions.cs b/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiNoteConversions.cs
index 205ed3ba3..5d381da03 100644
--- a/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiNoteConversions.cs
+++ b/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiNoteConversions.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Sentakki.Beatmaps
{
public static class Conversions
{
- public static List CreateTapNote(HitObject original, int path, Random rng, ConversionExperiments experimental = ConversionExperiments.none)
+ public static List CreateTapNote(HitObject original, int lane, Random rng, ConversionExperiments experimental = ConversionExperiments.none)
{
List notes = new List();
bool strong = original.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
@@ -26,24 +26,20 @@ public static List CreateTapNote(HitObject original, int path
notes.Add(new Tap
{
IsBreak = strong,
- Angle = path.GetAngleFromPath(),
+ Lane = lane,
Samples = original.Samples,
- StartTime = original.StartTime,
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, path),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, path),
+ StartTime = original.StartTime
});
if (twin && experimental.HasFlag(ConversionExperiments.twins))
{
- int newPath = path;
- while (path == newPath) newPath = rng.Next(0, 8);
+ int newPath = lane;
+ while (lane == newPath) newPath = rng.Next(0, 8);
notes.Add(new Tap
{
IsBreak = strong,
- Angle = newPath.GetAngleFromPath(),
+ Lane = newPath,
Samples = original.Samples,
- StartTime = original.StartTime,
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, newPath),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, newPath),
+ StartTime = original.StartTime
});
foreach (var note in notes)
note.HasTwin = true;
@@ -52,7 +48,7 @@ public static List CreateTapNote(HitObject original, int path
return notes;
}
- public static List CreateTouchNote(HitObject original, int path, Random rng, ConversionExperiments experimental = ConversionExperiments.none)
+ public static List CreateTouchNote(HitObject original, int lane, Random rng, ConversionExperiments experimental = ConversionExperiments.none)
{
Vector2 newPos = (original as IHasPosition)?.Position ?? Vector2.Zero;
newPos.Y = 384 - newPos.Y - 192;
@@ -62,7 +58,7 @@ public static List CreateTouchNote(HitObject original, int pa
{
Samples = original.Samples,
StartTime = original.StartTime,
- Position = newPos,
+ Position = newPos
}};
return notes;
@@ -71,13 +67,12 @@ public static List CreateTouchNote(HitObject original, int pa
public static SentakkiHitObject CreateTouchHold(HitObject original)
=> new TouchHold
{
- Position = Vector2.Zero,
StartTime = original.StartTime,
EndTime = (original as IHasDuration).EndTime,
Samples = original.Samples,
};
- public static List CreateHoldNote(HitObject original, int path, IBeatmap beatmap, Random rng, ConversionExperiments experimental = ConversionExperiments.none)
+ public static List CreateHoldNote(HitObject original, int lane, IBeatmap beatmap, Random rng, ConversionExperiments experimental = ConversionExperiments.none)
{
var curveData = original as IHasPathWithRepeats;
@@ -88,36 +83,32 @@ public static List CreateHoldNote(HitObject original, int pat
notes.Add(new Hold
{
IsBreak = strong,
- Angle = path.GetAngleFromPath(),
+ Lane = lane,
NodeSamples = curveData.NodeSamples,
StartTime = original.StartTime,
- EndTime = original.GetEndTime(),
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, path),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, path),
+ EndTime = original.GetEndTime()
});
if (experimental.HasFlag(ConversionExperiments.twins))
{
if (twin)
{
- int newPath = path;
- while (path == newPath) newPath = rng.Next(0, 8);
+ int newLane = lane;
+ while (lane == newLane) newLane = rng.Next(0, 8);
notes.Add(new Hold
{
IsBreak = strong,
- Angle = newPath.GetAngleFromPath(),
+ Lane = newLane,
NodeSamples = curveData.NodeSamples,
StartTime = original.StartTime,
EndTime = original.GetEndTime(),
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, newPath),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, newPath),
});
foreach (var note in notes)
note.HasTwin = true;
}
else
{
- var taps = CreateTapFromTicks(original, path, beatmap, rng);
+ var taps = CreateTapFromTicks(original, lane, beatmap, rng);
if (taps.Any())
notes.AddRange(taps);
}
@@ -126,7 +117,7 @@ public static List CreateHoldNote(HitObject original, int pat
return notes;
}
- public static List CreateTapFromTicks(HitObject original, int path, IBeatmap beatmap, Random rng)
+ public static List CreateTapFromTicks(HitObject original, int lane, IBeatmap beatmap, Random rng)
{
var curve = original as IHasPathWithRepeats;
double spanDuration = curve.Duration / (curve.RepeatCount + 1);
@@ -151,8 +142,8 @@ public static List CreateTapFromTicks(HitObject original, int
foreach (var e in SliderEventGenerator.Generate(original.StartTime, spanDuration, velocity, tickDistance, curve.Path.Distance, curve.RepeatCount + 1, legacyLastTickOffset, CancellationToken.None))
{
- int newPath = path;
- while (newPath == path) newPath = rng.Next(0, 8);
+ int newLane = lane;
+ while (newLane == lane) newLane = rng.Next(0, 8);
switch (e.Type)
{
@@ -160,11 +151,9 @@ public static List CreateTapFromTicks(HitObject original, int
case SliderEventType.Repeat:
hitObjects.Add(new Tap
{
- Angle = newPath.GetAngleFromPath(),
+ Lane = newLane,
Samples = getTickSamples(original.Samples),
StartTime = e.Time,
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, newPath),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, newPath),
});
break;
}
diff --git a/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiPatternGenerator.cs b/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiPatternGenerator.cs
index cd84b95da..1e69fa48e 100644
--- a/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiPatternGenerator.cs
+++ b/osu.Game.Rulesets.Sentakki/Beatmaps/SentakkiPatternGenerator.cs
@@ -30,17 +30,17 @@ public SentakkiPatternGenerator(IBeatmap beatmap)
rng = new Random(seed);
}
- //The patterns will generate the note path to be used based on the current offset
+ //The patterns will generate the note lane to be used based on the current offset
// argument list is (offset, diff)
private List> patternlist => new List>{
- //Stream pattern, path difference determined by offset2
+ //Stream pattern, lane difference determined by offset2
(twin)=> {
if(twin) return offset + 4;
else offset+=offset2;
return offset;
},
// Back and forth, works better with longer combos
- // Path difference determined by offset2, but will make sure offset2 is never 0.
+ // Lane difference determined by offset2, but will make sure offset2 is never 0.
(twin)=>{
offset2 = offset2 == 0 ? 1 : offset2;
offset+=offset2;
@@ -53,7 +53,7 @@ public SentakkiPatternGenerator(IBeatmap beatmap)
private int offset = 0;
private int offset2 = 0;
- private int getNewPath(bool twin = false) => patternlist[currentPattern].Invoke(twin);
+ private int getNewLane(bool twin = false) => patternlist[currentPattern].Invoke(twin);
public void CreateNewPattern()
{
@@ -120,21 +120,19 @@ public IEnumerable GenerateNewNote(HitObject original)
// Individual note generation code, because it's cleaner
private SentakkiHitObject createHoldNote(HitObject original, bool twin = false, bool isBreak = false)
{
- int notePath = getNewPath(twin);
+ int noteLane = getNewLane(twin);
return new Hold
{
IsBreak = isBreak,
- Angle = notePath.GetAngleFromPath(),
+ Lane = noteLane,
NodeSamples = (original as IHasPathWithRepeats).NodeSamples,
StartTime = original.StartTime,
- EndTime = original.GetEndTime(),
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, notePath),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, notePath),
+ EndTime = original.GetEndTime()
};
}
private IEnumerable createTapsFromTicks(HitObject original)
{
- int notePath = getNewPath(true);
+ int noteLane = getNewLane(true);
var curve = original as IHasPathWithRepeats;
double spanDuration = curve.Duration / (curve.RepeatCount + 1);
@@ -164,16 +162,14 @@ private IEnumerable createTapsFromTicks(HitObject original)
case SliderEventType.Repeat:
yield return new Tap
{
- Angle = notePath.GetAngleFromPath(),
+ Lane = noteLane,
Samples = original.Samples.Select(s => new HitSampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList(),
- StartTime = e.Time,
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, notePath),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, notePath),
+ StartTime = e.Time
};
break;
}
@@ -182,15 +178,13 @@ private IEnumerable createTapsFromTicks(HitObject original)
private SentakkiHitObject createTapNote(HitObject original, bool twin = false, bool isBreak = false)
{
- int notePath = getNewPath(twin);
+ int noteLane = getNewLane(twin);
return new Tap
{
IsBreak = isBreak,
- Angle = notePath.GetAngleFromPath(),
+ Lane = noteLane,
Samples = original.Samples,
StartTime = original.StartTime,
- EndPosition = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.INTERSECTDISTANCE, notePath),
- Position = SentakkiExtensions.GetPathPosition(SentakkiPlayfield.NOTESTARTDISTANCE, notePath),
};
}
diff --git a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/BlueprintPiece.cs
index f594c4b6e..ff2a64514 100644
--- a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/BlueprintPiece.cs
+++ b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/BlueprintPiece.cs
@@ -1,6 +1,7 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Sentakki.Objects;
+using osu.Game.Rulesets.Sentakki.UI;
namespace osu.Game.Rulesets.Sentakki.Edit.Blueprints
{
@@ -22,7 +23,7 @@ public BlueprintPiece()
/// The to reference properties from.
public virtual void UpdateFrom(T hitObject)
{
- Position = hitObject.EndPosition;
+ Position = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, hitObject.Lane.GetRotationForLane());
}
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/Components/HoldSelection.cs b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/Components/HoldSelection.cs
index feec6d751..1fef51ce0 100644
--- a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/Components/HoldSelection.cs
+++ b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/Components/HoldSelection.cs
@@ -6,6 +6,7 @@
using osu.Game.Graphics;
using osu.Game.Rulesets.Sentakki.Objects;
using osu.Game.Rulesets.Sentakki.Objects.Drawables;
+using osu.Game.Rulesets.Sentakki.UI;
using osuTK;
using osuTK.Graphics;
@@ -85,8 +86,8 @@ private void load(OsuColour colours)
public override void UpdateFrom(Hold hitObject)
{
//base.UpdateFrom(hitObject);
- Rotation = hitObject.Angle;
- notebody.Position = hitObject.EndPosition;
+ Rotation = hitObject.Lane.GetRotationForLane();
+ notebody.Position = new Vector2(0, -SentakkiPlayfield.INTERSECTDISTANCE + 40);
}
public void UpdateFrom(DrawableHold drawableHold)
diff --git a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/HoldPlacementBlueprint.cs b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/HoldPlacementBlueprint.cs
index 40888efb1..b64c53d60 100644
--- a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/HoldPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Holds/HoldPlacementBlueprint.cs
@@ -65,11 +65,7 @@ public override void UpdatePosition(SnapResult result)
newPos.Y = 600 - newPos.Y;
newPos -= new Vector2(300);
- var path = newPos.GetDegreesFromPosition(Vector2.Zero).GetNotePathFromDegrees();
- var angle = path.GetAngleFromPath();
-
- HitObject.Angle = angle;
- HitObject.EndPosition = new Vector2(0, -SentakkiPlayfield.INTERSECTDISTANCE + 40);
+ HitObject.Lane = newPos.GetDegreesFromPosition(Vector2.Zero).GetNoteLaneFromDegrees();
}
else
{
diff --git a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/Components/TapPiece.cs b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/Components/TapPiece.cs
index 3d44f606f..f04baeeff 100644
--- a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/Components/TapPiece.cs
+++ b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/Components/TapPiece.cs
@@ -59,7 +59,7 @@ public override void UpdateFrom(Tap hitObject)
public void UpdateFrom(DrawableTap drawableTap)
{
- Position = drawableTap.CirclePiece.Position;
+ Position = SentakkiExtensions.GetCircularPosition(-drawableTap.CirclePiece.Position.Y, drawableTap.HitObject.Lane.GetRotationForLane());
}
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/TapPlacementBlueprint.cs b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/TapPlacementBlueprint.cs
index f1be4901c..62db8c4a4 100644
--- a/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/TapPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Sentakki/Edit/Blueprints/Taps/TapPlacementBlueprint.cs
@@ -52,13 +52,7 @@ public override void UpdatePosition(SnapResult result)
newPos.Y = 600 - newPos.Y;
newPos -= new Vector2(300);
- var path = newPos.GetDegreesFromPosition(Vector2.Zero).GetNotePathFromDegrees();
- var angle = path.GetAngleFromPath();
-
- HitObject.Angle = angle;
-
- HitObject.Position = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.NOTESTARTDISTANCE, angle);
- HitObject.EndPosition = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, angle);
+ HitObject.Lane = newPos.GetDegreesFromPosition(Vector2.Zero).GetNoteLaneFromDegrees(); ;
}
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Edit/SentakkiSelectionHandler.cs b/osu.Game.Rulesets.Sentakki/Edit/SentakkiSelectionHandler.cs
index acd7dff64..024b474a0 100644
--- a/osu.Game.Rulesets.Sentakki/Edit/SentakkiSelectionHandler.cs
+++ b/osu.Game.Rulesets.Sentakki/Edit/SentakkiSelectionHandler.cs
@@ -37,20 +37,9 @@ public override bool HandleMovement(MoveSelectionEvent moveEvent)
break;
}
case Tap _:
- {
- var path = newPos.GetDegreesFromPosition(Vector2.Zero).GetNotePathFromDegrees();
- var angle = path.GetAngleFromPath();
- h.Position = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.NOTESTARTDISTANCE, angle);
- h.EndPosition = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, angle);
- h.Angle = angle;
- break;
- }
case Hold _:
{
- var path = newPos.GetDegreesFromPosition(Vector2.Zero).GetNotePathFromDegrees();
- var angle = path.GetAngleFromPath();
- h.EndPosition = new Vector2(0, -SentakkiPlayfield.INTERSECTDISTANCE + 40);
- h.Angle = angle;
+ h.Lane = newPos.GetDegreesFromPosition(Vector2.Zero).GetNoteLaneFromDegrees();
break;
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
index 23f52ad88..629ffe0b2 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
@@ -81,10 +81,14 @@ public DrawableHold(Hold hitObject)
isHitting.Value = false;
NoteBody.Glow.FadeOut(100);
},
- NoteAngle = HitObject.Angle
}
});
- HitObject.BindableAngle.BindValueChanged(angle => Rotation = angle.NewValue, true);
+
+ hitObject.LaneBindable.BindValueChanged(r =>
+ {
+ Rotation = r.NewValue.GetRotationForLane();
+ HitArea.NotePath = r.NewValue;
+ }, true);
}
protected override void AddNestedHitObject(DrawableHitObject hitObject)
@@ -114,7 +118,7 @@ protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
{
switch (hitObject)
{
- case HoldTail _:
+ case Hold.HoldTail _:
return new DrawableHoldTail(this)
{
Anchor = Anchor.TopCentre,
@@ -122,7 +126,7 @@ protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
AccentColour = { BindTarget = AccentColour }
};
- case Tap _:
+ case Hold.HoldHead _:
return new DrawableHoldHead(this)
{
Anchor = Anchor.TopCentre,
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableSentakkiHitObject.cs b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableSentakkiHitObject.cs
index d0a641c99..d7d2abd75 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableSentakkiHitObject.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableSentakkiHitObject.cs
@@ -31,7 +31,7 @@ public class DrawableSentakkiHitObject : DrawableHitObject
// Used for the animation update
protected readonly Bindable AnimationDuration = new Bindable(1000);
- protected override float SamplePlaybackPosition => (HitObject.EndPosition.X + SentakkiPlayfield.INTERSECTDISTANCE) / (SentakkiPlayfield.INTERSECTDISTANCE * 2);
+ protected override float SamplePlaybackPosition => (SentakkiExtensions.GetPositionAlongLane(SentakkiPlayfield.INTERSECTDISTANCE, HitObject.Lane).X / (SentakkiPlayfield.INTERSECTDISTANCE * 2)) + .5f;
public SentakkiAction[] HitActions { get; set; } = new[]
{
SentakkiAction.Button1,
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTap.cs b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTap.cs
index 3820822c5..980bb2299 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTap.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTap.cs
@@ -5,6 +5,8 @@
using osu.Game.Rulesets.Sentakki.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Sentakki.UI;
+using osu.Framework.Utils;
using osuTK;
using osuTK.Graphics;
using System;
@@ -32,7 +34,7 @@ public DrawableTap(SentakkiHitObject hitObject)
CirclePiece = new TapCircle()
{
Scale = new Vector2(0f),
- Position = HitObject.Position
+ Position = new Vector2(0, -SentakkiPlayfield.NOTESTARTDISTANCE)
},
HitArea = new HitReceptor()
{
@@ -44,15 +46,13 @@ public DrawableTap(SentakkiHitObject hitObject)
UpdateResult(true);
return true;
},
- Position = hitObject.EndPosition,
+ Position = new Vector2(0, -SentakkiPlayfield.INTERSECTDISTANCE),
},
});
-
- HitObject.BindableAngle.BindValueChanged(angle =>
+ hitObject.LaneBindable.BindValueChanged(r =>
{
- HitObjectLine.Rotation = angle.NewValue;
- HitArea.NoteAngle = angle.NewValue;
- HitArea.Position = hitObject.EndPosition;
+ Rotation = r.NewValue.GetRotationForLane();
+ HitArea.NotePath = r.NewValue;
}, true);
}
@@ -81,7 +81,7 @@ protected override void Update()
// Calculate position
float moveAmount = Math.Clamp((float)((currentProg - animTime) / animTime), 0, 1);
- CirclePiece.Position = HitObject.Position + ((HitObject.EndPosition - HitObject.Position) * moveAmount);
+ CirclePiece.Y = (float)Interpolation.Lerp(-SentakkiPlayfield.NOTESTARTDISTANCE, -SentakkiPlayfield.INTERSECTDISTANCE, moveAmount);
// Handle hidden and fadeIn modifications
if (IsHidden)
@@ -137,12 +137,10 @@ protected override void UpdateStateTransforms(ArmedState state)
break;
case ArmedState.Miss:
- var c = HitObject.Angle + 90;
- var d = c * (float)(Math.PI / 180);
CirclePiece.ScaleTo(0.5f, time_fade_miss, Easing.InCubic)
.FadeColour(Color4.Red, time_fade_miss, Easing.OutQuint)
- .MoveToOffset(new Vector2(-(100 * (float)Math.Cos(d)), -(100 * (float)Math.Sin(d))), time_fade_hit, Easing.OutCubic)
+ .MoveToOffset(new Vector2(0, -100), time_fade_hit, Easing.OutCubic)
.FadeOut(time_fade_miss);
this.ScaleTo(1f, time_fade_miss).Expire();
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTouch.cs b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTouch.cs
index aca8adc14..4870d91f9 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTouch.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableTouch.cs
@@ -23,7 +23,7 @@ public class DrawableTouch : DrawableSentakkiHitObject, IDrawableHitObjectWithPr
public Drawable ProxiedLayer => this;
- protected override float SamplePlaybackPosition => (HitObject.Position.X + SentakkiPlayfield.INTERSECTDISTANCE) / (SentakkiPlayfield.INTERSECTDISTANCE * 2);
+ protected override float SamplePlaybackPosition => ((HitObject as Touch).Position.X / (SentakkiPlayfield.INTERSECTDISTANCE * 2)) + .5f;
protected override double InitialLifetimeOffset => 6000;
@@ -42,7 +42,7 @@ public class DrawableTouch : DrawableSentakkiHitObject, IDrawableHitObjectWithPr
private SentakkiInputManager sentakkiActionInputManager;
internal SentakkiInputManager SentakkiActionInputManager => sentakkiActionInputManager ??= GetContainingInputManager() as SentakkiInputManager;
- public DrawableTouch(SentakkiHitObject hitObject) : base(hitObject)
+ public DrawableTouch(Touch hitObject) : base(hitObject)
{
Size = new Vector2(80);
Position = hitObject.Position;
@@ -102,7 +102,7 @@ private void load(SentakkiRulesetConfigManager sentakkiConfigs)
}
// Easing functions for manual use.
- private readonly DefaultEasingFunction inOutBack = new DefaultEasingFunction(Easing.InOutBack);
+ private readonly DefaultEasingFunction outSine = new DefaultEasingFunction(Easing.OutSine);
private readonly DefaultEasingFunction inQuint = new DefaultEasingFunction(Easing.InQuint);
protected override void Update()
@@ -112,21 +112,21 @@ protected override void Update()
if (Result.HasResult) return;
double fadeIn = AnimationDuration.Value * GameplaySpeed;
- double moveTo = 500 * GameplaySpeed;
+ double moveTo = HitObject.HitWindows.WindowFor(HitResult.Meh) * 2 * GameplaySpeed;
double animStart = HitObject.StartTime - fadeIn - moveTo;
double currentProg = Clock.CurrentTime - animStart;
// Calculate initial entry animation
float fadeAmount = Math.Clamp((float)(currentProg / fadeIn), 0, 1);
- Alpha = fadeAmount * (float)inOutBack.ApplyEasing(fadeAmount);
- Scale = new Vector2(fadeAmount * (float)inOutBack.ApplyEasing(fadeAmount));
+ Alpha = fadeAmount * (float)outSine.ApplyEasing(fadeAmount);
+ Scale = new Vector2(fadeAmount * (float)outSine.ApplyEasing(fadeAmount));
// Calculate position
float moveAmount = Math.Clamp((float)((currentProg - fadeIn) / moveTo), 0, 1);
// Used to simplify this crazy arse manual animating
- float moveAnimFormula(float originalValue) => (float)(originalValue - (originalValue * moveAmount * inQuint.ApplyEasing(moveAmount)));
+ float moveAnimFormula(float originalValue) => (float)(originalValue - (originalValue * inQuint.ApplyEasing(moveAmount)));
blob1.Position = new Vector2(moveAnimFormula(40), 0);
blob2.Position = new Vector2(moveAnimFormula(-40), 0);
@@ -134,7 +134,7 @@ protected override void Update()
blob4.Position = new Vector2(0, moveAnimFormula(-40));
// Used to simplify this crazy arse manual animating
- float sizeAnimFormula() => (float)(.5 + .5 * moveAmount * inQuint.ApplyEasing(moveAmount));
+ float sizeAnimFormula() => (float)(.5 + .5 * inQuint.ApplyEasing(moveAmount));
blob1.Scale = new Vector2(sizeAnimFormula());
blob2.Scale = new Vector2(sizeAnimFormula());
@@ -188,8 +188,8 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
var result = HitObject.HitWindows.ResultFor(timeOffset);
if (timeOffset < 0 && result <= HitResult.Miss)
return;
- if (result >= HitResult.Meh && timeOffset < 0)
- result = HitResult.Perfect;
+ if (result >= HitResult.Meh && result < HitResult.Great && timeOffset < 0)
+ result = HitResult.Great;
ApplyResult(r => r.Type = result);
}
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Drawables/Pieces/HitReceptor.cs b/osu.Game.Rulesets.Sentakki/Objects/Drawables/Pieces/HitReceptor.cs
index 843ea4148..5907a94d7 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Drawables/Pieces/HitReceptor.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Drawables/Pieces/HitReceptor.cs
@@ -21,10 +21,10 @@ public class HitReceptor : CircularContainer, IKeyBindingHandler
public Func Hit;
public Action Release;
- public float NoteAngle = -1;
+ public int? NotePath = null;
public bool HoverAction()
{
- if (!SentakkiActionInputManager.CurrentAngles.Contains(NoteAngle))
+ if (!NotePath.HasValue || !SentakkiActionInputManager.CurrentPath.Contains(NotePath.Value))
{
if (SentakkiActionInputManager.PressedActions.Any(action => OnPressed(action)))
actions.AddRange(SentakkiActionInputManager.PressedActions.Except(actions));
@@ -44,7 +44,8 @@ public virtual bool OnPressed(SentakkiAction action)
{
if (IsHovered)
{
- SentakkiActionInputManager.CurrentAngles.Add(NoteAngle);
+ if (NotePath.HasValue)
+ SentakkiActionInputManager.CurrentPath.Add(NotePath.Value);
actions.Add(action);
return Hit?.Invoke() ?? false;
}
@@ -57,13 +58,15 @@ public void OnReleased(SentakkiAction action)
if (!actions.Any())
{
Release?.Invoke();
- SentakkiActionInputManager.CurrentAngles.Remove(NoteAngle);
+ if (NotePath.HasValue)
+ SentakkiActionInputManager.CurrentPath.Remove(NotePath.Value);
}
}
protected override void OnHoverLost(HoverLostEvent e)
{
- SentakkiActionInputManager.CurrentAngles.Remove(NoteAngle);
+ if (NotePath.HasValue)
+ SentakkiActionInputManager.CurrentPath.Remove(NotePath.Value);
if (actions.Any())
{
actions.Clear();
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Hold.cs b/osu.Game.Rulesets.Sentakki/Objects/Hold.cs
index 61c5fcd5f..0a1eb3d96 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Hold.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Hold.cs
@@ -63,29 +63,18 @@ public override double StartTime
}
}
- public override float Angle
+ public override int Lane
{
- get => base.Angle;
+ get => base.Lane;
set
{
- base.Angle = value;
- Head.Angle = value;
- Tail.Angle = value;
+ base.Lane = value;
+ Head.Lane = value;
+ Tail.Lane = value;
}
}
- public override Vector2 EndPosition
- {
- get => base.EndPosition;
- set
- {
- base.EndPosition = value;
- Head.EndPosition = value;
- Tail.EndPosition = value;
- }
- }
-
- public readonly Tap Head = new Tap();
+ public readonly HoldHead Head = new HoldHead();
public readonly HoldTail Tail = new HoldTail();
@@ -100,5 +89,8 @@ protected override void CreateNestedHitObjects()
public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
+
+ public class HoldHead : SentakkiHitObject { }
+ public class HoldTail : SentakkiHitObject { }
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Objects/HoldTail.cs b/osu.Game.Rulesets.Sentakki/Objects/HoldTail.cs
deleted file mode 100644
index cb9fea782..000000000
--- a/osu.Game.Rulesets.Sentakki/Objects/HoldTail.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Sentakki.Judgements;
-
-namespace osu.Game.Rulesets.Sentakki.Objects
-{
- public class HoldTail : Tap { }
-}
diff --git a/osu.Game.Rulesets.Sentakki/Objects/SentakkiHitObject.cs b/osu.Game.Rulesets.Sentakki/Objects/SentakkiHitObject.cs
index 37a7a7a45..abdab7ddc 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/SentakkiHitObject.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/SentakkiHitObject.cs
@@ -19,17 +19,16 @@ public abstract class SentakkiHitObject : HitObject, IHasPosition
public override Judgement CreateJudgement() => IsBreak ? new SentakkiBreakJudgement() : new SentakkiJudgement();
public virtual Color4 NoteColor => IsBreak ? Color4.OrangeRed : (HasTwin ? Color4.Gold : Color4Extensions.FromHex("ff0064"));
- public virtual Vector2 EndPosition { get; set; }
- public virtual float Angle
+
+ public readonly BindableInt LaneBindable = new BindableInt(0);
+ public virtual int Lane
{
- get => BindableAngle.Value;
- set => BindableAngle.Value = value;
+ get => LaneBindable.Value;
+ set => LaneBindable.Value = value;
}
- public readonly Bindable BindableAngle = new Bindable(0);
-
- public Vector2 Position { get; set; }
-
+ // This section is required just so editor actually starts
+ public Vector2 Position { get; set; } = Vector2.Zero;
public float X => Position.X;
public float Y => Position.Y;
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Touch.cs b/osu.Game.Rulesets.Sentakki/Objects/Touch.cs
index 7272f5bdb..dab217ecc 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Touch.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Touch.cs
@@ -1,18 +1,17 @@
using osu.Game.Rulesets.Sentakki.Scoring;
using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
+using osuTK;
namespace osu.Game.Rulesets.Sentakki.Objects
{
public class Touch : SentakkiHitObject
{
+ // Currently to avoid conflict issues
+ //public new Vector2 Position { get; set; }
+
public override bool IsBreak => false;
public override Color4 NoteColor => HasTwin ? Color4.Gold : Color4.Cyan;
-
- public override float Angle => 0;
-
- // This is not actually used during the result check, since all valid hits result in a perfect judgement
- // The only reason that it's here is so that hits show on the accuracy meter at the side.
- protected override HitWindows CreateHitWindows() => new SentakkiHitWindows();
+ protected override HitWindows CreateHitWindows() => new SentakkiTouchHitWindows();
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Resources/Samples/Gameplay/Taka.wav b/osu.Game.Rulesets.Sentakki/Resources/Samples/Gameplay/Taka.wav
new file mode 100644
index 000000000..e04d318d9
Binary files /dev/null and b/osu.Game.Rulesets.Sentakki/Resources/Samples/Gameplay/Taka.wav differ
diff --git a/osu.Game.Rulesets.Sentakki/Scoring/SentakkiHitWindows.cs b/osu.Game.Rulesets.Sentakki/Scoring/SentakkiHitWindows.cs
index f745020d4..aff3ce7dd 100644
--- a/osu.Game.Rulesets.Sentakki/Scoring/SentakkiHitWindows.cs
+++ b/osu.Game.Rulesets.Sentakki/Scoring/SentakkiHitWindows.cs
@@ -18,5 +18,13 @@ public override bool IsHitResultAllowed(HitResult result)
return false;
}
}
+
+ protected override DifficultyRange[] GetRanges() => new DifficultyRange[]{
+ new DifficultyRange(HitResult.Miss, 144, 144, 144),
+ new DifficultyRange(HitResult.Meh, 144, 144, 144),
+ new DifficultyRange(HitResult.Good, 96, 96, 96),
+ new DifficultyRange(HitResult.Great, 48, 48, 48),
+ new DifficultyRange(HitResult.Perfect, 16, 16, 16)
+ };
}
}
diff --git a/osu.Game.Rulesets.Sentakki/Scoring/SentakkiTouchHitWindows.cs b/osu.Game.Rulesets.Sentakki/Scoring/SentakkiTouchHitWindows.cs
new file mode 100644
index 000000000..b402815db
--- /dev/null
+++ b/osu.Game.Rulesets.Sentakki/Scoring/SentakkiTouchHitWindows.cs
@@ -0,0 +1,15 @@
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Sentakki.Scoring
+{
+ public class SentakkiTouchHitWindows : SentakkiHitWindows
+ {
+ protected override DifficultyRange[] GetRanges() => new DifficultyRange[]{
+ new DifficultyRange(HitResult.Miss, 288, 288, 288),
+ new DifficultyRange(HitResult.Meh, 288, 288, 288),
+ new DifficultyRange(HitResult.Good, 240, 240, 240),
+ new DifficultyRange(HitResult.Great, 192, 192, 192),
+ new DifficultyRange(HitResult.Perfect, 144, 144, 144)
+ };
+ }
+}
diff --git a/osu.Game.Rulesets.Sentakki/SentakkiExtensions.cs b/osu.Game.Rulesets.Sentakki/SentakkiExtensions.cs
index 038843901..293114d38 100644
--- a/osu.Game.Rulesets.Sentakki/SentakkiExtensions.cs
+++ b/osu.Game.Rulesets.Sentakki/SentakkiExtensions.cs
@@ -6,13 +6,13 @@ namespace osu.Game.Rulesets.Sentakki
{
public static class SentakkiExtensions
{
- public static float GetAngleFromPath(this int path)
+ public static float GetRotationForLane(this int lane)
{
- while (path < 0) path += 8;
- path %= 8;
- return SentakkiPlayfield.PATHANGLES[path];
+ while (lane < 0) lane += 8;
+ lane %= 8;
+ return SentakkiPlayfield.LANEANGLES[lane];
}
- public static Vector2 GetPathPosition(float distance, int path) => GetCircularPosition(distance, path.GetAngleFromPath());
+ public static Vector2 GetPositionAlongLane(float distance, int lane) => GetCircularPosition(distance, lane.GetRotationForLane());
public static Vector2 GetCircularPosition(float distance, float angle)
{
@@ -21,15 +21,15 @@ public static Vector2 GetCircularPosition(float distance, float angle)
public static float GetDegreesFromPosition(this Vector2 target, Vector2 self) => (float)MathHelper.RadiansToDegrees(Math.Atan2(target.X - self.X, target.Y - self.Y));
- public static int GetNotePathFromDegrees(this float degrees)
+ public static int GetNoteLaneFromDegrees(this float degrees)
{
if (degrees < 0) degrees += 360;
if (degrees >= 360) degrees %= 360;
int result = 0;
- for (int i = 0; i < SentakkiPlayfield.PATHANGLES.Length; ++i)
+ for (int i = 0; i < SentakkiPlayfield.LANEANGLES.Length; ++i)
{
- if (SentakkiPlayfield.PATHANGLES[i] - degrees >= -22.5f && SentakkiPlayfield.PATHANGLES[i] - degrees <= 22.5f)
+ if (SentakkiPlayfield.LANEANGLES[i] - degrees >= -22.5f && SentakkiPlayfield.LANEANGLES[i] - degrees <= 22.5f)
result = i;
}
return result;
diff --git a/osu.Game.Rulesets.Sentakki/SentakkiInputManager.cs b/osu.Game.Rulesets.Sentakki/SentakkiInputManager.cs
index 3a9195750..54516e686 100644
--- a/osu.Game.Rulesets.Sentakki/SentakkiInputManager.cs
+++ b/osu.Game.Rulesets.Sentakki/SentakkiInputManager.cs
@@ -40,7 +40,7 @@ public SentakkiInputManager(RulesetInfo ruleset)
{
}
- public List CurrentAngles = new List();
+ public List CurrentPath = new List();
}
public enum SentakkiAction
diff --git a/osu.Game.Rulesets.Sentakki/SentakkiRuleset.cs b/osu.Game.Rulesets.Sentakki/SentakkiRuleset.cs
index 51d19dfeb..e4252d8e7 100644
--- a/osu.Game.Rulesets.Sentakki/SentakkiRuleset.cs
+++ b/osu.Game.Rulesets.Sentakki/SentakkiRuleset.cs
@@ -4,7 +4,9 @@
using osu.Framework.Input.Bindings;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
+using osu.Game.Scoring;
using osu.Game.Overlays.Settings;
+using osu.Game.Screens.Ranking.Statistics;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Sentakki.Beatmaps;
@@ -12,6 +14,7 @@
using osu.Game.Rulesets.Sentakki.Mods;
using osu.Game.Rulesets.Sentakki.Replays;
using osu.Game.Rulesets.Sentakki.Scoring;
+using osu.Game.Rulesets.Sentakki.Statistics;
using osu.Game.Rulesets.Sentakki.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays.Types;
@@ -20,6 +23,7 @@
using System.Collections.Generic;
using osu.Game.Rulesets.Sentakki.Edit;
using osu.Game.Rulesets.Edit;
+using osuTK;
namespace osu.Game.Rulesets.Sentakki
{
@@ -97,6 +101,32 @@ public override IEnumerable GetDefaultKeyBindings(int variant = 0) =
new KeyBinding(InputKey.MouseRight, SentakkiAction.Button2),
};
+ public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => new[]
+ {
+ new StatisticRow
+ {
+ Columns = new[]
+ {
+ new StatisticItem("Timing Distribution", new HitEventTimingDistributionGraph(score.HitEvents)
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 250
+ })
+ }
+ },
+ new StatisticRow
+ {
+ Columns = new[]
+ {
+ new StatisticItem("Judgement Distribution", new JudgementChart(score.HitEvents)
+ {
+ RelativeSizeAxes = Axes.X,
+ Size = new Vector2(1, 250)
+ }),
+ }
+ }
+ };
+
public override Drawable CreateIcon() => new Sprite
{
Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/Icon2"),
diff --git a/osu.Game.Rulesets.Sentakki/Statistics/JudgementChart.cs b/osu.Game.Rulesets.Sentakki/Statistics/JudgementChart.cs
new file mode 100644
index 000000000..d0bc0e0d6
--- /dev/null
+++ b/osu.Game.Rulesets.Sentakki/Statistics/JudgementChart.cs
@@ -0,0 +1,252 @@
+using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Rulesets.Sentakki.Objects;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Graphics.UserInterface;
+using osuTK.Graphics;
+using osuTK;
+
+namespace osu.Game.Rulesets.Sentakki.Statistics
+{
+ public class JudgementChart : CompositeDrawable
+ {
+ private const double entry_animation_duration = 150;
+ private const double bar_fill_duration = 3000;
+ public JudgementChart(List hitEvents)
+ {
+ Origin = Anchor.Centre;
+ Anchor = Anchor.Centre;
+ Size = new Vector2(500, 250);
+ AddRangeInternal(new Drawable[]{
+ new NoteEntry
+ {
+ ObjectName = "Tap",
+ HitEvents = hitEvents.Where(e=> e.HitObject is Tap && !(e.HitObject as SentakkiHitObject).IsBreak).ToList(),
+ Position = new Vector2(0, 0),
+ InitialLifetimeOffset = entry_animation_duration * 0
+ },
+ new NoteEntry
+ {
+ ObjectName = "Hold",
+ HitEvents = hitEvents.Where(e => (e.HitObject is Hold.HoldHead || e.HitObject is Hold.HoldTail) && !(e.HitObject as SentakkiHitObject).IsBreak).ToList(),
+ Position = new Vector2(0, .16f),
+ InitialLifetimeOffset = entry_animation_duration * 1
+ },
+ new NoteEntry
+ {
+ ObjectName = "Slide",
+ HitEvents = new List(),
+ Position = new Vector2(0, .32f),
+ InitialLifetimeOffset = entry_animation_duration * 2
+ },
+ new NoteEntry
+ {
+ ObjectName = "Touch",
+ HitEvents = hitEvents.Where(e => e.HitObject is Touch).ToList(),
+ Position = new Vector2(0, .48f),
+ InitialLifetimeOffset = entry_animation_duration * 3
+ },
+ new NoteEntry
+ {
+ ObjectName = "Touch Hold",
+ HitEvents = hitEvents.Where(e => e.HitObject is TouchHold).ToList(),
+ Position = new Vector2(0, .64f),
+ InitialLifetimeOffset = entry_animation_duration * 4
+ },
+ new NoteEntry
+ {
+ ObjectName = "Break",
+ HitEvents = hitEvents.Where(e => (e.HitObject as SentakkiHitObject).IsBreak).ToList(),
+ Position = new Vector2(0, .80f),
+ InitialLifetimeOffset = entry_animation_duration * 5
+ },
+ });
+ }
+ public class NoteEntry : Container
+ {
+ public double InitialLifetimeOffset = 0;
+ private Container progressBox;
+ private RollingCounter noteCounter;
+
+ public string ObjectName = "Object";
+ public List HitEvents;
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ float MehCount = 0;
+ float GoodCount = 0;
+ float GreatCount = 0;
+
+ foreach (var e in HitEvents)
+ {
+ switch (e.Result)
+ {
+ case HitResult.Perfect:
+ case HitResult.Great:
+ ++GreatCount;
+ goto case HitResult.Good;
+ case HitResult.Good:
+ ++GoodCount;
+ goto case HitResult.Meh;
+ case HitResult.Meh:
+ ++MehCount;
+ break;
+ }
+ }
+
+ Color4 textColour = HitEvents.Count == 0 ? Color4Extensions.FromHex("bcbcbc") : (GreatCount == HitEvents.Count) ? Color4.White : Color4Extensions.FromHex("#3c5394");
+ Color4 boxColour = HitEvents.Count == 0 ? Color4Extensions.FromHex("808080") : (GreatCount == HitEvents.Count) ? Color4Extensions.FromHex("fda908") : Color4Extensions.FromHex("#DCE9F9");
+ Color4 borderColour = HitEvents.Count == 0 ? Color4Extensions.FromHex("536277") : (GreatCount == HitEvents.Count) ? Color4Extensions.FromHex("fda908") : Color4Extensions.FromHex("#98b8df");
+ Color4 numberColour = (GreatCount == HitEvents.Count && HitEvents.Count > 0) ? Color4.White : Color4Extensions.FromHex("#3c5394");
+
+ Anchor = Anchor.TopCentre;
+ Origin = Anchor.TopCentre;
+ RelativePositionAxes = Axes.Both;
+ RelativeSizeAxes = Axes.Both;
+ Size = new Vector2(1, .16f);
+ Scale = new Vector2(1, 0);
+ Alpha = 0;
+ Masking = true;
+ BorderThickness = 2;
+ BorderColour = borderColour;
+ CornerRadius = 5;
+ CornerExponent = 2.5f;
+ AlwaysPresent = true;
+
+ InternalChildren = new Drawable[]{
+ new Box {
+ RelativeSizeAxes = Axes.Both,
+ Colour = boxColour,
+ },
+ new Container { // Left
+ RelativeSizeAxes = Axes.Both,
+ Origin = Anchor.CentreLeft,
+ Anchor = Anchor.CentreLeft,
+ Size = new Vector2(.33f, 1),
+ Child = new OsuSpriteText
+ {
+ Colour = textColour,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = ObjectName.ToUpper(),
+ Font = OsuFont.Torus.With(size: 20, weight: FontWeight.Bold)
+ }
+ },
+ progressBox = new Container { // Centre
+ RelativeSizeAxes = Axes.Both,
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Size = new Vector2(.34f, .8f),
+ CornerRadius = 5,
+ CornerExponent = 2.5f,
+ Masking = true,
+ BorderThickness = 2,
+ BorderColour = Color4.Black,
+ Children = new Drawable[]{
+ new Box{
+ RelativeSizeAxes = Axes.Both,
+ Colour = (HitEvents.Count ==0) ? Color4Extensions.FromHex("343434"):Color4.DarkGray,
+ }
+ }
+ },
+ new Container { // Right
+ RelativeSizeAxes = Axes.Both,
+ Origin = Anchor.CentreRight,
+ Anchor = Anchor.CentreRight,
+ Size = new Vector2(.33f, 1),
+ Child = noteCounter = new TotalNoteCounter
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Colour = numberColour,
+ Current = { Value = 0 },
+ }
+ },
+ };
+
+ progressBox.AddRange(new Drawable[]{
+ new ChartBar(HitResult.Meh, MehCount/HitEvents.Count){
+ InitialLifetimeOffset = InitialLifetimeOffset
+ },
+ new ChartBar(HitResult.Good, GoodCount/HitEvents.Count){
+ InitialLifetimeOffset = InitialLifetimeOffset
+ },
+ new ChartBar(HitResult.Great, GreatCount/HitEvents.Count){
+ InitialLifetimeOffset = InitialLifetimeOffset
+ },
+ });
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ ScheduleAfterChildren(() =>
+ {
+ using (BeginDelayedSequence(InitialLifetimeOffset, true))
+ {
+ this.ScaleTo(1, entry_animation_duration, Easing.OutBack).FadeIn();
+ noteCounter.Current.Value = HitEvents.Count;
+ }
+ });
+ }
+
+ public class TotalNoteCounter : RollingCounter
+ {
+ protected override double RollingDuration => bar_fill_duration;
+
+ protected override Easing RollingEasing => Easing.OutPow10;
+
+ public TotalNoteCounter()
+ {
+ DisplayedCountSpriteText.Anchor = Anchor.Centre;
+ DisplayedCountSpriteText.Origin = Anchor.Centre;
+ DisplayedCountSpriteText.Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold);
+ }
+
+ protected override string FormatCount(long count) => count.ToString("N0");
+
+ public override void Increment(long amount)
+ => Current.Value += amount;
+ }
+
+ private class ChartBar : Container
+ {
+ public double InitialLifetimeOffset = 0;
+
+ private HitResult result;
+
+ public ChartBar(HitResult result, float progress)
+ {
+ this.result = result;
+ RelativeSizeAxes = Axes.Both;
+ Size = new Vector2(float.IsNaN(progress) ? 0 : progress, 1);
+ Scale = new Vector2(0, 1);
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Add(new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colours.ForHitResult(result)
+ });
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ this.Delay(InitialLifetimeOffset).ScaleTo(1, bar_fill_duration, Easing.OutPow10);
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Sentakki/UI/Components/SentakkiRing.cs b/osu.Game.Rulesets.Sentakki/UI/Components/SentakkiRing.cs
index f7205d91a..b09843997 100644
--- a/osu.Game.Rulesets.Sentakki/UI/Components/SentakkiRing.cs
+++ b/osu.Game.Rulesets.Sentakki/UI/Components/SentakkiRing.cs
@@ -97,7 +97,7 @@ public SentakkiRing()
};
// Add dots to the actual ring
- foreach (float pathAngle in SentakkiPlayfield.PATHANGLES)
+ foreach (float pathAngle in SentakkiPlayfield.LANEANGLES)
{
AddInternal(new CircularContainer
{
diff --git a/osu.Game.Rulesets.Sentakki/UI/DrawableSentakkiRuleset.cs b/osu.Game.Rulesets.Sentakki/UI/DrawableSentakkiRuleset.cs
index 0155390a8..77f367647 100644
--- a/osu.Game.Rulesets.Sentakki/UI/DrawableSentakkiRuleset.cs
+++ b/osu.Game.Rulesets.Sentakki/UI/DrawableSentakkiRuleset.cs
@@ -11,6 +11,7 @@
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Play;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Sentakki.UI
@@ -62,6 +63,8 @@ public override DrawableHitObject CreateDrawableRepresentatio
return null;
}
+ protected override ResumeOverlay CreateResumeOverlay() => new SentakkiResumeOverlay();
+
protected override PassThroughInputManager CreateInputManager() => new SentakkiInputManager(Ruleset?.RulesetInfo);
}
}
diff --git a/osu.Game.Rulesets.Sentakki/UI/SentakkiPlayfield.cs b/osu.Game.Rulesets.Sentakki/UI/SentakkiPlayfield.cs
index efaa2e3d9..614b49b5b 100644
--- a/osu.Game.Rulesets.Sentakki/UI/SentakkiPlayfield.cs
+++ b/osu.Game.Rulesets.Sentakki/UI/SentakkiPlayfield.cs
@@ -31,17 +31,17 @@ public class SentakkiPlayfield : Playfield, IRequireHighFrequencyMousePosition
public static readonly float INTERSECTDISTANCE = 296.5f;
public static readonly float NOTESTARTDISTANCE = 66f;
- public static readonly float[] PATHANGLES =
- {
- 22.5f,
- 67.5f,
- 112.5f,
- 157.5f,
- 202.5f,
- 247.5f,
- 292.5f,
- 337.5f
- };
+ public static readonly float[] LANEANGLES =
+ {
+ 22.5f,
+ 67.5f,
+ 112.5f,
+ 157.5f,
+ 202.5f,
+ 247.5f,
+ 292.5f,
+ 337.5f
+ };
// Touch notes always appear above other notes, regardless of start time
private readonly TouchNoteProxyContainer touchNoteContainer;
@@ -105,8 +105,6 @@ private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
var sentakkiObj = (DrawableSentakkiHitObject)judgedObject;
- var b = sentakkiObj.HitObject.Angle + 90;
- var a = b *= (float)(Math.PI / 180);
DrawableSentakkiJudgement explosion;
switch (judgedObject)
{
@@ -131,8 +129,8 @@ private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Position = new Vector2(-(240 * (float)Math.Cos(a)), -(240 * (float)Math.Sin(a))),
- Rotation = sentakkiObj.HitObject.Angle,
+ Position = SentakkiExtensions.GetPositionAlongLane(240, sentakkiObj.HitObject.Lane),
+ Rotation = sentakkiObj.HitObject.Lane.GetRotationForLane(),
};
break;
}
diff --git a/osu.Game.Rulesets.Sentakki/UI/SentakkiResumeOverlay.cs b/osu.Game.Rulesets.Sentakki/UI/SentakkiResumeOverlay.cs
new file mode 100644
index 000000000..f77c61336
--- /dev/null
+++ b/osu.Game.Rulesets.Sentakki/UI/SentakkiResumeOverlay.cs
@@ -0,0 +1,91 @@
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Skinning;
+using osu.Game.Audio;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Screens.Play;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
+using osuTK.Graphics;
+using System;
+
+namespace osu.Game.Rulesets.Sentakki.UI
+{
+ public class SentakkiResumeOverlay : ResumeOverlay
+ {
+ protected override string Message => "Get ready!";
+
+ private double timePassed = 3500;
+ private Bindable tickCount = new Bindable(4);
+
+ private OsuSpriteText counterText;
+ private readonly SkinnableSound countSound;
+
+ private SentakkiCursorContainer localCursorContainer;
+
+ public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null;
+
+ public SentakkiResumeOverlay()
+ {
+ Origin = Anchor.Centre;
+ Anchor = Anchor.Centre;
+ RelativeSizeAxes = Axes.Both;
+ FillMode = FillMode.Fill;
+ Children = new Drawable[]{
+ counterText = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = "",
+ Font = OsuFont.Torus.With(size: 50),
+ Colour = Color4.White,
+ },
+ countSound = new SkinnableSound(new SampleInfo("Taka"))
+ };
+ tickCount.BindValueChanged(
+ ticks =>
+ {
+ counterText.Text = (ticks.NewValue == 4) ? "" : ticks.NewValue.ToString();
+ if (ticks.NewValue % 4 != 0) countSound?.Play();
+ if (ticks.NewValue <= 0) Resume();
+ }
+ );
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+ timePassed -= Clock.ElapsedFrameTime;
+ tickCount.Value = (int)Math.Ceiling(timePassed / 1000);
+ }
+
+ protected override void PopIn()
+ {
+ base.PopIn();
+
+ // Reset the countdown
+ timePassed = 3500;
+
+ GameplayCursor.ActiveCursor.Hide();
+
+ if (localCursorContainer == null)
+ {
+ Add(localCursorContainer = new SentakkiCursorContainer());
+ localCursorContainer.MoveTo(GameplayCursor.ActiveCursor.Position);
+ }
+ }
+
+ protected override void PopOut()
+ {
+ base.PopOut();
+
+ if (localCursorContainer != null && GameplayCursor?.ActiveCursor != null)
+ GameplayCursor.ActiveCursor.Position = localCursorContainer.Position;
+
+ localCursorContainer?.Expire();
+ localCursorContainer = null;
+ GameplayCursor?.ActiveCursor?.Show();
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Sentakki/osu.Game.Rulesets.Sentakki.csproj b/osu.Game.Rulesets.Sentakki/osu.Game.Rulesets.Sentakki.csproj
index 083676a0a..2670d13b0 100644
--- a/osu.Game.Rulesets.Sentakki/osu.Game.Rulesets.Sentakki.csproj
+++ b/osu.Game.Rulesets.Sentakki/osu.Game.Rulesets.Sentakki.csproj
@@ -10,6 +10,6 @@
osu.Game.Rulesets.Sentakki
-
+
\ No newline at end of file