diff --git a/osu.Game/Modes/ScoreProcesssor.cs b/osu.Game/Modes/ScoreProcesssor.cs
index 3c8d2f4d25..63521996e5 100644
--- a/osu.Game/Modes/ScoreProcesssor.cs
+++ b/osu.Game/Modes/ScoreProcesssor.cs
@@ -30,6 +30,22 @@ namespace osu.Game.Modes
public readonly BindableInt Combo = new BindableInt();
+ ///
+ /// Are we allowed to fail?
+ ///
+ protected bool CanFail => true;
+
+ protected bool HasFailed;
+
+ ///
+ /// Called when we reach a failing health of zero.
+ ///
+ public event Action Failed;
+
+ ///
+ /// Keeps track of the highest combo ever achieved in this play.
+ /// This is handled automatically by ScoreProcessor.
+ ///
public readonly BindableInt HighestCombo = new BindableInt();
public readonly List Judgements;
@@ -51,6 +67,11 @@ namespace osu.Game.Modes
UpdateCalculations(judgement);
judgement.ComboAtHit = (ulong)Combo.Value;
+ if (Health.Value == Health.MinValue && !HasFailed)
+ {
+ HasFailed = true;
+ Failed?.Invoke();
+ }
}
///
diff --git a/osu.Game/Modes/UI/ScoreOverlay.cs b/osu.Game/Modes/UI/ScoreOverlay.cs
index 8fd070e9dd..4e16571b60 100644
--- a/osu.Game/Modes/UI/ScoreOverlay.cs
+++ b/osu.Game/Modes/UI/ScoreOverlay.cs
@@ -63,7 +63,7 @@ namespace osu.Game.Modes.UI
processor.TotalScore.ValueChanged += delegate { ScoreCounter?.Set((ulong)processor.TotalScore.Value); };
processor.Accuracy.ValueChanged += delegate { AccuracyCounter?.Set((float)processor.Accuracy.Value); };
processor.Combo.ValueChanged += delegate { ComboCounter?.Set((ulong)processor.Combo.Value); };
- if (HealthDisplay != null) processor.Health.Weld(HealthDisplay.Current);
+ if (HealthDisplay != null) HealthDisplay.Current.Weld(processor.Health);
}
}
}
diff --git a/osu.Game/Screens/Play/FailDialog.cs b/osu.Game/Screens/Play/FailDialog.cs
new file mode 100644
index 0000000000..c8718c1618
--- /dev/null
+++ b/osu.Game/Screens/Play/FailDialog.cs
@@ -0,0 +1,45 @@
+//Copyright (c) 2007-2016 ppy Pty Ltd .
+//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.GameModes;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Transformations;
+using osu.Game.Modes;
+using osu.Game.Screens.Backgrounds;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace osu.Game.Screens.Play
+{
+ class FailDialog : OsuGameMode
+ {
+ protected override BackgroundMode CreateBackground() => new BackgroundModeBeatmap(Beatmap);
+
+ private static readonly Vector2 BACKGROUND_BLUR = new Vector2(20);
+
+ public FailDialog()
+ {
+ Add(new SpriteText
+ {
+ Text = "You failed!",
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ TextSize = 50
+ });
+ }
+
+ protected override void OnEntering(GameMode last)
+ {
+ base.OnEntering(last);
+ Background.Schedule(() => (Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000));
+ }
+
+ protected override bool OnExiting(GameMode next)
+ {
+ Background.Schedule(() => Background.FadeColour(Color4.White, 500));
+ return base.OnExiting(next);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index fbee5db865..d6594dd2be 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -24,6 +24,7 @@ using osu.Game.Screens.Ranking;
using osu.Game.Configuration;
using osu.Framework.Configuration;
using System;
+using OpenTK.Graphics;
namespace osu.Game.Screens.Play
{
@@ -31,12 +32,10 @@ namespace osu.Game.Screens.Play
{
public bool Autoplay;
- protected override BackgroundMode CreateBackground() => null;
+ protected override BackgroundMode CreateBackground() => new BackgroundModeBeatmap(Beatmap);
internal override bool ShowOverlays => false;
- protected bool CanFail => true;
-
public BeatmapInfo BeatmapInfo;
public PlayMode PreferredPlayMode;
@@ -98,8 +97,12 @@ namespace osu.Game.Screens.Play
hitRenderer = ruleset.CreateHitRendererWith(beatmap.HitObjects);
+ //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation)
hitRenderer.OnJudgement += scoreProcessor.AddJudgement;
- hitRenderer.OnAllJudged += hitRenderer_OnAllJudged;
+ hitRenderer.OnAllJudged += onPass;
+
+ //bind ScoreProcessor to ourselves (for a fail situation)
+ scoreProcessor.Failed += onFail;
if (Autoplay)
hitRenderer.Schedule(() => hitRenderer.DrawableObjects.ForEach(h => h.State = ArmedState.Hit));
@@ -134,7 +137,7 @@ namespace osu.Game.Screens.Play
});
}
- private void hitRenderer_OnAllJudged()
+ private void onPass()
{
Delay(1000);
Schedule(delegate
@@ -147,6 +150,19 @@ namespace osu.Game.Screens.Play
});
}
+ private void onFail()
+ {
+ Content.FadeColour(Color4.Red, 500);
+ sourceClock.Stop();
+
+ Delay(500);
+ Schedule(delegate
+ {
+ ValidForResume = false;
+ Push(new FailDialog());
+ });
+ }
+
protected override void OnEntering(GameMode last)
{
base.OnEntering(last);
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 5f0a29359f..c4ae8a16bb 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -116,6 +116,7 @@
+