diff --git a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
index d68124e1f..7c68e2dd3 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
@@ -66,11 +66,10 @@ private void load()
});
}
- protected override void OnFree()
+ protected override void OnApply()
{
- base.OnFree();
- HoldStartTime = null;
- TotalHoldTime = 0;
+ base.OnApply();
+ isHolding = false;
}
protected override void UpdateInitialTransforms()
@@ -97,42 +96,62 @@ protected override void UpdateInitialTransforms()
.Then().Delay(HitObject.Duration - stretchTime) // Wait until the end of the hold note, while considering how much time we need for shrinking
.ResizeHeightTo(0, stretchTime); // We shrink the hold note as it exits
- if (HoldStartTime == null && !Auto)
+ if (isHolding == false && !Auto)
NoteBody.Delay(animTime).FadeColour(Color4.Gray, 100);
}
}
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
- if (Time.Current > HitObject.GetEndTime())
+ if (!userTriggered)
{
- endHold();
- double totalHoldRatio = TotalHoldTime / ((IHasDuration)HitObject).Duration;
- HitResult result;
-
- if (totalHoldRatio >= .75 || Auto)
- result = HitResult.Great;
- else if (totalHoldRatio >= .5)
- result = HitResult.Good;
- else if (totalHoldRatio >= .25)
- result = HitResult.Ok;
- else
- result = HitResult.Miss;
-
- // This is specifically to accommodate the threshold setting in HR
- if (!HitObject.HitWindows.IsHitResultAllowed(result))
- result = HitResult.Miss;
-
- // Hold is over, but head windows are still active.
- // Only happens on super short holds
- // Force a miss on the head in this case
- if (!headContainer[0].Result.HasResult)
- headContainer[0].MissForcefully();
-
- ApplyResult(result);
+ if (timeOffset >= 0 && Auto)
+ ApplyResult(HitResult.Perfect);
+ else if (timeOffset >= 0 && isHolding)
+ ApplyResult(applyDeductionTo(HitResult.Perfect));
+ else if (!HitObject.HitWindows.CanBeHit(timeOffset: timeOffset))
+ ApplyResult(Result.Judgement.MinResult);
+
+ return;
+ }
+ var result = HitObject.HitWindows.ResultFor(timeOffset);
+
+ if (result == HitResult.None)
+ return;
+
+ if (HitObject.Ex && result.IsHit())
+ result = Result.Judgement.MaxResult;
+
+ ApplyResult(applyDeductionTo(result));
+
+ HitResult applyDeductionTo(HitResult originalResult)
+ {
+ int deduction = (int)Math.Min(Math.Floor(timeNotHeld / 300), 3);
+
+ var newResult = originalResult - deduction;
+
+ if (originalResult <= HitResult.Ok)
+ return HitResult.Ok;
+
+ return newResult;
}
}
+ private double timeNotHeld = 0;
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (!Head.AllJudged)
+ return;
+
+ if (isHolding)
+ return;
+
+ timeNotHeld += Time.Elapsed;
+ }
+
protected override void UpdateHitStateTransforms(ArmedState state)
{
base.UpdateHitStateTransforms(state);
@@ -190,33 +209,6 @@ protected override void ClearNestedHitObjects()
headContainer.Clear(false);
}
- ///
- /// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
- ///
- public double? HoldStartTime { get; private set; }
-
- public double TotalHoldTime;
-
- private bool beginHoldAt(double timeOffset)
- {
- if (HoldStartTime is not null)
- return false;
-
- if (timeOffset < -Head.HitObject.HitWindows.WindowFor(HitResult.Miss))
- return false;
-
- HoldStartTime = Math.Max(Time.Current, HitObject.StartTime);
- return true;
- }
-
- private void endHold()
- {
- if (HoldStartTime.HasValue)
- TotalHoldTime += Math.Max(Time.Current - HoldStartTime.Value, 0);
-
- HoldStartTime = null;
- }
-
private SentakkiInputManager sentakkiActionInputManager = null!;
internal SentakkiInputManager SentakkiActionInputManager => sentakkiActionInputManager ??= (SentakkiInputManager)GetContainingInputManager();
@@ -235,6 +227,8 @@ private int pressedCount
}
}
+ private bool isHolding = false;
+
public bool OnPressed(KeyBindingPressEvent e)
{
if (AllJudged)
@@ -243,21 +237,25 @@ public bool OnPressed(KeyBindingPressEvent e)
if (e.Action != SentakkiAction.Key1 + HitObject.Lane)
return false;
- if (beginHoldAt(Time.Current - Head.HitObject.StartTime))
- {
- Head.UpdateResult();
- NoteBody.FadeColour(AccentColour.Value, 50);
- return true;
- }
-
// Passthrough excess inputs to later hitobjects in the same lane
- return false;
+ if (isHolding)
+ return false;
+
+ double timeOffset = Time.Current - HitObject.StartTime;
+
+ if (timeOffset < -Head.HitObject.HitWindows.WindowFor(HitResult.Miss))
+ return false;
+
+ Head.UpdateResult();
+ isHolding = true;
+ NoteBody.FadeColour(AccentColour.Value, 50);
+ return true;
}
public void OnReleased(KeyBindingReleaseEvent e)
{
if (AllJudged) return;
- if (HoldStartTime is null) return;
+ if (!isHolding) return;
if (e.Action != SentakkiAction.Key1 + HitObject.Lane)
return;
@@ -267,7 +265,8 @@ public void OnReleased(KeyBindingReleaseEvent e)
if (pressedCount > 1)
return;
- endHold();
+ UpdateResult(true);
+ isHolding = false;
if (!AllJudged)
NoteBody.FadeColour(Color4.Gray, 100);
diff --git a/osu.Game.Rulesets.Sentakki/Objects/Hold.cs b/osu.Game.Rulesets.Sentakki/Objects/Hold.cs
index e54e5051e..b4052e71a 100644
--- a/osu.Game.Rulesets.Sentakki/Objects/Hold.cs
+++ b/osu.Game.Rulesets.Sentakki/Objects/Hold.cs
@@ -49,7 +49,7 @@ protected override void CreateNestedHitObjects(CancellationToken cancellationTok
});
}
- protected override HitWindows CreateHitWindows() => new SentakkiEmptyHitWindows();
+ protected override HitWindows CreateHitWindows() => new SentakkiTapHitWindows();
public class HoldHead : SentakkiLanedHitObject
{