Skip to content

Commit

Permalink
Merge pull request #570 from LumpBloom7/Alternative-Hold-mechanics
Browse files Browse the repository at this point in the history
Reintroduce timing dependent HoldTails
  • Loading branch information
LumpBloom7 authored Apr 13, 2024
2 parents c081af2 + 3c066d4 commit 85ddaca
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 68 deletions.
133 changes: 66 additions & 67 deletions osu.Game.Rulesets.Sentakki/Objects/Drawables/DrawableHold.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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);
Expand Down Expand Up @@ -190,33 +209,6 @@ protected override void ClearNestedHitObjects()
headContainer.Clear(false);
}

/// <summary>
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
/// </summary>
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();

Expand All @@ -235,6 +227,8 @@ private int pressedCount
}
}

private bool isHolding = false;

public bool OnPressed(KeyBindingPressEvent<SentakkiAction> e)
{
if (AllJudged)
Expand All @@ -243,21 +237,25 @@ public bool OnPressed(KeyBindingPressEvent<SentakkiAction> 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<SentakkiAction> e)
{
if (AllJudged) return;
if (HoldStartTime is null) return;
if (!isHolding) return;

if (e.Action != SentakkiAction.Key1 + HitObject.Lane)
return;
Expand All @@ -267,7 +265,8 @@ public void OnReleased(KeyBindingReleaseEvent<SentakkiAction> e)
if (pressedCount > 1)
return;

endHold();
UpdateResult(true);
isHolding = false;

if (!AllJudged)
NoteBody.FadeColour(Color4.Gray, 100);
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Sentakki/Objects/Hold.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down

0 comments on commit 85ddaca

Please sign in to comment.