diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs
index a8eb5e1886..cfa8e6ac7e 100644
--- a/osu.Game/Database/ScoreDatabase.cs
+++ b/osu.Game/Database/ScoreDatabase.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Database
using (SerializationReader sr = new SerializationReader(s))
{
var ruleset = Ruleset.GetRuleset((PlayMode)sr.ReadByte());
- score = ruleset.CreateScoreProcessor().GetScore();
+ score = ruleset.CreateScoreProcessor().CreateScore();
/* score.Pass = true;*/
var version = sr.ReadInt32();
diff --git a/osu.Game/Modes/ScoreProcessor.cs b/osu.Game/Modes/ScoreProcessor.cs
index 3900a79485..a6e29d53e1 100644
--- a/osu.Game/Modes/ScoreProcessor.cs
+++ b/osu.Game/Modes/ScoreProcessor.cs
@@ -7,13 +7,14 @@ using System.Collections.Generic;
using osu.Game.Modes.Judgements;
using osu.Game.Modes.UI;
using osu.Game.Modes.Objects;
+using osu.Game.Beatmaps;
namespace osu.Game.Modes
{
public abstract class ScoreProcessor
{
///
- /// Invoked when the score is in a failing state.
+ /// Invoked when the ScoreProcessor is in a failed state.
///
public event Action Failed;
@@ -42,7 +43,28 @@ namespace osu.Game.Modes
///
public readonly BindableInt HighestCombo = new BindableInt();
- public virtual Score GetScore() => new Score
+ ///
+ /// Whether the score is in a failed state.
+ ///
+ public virtual bool HasFailed => false;
+
+ ///
+ /// Whether this ScoreProcessor has already triggered the failed state.
+ ///
+ private bool alreadyFailed;
+
+ protected ScoreProcessor()
+ {
+ Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
+
+ Reset();
+ }
+
+ ///
+ /// Creates a Score applicable to the game mode in which this ScoreProcessor resides.
+ ///
+ /// The Score.
+ public virtual Score CreateScore() => new Score
{
TotalScore = TotalScore,
Combo = Combo,
@@ -52,16 +74,31 @@ namespace osu.Game.Modes
};
///
- /// Checks if the score is in a failing state.
+ /// Resets this ScoreProcessor to a default state.
///
- /// Whether the score is in a failing state.
- public abstract bool CheckFailed();
+ protected virtual void Reset()
+ {
+ TotalScore.Value = 0;
+ Accuracy.Value = 0;
+ Health.Value = 0;
+ Combo.Value = 0;
+ HighestCombo.Value = 0;
+
+ alreadyFailed = false;
+ }
///
- /// Notifies subscribers that the score is in a failed state.
+ /// Checks if the score is in a failed state and notifies subscribers.
+ ///
+ /// This can only ever notify subscribers once.
+ ///
///
- protected void TriggerFailed()
+ protected void UpdateFailed()
{
+ if (alreadyFailed || !HasFailed)
+ return;
+
+ alreadyFailed = true;
Failed?.Invoke();
}
}
@@ -75,29 +112,28 @@ namespace osu.Game.Modes
///
protected readonly List Judgements = new List();
- ///
- /// Whether the score is in a failable state.
- ///
- protected virtual bool IsFailable => Health.Value == Health.MinValue;
-
- ///
- /// Whether this ScoreProcessor has already failed.
- ///
- private bool hasFailed;
+ public override bool HasFailed => Health.Value == Health.MinValue;
protected ScoreProcessor()
{
- Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
+ }
+
+ protected ScoreProcessor(HitRenderer hitRenderer)
+ {
+ Judgements.Capacity = hitRenderer.Beatmap.HitObjects.Count;
+
+ hitRenderer.OnJudgement += addJudgement;
+
+ ComputeTargets(hitRenderer.Beatmap);
Reset();
}
- protected ScoreProcessor(HitRenderer hitRenderer)
- : this()
- {
- Judgements.Capacity = hitRenderer.Beatmap.HitObjects.Count;
- hitRenderer.OnJudgement += addJudgement;
- }
+ ///
+ /// Computes target scoring values for this ScoreProcessor. This is equivalent to performing an auto-play of the score to find the values.
+ ///
+ /// The Beatmap containing the objects that will be judged by this ScoreProcessor.
+ protected virtual void ComputeTargets(Beatmap beatmap) { }
///
/// Adds a judgement to this ScoreProcessor.
@@ -111,33 +147,12 @@ namespace osu.Game.Modes
judgement.ComboAtHit = (ulong)Combo.Value;
- CheckFailed();
+ UpdateFailed();
}
- public override bool CheckFailed()
- {
- if (!hasFailed && IsFailable)
- {
- hasFailed = true;
- TriggerFailed();
- }
-
- return hasFailed;
- }
-
- ///
- /// Resets this ScoreProcessor to a stale state.
- ///
- protected virtual void Reset()
+ protected override void Reset()
{
Judgements.Clear();
-
- hasFailed = false;
- TotalScore.Value = 0;
- Accuracy.Value = 0;
- Health.Value = 0;
- Combo.Value = 0;
- HighestCombo.Value = 0;
}
///
@@ -146,4 +161,4 @@ namespace osu.Game.Modes
/// A new JudgementInfo that triggered this calculation. May be null.
protected abstract void UpdateCalculations(TJudgement newJudgement);
}
-}
+}
\ No newline at end of file
diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs
index a0ca2549c0..1971559f49 100644
--- a/osu.Game/Modes/UI/HitRenderer.cs
+++ b/osu.Game/Modes/UI/HitRenderer.cs
@@ -25,6 +25,9 @@ namespace osu.Game.Modes.UI
///
public abstract class HitRenderer : Container
{
+ ///
+ /// Invoked when all the judgeable HitObjects have been judged.
+ ///
public event Action OnAllJudged;
///
@@ -190,9 +193,10 @@ namespace osu.Game.Modes.UI
/// The object that Judgement has been updated for.
private void onJudgement(DrawableHitObject judgedObject)
{
- OnJudgement?.Invoke(judgedObject.Judgement);
Playfield.OnJudgement(judgedObject);
+ OnJudgement?.Invoke(judgedObject.Judgement);
+
CheckAllJudged();
}
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index ec8cbb1438..674a741d8c 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -239,14 +239,9 @@ namespace osu.Game.Screens.Play
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
+ // Only show the completion screen if the player hasn't failed
+ if (scoreProcessor.HasFailed)
return;
- }
Delay(1000);
Schedule(delegate
@@ -254,7 +249,7 @@ namespace osu.Game.Screens.Play
ValidForResume = false;
Push(new Results
{
- Score = scoreProcessor.GetScore()
+ Score = scoreProcessor.CreateScore()
});
});
}