diff --git a/osu.Game/Modes/ScoreProcessor.cs b/osu.Game/Modes/ScoreProcessor.cs
index 35e19626b2..3900a79485 100644
--- a/osu.Game/Modes/ScoreProcessor.cs
+++ b/osu.Game/Modes/ScoreProcessor.cs
@@ -12,6 +12,36 @@ namespace osu.Game.Modes
{
public abstract class ScoreProcessor
{
+ ///
+ /// Invoked when the score is in a failing state.
+ ///
+ public event Action Failed;
+
+ ///
+ /// The current total score.
+ ///
+ public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 };
+
+ ///
+ /// The current accuracy.
+ ///
+ public readonly BindableDouble Accuracy = new BindableDouble { MinValue = 0, MaxValue = 1 };
+
+ ///
+ /// The current health.
+ ///
+ public readonly BindableDouble Health = new BindableDouble { MinValue = 0, MaxValue = 1 };
+
+ ///
+ /// The current combo.
+ ///
+ public readonly BindableInt Combo = new BindableInt();
+
+ ///
+ /// THe highest combo achieved by this score.
+ ///
+ public readonly BindableInt HighestCombo = new BindableInt();
+
public virtual Score GetScore() => new Score
{
TotalScore = TotalScore,
@@ -21,24 +51,11 @@ namespace osu.Game.Modes
Health = Health,
};
- public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 };
-
- public readonly BindableDouble Accuracy = new BindableDouble { MinValue = 0, MaxValue = 1 };
-
- public readonly BindableDouble Health = new BindableDouble { MinValue = 0, MaxValue = 1 };
-
- public readonly BindableInt Combo = new BindableInt();
-
///
- /// Keeps track of the highest combo ever achieved in this play.
- /// This is handled automatically by ScoreProcessor.
+ /// Checks if the score is in a failing state.
///
- public readonly BindableInt HighestCombo = new BindableInt();
-
- ///
- /// Called when we reach a failing health of zero.
- ///
- public event Action Failed;
+ /// Whether the score is in a failing state.
+ public abstract bool CheckFailed();
///
/// Notifies subscribers that the score is in a failed state.
@@ -56,17 +73,17 @@ namespace osu.Game.Modes
///
/// All judgements held by this ScoreProcessor.
///
- protected List Judgements;
+ protected readonly List Judgements = new List();
///
- /// Are we allowed to fail?
+ /// Whether the score is in a failable state.
///
- protected bool CanFail => true;
+ protected virtual bool IsFailable => Health.Value == Health.MinValue;
///
- /// Whether this ScoreProcessor has already triggered the failed event.
+ /// Whether this ScoreProcessor has already failed.
///
- protected bool HasFailed { get; private set; }
+ private bool hasFailed;
protected ScoreProcessor()
{
@@ -78,10 +95,14 @@ namespace osu.Game.Modes
protected ScoreProcessor(HitRenderer hitRenderer)
: this()
{
- Judgements = new List(hitRenderer.Beatmap.HitObjects.Count);
+ Judgements.Capacity = hitRenderer.Beatmap.HitObjects.Count;
hitRenderer.OnJudgement += addJudgement;
}
+ ///
+ /// Adds a judgement to this ScoreProcessor.
+ ///
+ /// The judgement to add.
private void addJudgement(TJudgement judgement)
{
Judgements.Add(judgement);
@@ -89,17 +110,35 @@ namespace osu.Game.Modes
UpdateCalculations(judgement);
judgement.ComboAtHit = (ulong)Combo.Value;
- if (Health.Value == Health.MinValue && !HasFailed)
+
+ CheckFailed();
+ }
+
+ public override bool CheckFailed()
+ {
+ if (!hasFailed && IsFailable)
{
- HasFailed = true;
+ hasFailed = true;
TriggerFailed();
}
+
+ return hasFailed;
}
///
/// Resets this ScoreProcessor to a stale state.
///
- protected virtual void Reset() { }
+ protected virtual void Reset()
+ {
+ Judgements.Clear();
+
+ hasFailed = false;
+ TotalScore.Value = 0;
+ Accuracy.Value = 0;
+ Health.Value = 0;
+ Combo.Value = 0;
+ HighestCombo.Value = 0;
+ }
///
/// Update any values that potentially need post-processing on a judgement change.
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index a4c7e84ce7..ec8cbb1438 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -135,7 +135,7 @@ namespace osu.Game.Screens.Play
hudOverlay.BindHitRenderer(hitRenderer);
//bind HitRenderer to ScoreProcessor and ourselves (for a pass situation)
- hitRenderer.OnAllJudged += onPass;
+ hitRenderer.OnAllJudged += onCompletion;
//bind ScoreProcessor to ourselves (for a fail situation)
scoreProcessor.Failed += onFail;
@@ -237,8 +237,17 @@ namespace osu.Game.Screens.Play
});
}
- private void onPass()
+ private void onCompletion()
{
+ // Force a final check to see if the player has failed
+ // Some game modes (e.g. taiko) fail at the end of the map
+ if (scoreProcessor.CheckFailed())
+ {
+ // If failed, onFail will be invoked which will push a new screen.
+ // Let's not push the completion screen in this case
+ return;
+ }
+
Delay(1000);
Schedule(delegate
{