diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
index e77dd76353..5c41e4136c 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs
@@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
         private DrawableFruit createDrawable(int index)
         {
             Fruit fruit = index == 5
-                ? new BananaShower.Banana
+                ? new Banana
                 {
                     StartTime = 1000000000000,
                     IndexInBeatmap = index,
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index 8473f5a36c..33fc838d35 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -49,9 +49,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
                 switch (obj)
                 {
                     case BananaShower bananaShower:
-                        foreach (var nested in bananaShower.NestedHitObjects)
+                        foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
                         {
-                            ((BananaShower.Banana)nested).X = (float)rng.NextDouble();
+                            banana.X = (float)rng.NextDouble();
                             rng.Next(); // osu!stable retrieved a random banana type
                             rng.Next(); // osu!stable retrieved a random banana rotation
                             rng.Next(); // osu!stable retrieved a random banana colour
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
new file mode 100644
index 0000000000..c39e663d75
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
@@ -0,0 +1,36 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Catch.Judgements
+{
+    public class CatchBananaJudgement : CatchJudgement
+    {
+        public override bool AffectsCombo => false;
+
+        public override bool ShouldExplode => true;
+
+        protected override int NumericResultFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 1100;
+            }
+        }
+
+        protected override float HealthIncreaseFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 8;
+            }
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
new file mode 100644
index 0000000000..0df2305339
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
@@ -0,0 +1,32 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Catch.Judgements
+{
+    public class CatchDropletJudgement : CatchJudgement
+    {
+        protected override int NumericResultFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 30;
+            }
+        }
+
+        protected override float HealthIncreaseFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 7;
+            }
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
index bb2786f14f..51d7d3b5cd 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
@@ -2,11 +2,51 @@
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
 using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Scoring;
 
 namespace osu.Game.Rulesets.Catch.Judgements
 {
     public class CatchJudgement : Judgement
     {
-        // todo: wangs
+        public override HitResult MaxResult => HitResult.Perfect;
+
+        protected override int NumericResultFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 300;
+            }
+        }
+
+        /// <summary>
+        /// The base health increase for the result achieved.
+        /// </summary>
+        public float HealthIncrease => HealthIncreaseFor(Result);
+
+        /// <summary>
+        /// Whether fruit on the platter should explode or drop.
+        /// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" />
+        /// </summary>
+        public virtual bool ShouldExplode => IsHit;
+
+        /// <summary>
+        /// Convert a <see cref="HitResult"/> to a base health increase.
+        /// </summary>
+        /// <param name="result">The value to convert.</param>
+        /// <returns>The base health increase.</returns>
+        protected virtual float HealthIncreaseFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 10.2f;
+            }
+        }
     }
 }
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
new file mode 100644
index 0000000000..8b77351027
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
@@ -0,0 +1,34 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Catch.Judgements
+{
+    public class CatchTinyDropletJudgement : CatchJudgement
+    {
+        public override bool AffectsCombo => false;
+
+        protected override int NumericResultFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 10;
+            }
+        }
+
+        protected override float HealthIncreaseFor(HitResult result)
+        {
+            switch (result)
+            {
+                default:
+                    return 0;
+                case HitResult.Perfect:
+                    return 4;
+            }
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs
new file mode 100644
index 0000000000..f7c60a7a47
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs
@@ -0,0 +1,10 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Rulesets.Catch.Objects
+{
+    public class Banana : Fruit
+    {
+        public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
+    }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 4dd491966c..25af7e4bdf 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -37,10 +37,5 @@ namespace osu.Game.Rulesets.Catch.Objects
         public double EndTime => StartTime + Duration;
 
         public double Duration { get; set; }
-
-        public class Banana : Fruit
-        {
-            public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
-        }
     }
 }
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
new file mode 100644
index 0000000000..dd027abbe0
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
@@ -0,0 +1,17 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Catch.Judgements;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+    public class DrawableBanana : DrawableFruit
+    {
+        public DrawableBanana(Banana h)
+            : base(h)
+        {
+        }
+
+        protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
+    }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
index 739cc6a59b..f039504600 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
@@ -5,9 +5,7 @@ using System;
 using System.Linq;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Judgements;
 using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Scoring;
 
 namespace osu.Game.Rulesets.Catch.Objects.Drawable
 {
@@ -24,15 +22,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
 
             InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
 
-            foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>())
+            foreach (var b in s.NestedHitObjects.Cast<Banana>())
                 AddNested(getVisualRepresentation?.Invoke(b));
         }
 
-        protected override void CheckForJudgements(bool userTriggered, double timeOffset)
-        {
-            if (timeOffset >= 0)
-                AddJudgement(new Judgement { Result = NestedHitObjects.Cast<DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
-        }
+        protected override bool ProvidesJudgement => false;
 
         protected override void AddNested(DrawableHitObject h)
         {
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index e3564b5967..6ce2e6a2ae 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -2,14 +2,14 @@
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
 using System;
+using OpenTK;
+using OpenTK.Graphics;
 using osu.Framework.Graphics;
-using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Catch.Judgements;
 using osu.Game.Rulesets.Objects.Drawables;
 using osu.Game.Rulesets.Objects.Types;
-using OpenTK;
 using osu.Game.Rulesets.Scoring;
 using osu.Game.Skinning;
-using OpenTK.Graphics;
 
 namespace osu.Game.Rulesets.Catch.Objects.Drawable
 {
@@ -58,9 +58,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
             if (CheckPosition == null) return;
 
             if (timeOffset >= 0)
-                AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
+            {
+                var judgement = CreateJudgement();
+                judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
+                AddJudgement(judgement);
+            }
         }
 
+        protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
+
         protected override void SkinChanged(ISkinSource skin, bool allowFallback)
         {
             base.SkinChanged(skin, allowFallback);
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
index 5c8a7c4a7c..11d5ed1f92 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
 using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
 using OpenTK;
 using OpenTK.Graphics;
+using osu.Game.Rulesets.Catch.Judgements;
 
 namespace osu.Game.Rulesets.Catch.Objects.Drawable
 {
@@ -23,6 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
             Masking = false;
         }
 
+        protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
+
         [BackgroundDependencyLoader]
         private void load()
         {
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
new file mode 100644
index 0000000000..2232bb81a7
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
@@ -0,0 +1,19 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using osu.Game.Rulesets.Catch.Judgements;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawable
+{
+    public class DrawableTinyDroplet : DrawableDroplet
+    {
+        public DrawableTinyDroplet(Droplet h)
+            : base(h)
+        {
+            Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
+        }
+
+        protected override CatchJudgement CreateJudgement() => new CatchTinyDropletJudgement();
+    }
+}
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
index 936ab6a9d3..23b620248f 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Replays
                     return;
                 }
 
-                if (h is BananaShower.Banana)
+                if (h is Banana)
                 {
                     // auto bananas unrealistically warp to catch 100% combo.
                     Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
@@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Catch.Replays
                 {
                     switch (nestedObj)
                     {
-                        case BananaShower.Banana _:
+                        case Banana _:
                         case TinyDroplet _:
                         case Droplet _:
                         case Fruit _:
diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
index ce1aee5c34..5b69d836a3 100644
--- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs
@@ -1,10 +1,12 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
+using System;
 using System.Linq;
 using osu.Game.Beatmaps;
 using osu.Game.Rulesets.Catch.Judgements;
 using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Judgements;
 using osu.Game.Rulesets.Scoring;
 using osu.Game.Rulesets.UI;
 
@@ -17,28 +19,57 @@ namespace osu.Game.Rulesets.Catch.Scoring
         {
         }
 
+        private float hpDrainRate;
+
         protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
         {
+            hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
+
             foreach (var obj in beatmap.HitObjects)
             {
                 switch (obj)
                 {
                     case JuiceStream stream:
-                        foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
-                            AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+                        foreach (var nestedObject in stream.NestedHitObjects)
+                            switch (nestedObject)
+                            {
+                                case TinyDroplet _:
+                                    AddJudgement(new CatchTinyDropletJudgement { Result = HitResult.Perfect });
+                                    break;
+                                case Droplet _:
+                                    AddJudgement(new CatchDropletJudgement { Result = HitResult.Perfect });
+                                    break;
+                                case Fruit _:
+                                    AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+                                    break;
+                            }
                         break;
                     case BananaShower shower:
                         foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
-                            AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
-                        AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
+                            AddJudgement(new CatchBananaJudgement { Result = HitResult.Perfect });
                         break;
                     case Fruit _:
                         AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
                         break;
                 }
             }
+        }
 
-            base.SimulateAutoplay(beatmap);
+        private const double harshness = 0.01;
+
+        protected override void OnNewJudgement(Judgement judgement)
+        {
+            base.OnNewJudgement(judgement);
+
+            if (judgement.Result == HitResult.Miss)
+            {
+                if (!judgement.IsBonus)
+                    Health.Value -= hpDrainRate * (harshness * 2);
+                return;
+            }
+
+            if (judgement is CatchJudgement catchJudgement)
+                Health.Value += Math.Max(catchJudgement.HealthIncrease - hpDrainRate, 0) * harshness;
         }
     }
 }
diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
index 52763e09af..1ac052de4d 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs
@@ -38,14 +38,16 @@ namespace osu.Game.Rulesets.Catch.UI
         {
             switch (h)
             {
+                case Banana banana:
+                    return new DrawableBanana(banana);
                 case Fruit fruit:
                     return new DrawableFruit(fruit);
                 case JuiceStream stream:
                     return new DrawableJuiceStream(stream, GetVisualRepresentation);
-                case BananaShower banana:
-                    return new DrawableBananaShower(banana, GetVisualRepresentation);
+                case BananaShower shower:
+                    return new DrawableBananaShower(shower, GetVisualRepresentation);
                 case TinyDroplet tiny:
-                    return new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) };
+                    return new DrawableTinyDroplet(tiny);
                 case Droplet droplet:
                     return new DrawableDroplet(droplet);
             }
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index ceb05d349f..9c376f340a 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures;
 using osu.Framework.Input.Bindings;
 using osu.Framework.MathUtils;
 using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Judgements;
 using osu.Game.Rulesets.Catch.Objects;
 using osu.Game.Rulesets.Catch.Objects.Drawable;
 using osu.Game.Rulesets.Catch.Replays;
@@ -78,12 +79,11 @@ namespace osu.Game.Rulesets.Catch.UI
 
                 if (!fruit.StaysOnPlate)
                     runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
-
             }
 
             if (fruit.HitObject.LastInCombo)
             {
-                if (judgement.IsHit)
+                if (((CatchJudgement)judgement).ShouldExplode)
                     runAfterLoaded(() => MovableCatcher.Explode());
                 else
                     MovableCatcher.Drop();
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
index 9630ba9273..9055e48a4c 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mania.Judgements
     public class HoldNoteJudgement : ManiaJudgement
     {
         public override bool AffectsCombo => false;
+
         protected override int NumericResultFor(HitResult result) => 0;
     }
 }
diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs b/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs
index b7c4470592..26becfdec9 100644
--- a/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs
+++ b/osu.Game.Rulesets.Osu/Judgements/OsuJudgement.cs
@@ -1,7 +1,6 @@
 // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using OpenTK;
 using osu.Game.Rulesets.Judgements;
 using osu.Game.Rulesets.Osu.Objects.Drawables;
 using osu.Game.Rulesets.Scoring;
@@ -12,11 +11,6 @@ namespace osu.Game.Rulesets.Osu.Judgements
     {
         public override HitResult MaxResult => HitResult.Great;
 
-        /// <summary>
-        /// The positional hit offset.
-        /// </summary>
-        public Vector2 PositionOffset;
-
         protected override int NumericResultFor(HitResult result)
         {
             switch (result)
diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs b/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
index c4e265aac9..d52de9f971 100644
--- a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
+++ b/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Osu.Judgements
     public class OsuSliderTailJudgement : OsuJudgement
     {
         public override bool AffectsCombo => false;
+
         protected override int NumericResultFor(HitResult result) => 0;
     }
 }
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index 9fe6dcd46c..421c93d485 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -93,7 +93,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
             AddJudgement(new OsuJudgement
             {
                 Result = result,
-                PositionOffset = Vector2.Zero //todo: set to correct value
             });
         }
 
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index f2d5631e93..04724931ae 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -11,7 +11,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
 using osu.Game.Rulesets.UI;
 using System.Linq;
 using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Osu.Judgements;
 
 namespace osu.Game.Rulesets.Osu.UI
 {
@@ -75,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.UI
             DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
             {
                 Origin = Anchor.Centre,
-                Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset
+                Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
             };
 
             judgementLayer.Add(explosion);
diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs
index 587f2c8d15..129dd07c3e 100644
--- a/osu.Game/Rulesets/Judgements/Judgement.cs
+++ b/osu.Game/Rulesets/Judgements/Judgement.cs
@@ -45,11 +45,15 @@ namespace osu.Game.Rulesets.Judgements
         public double TimeOffset { get; set; }
 
         /// <summary>
-        /// Whether the <see cref="Result"/> should affect the combo portion of the score.
-        /// If false, the <see cref="Result"/> will be considered for the bonus portion of the score.
+        /// Whether the <see cref="Result"/> should affect the current combo.
         /// </summary>
         public virtual bool AffectsCombo => true;
 
+        /// <summary>
+        /// Whether the <see cref="Result"/> should be counted as base (combo) or bonus score.
+        /// </summary>
+        public virtual bool IsBonus => !AffectsCombo;
+
         /// <summary>
         /// The numeric representation for the result achieved.
         /// </summary>
diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
index dd4120f2fb..9e8ea0f7c2 100644
--- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
@@ -261,13 +261,19 @@ namespace osu.Game.Rulesets.Scoring
                         break;
                 }
 
-                baseScore += judgement.NumericResult;
-                rollingMaxBaseScore += judgement.MaxNumericResult;
-
                 JudgedHits++;
             }
-            else if (judgement.IsHit)
-                bonusScore += judgement.NumericResult;
+
+            if (judgement.IsBonus)
+            {
+                if (judgement.IsHit)
+                    bonusScore += judgement.NumericResult;
+            }
+            else
+            {
+                baseScore += judgement.NumericResult;
+                rollingMaxBaseScore += judgement.MaxNumericResult;
+            }
         }
 
         /// <summary>
@@ -280,14 +286,18 @@ namespace osu.Game.Rulesets.Scoring
             HighestCombo.Value = judgement.HighestComboAtJudgement;
 
             if (judgement.AffectsCombo)
+                JudgedHits--;
+
+            if (judgement.IsBonus)
+            {
+                if (judgement.IsHit)
+                    bonusScore -= judgement.NumericResult;
+            }
+            else
             {
                 baseScore -= judgement.NumericResult;
                 rollingMaxBaseScore -= judgement.MaxNumericResult;
-
-                JudgedHits--;
             }
-            else if (judgement.IsHit)
-                bonusScore -= judgement.NumericResult;
         }
 
         private void updateScore()
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index a2ed01f5a7..a993b61e7b 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -158,7 +158,8 @@ namespace osu.Game.Screens.Play
             userAudioOffset.TriggerChange();
 
             ScoreProcessor = RulesetContainer.CreateScoreProcessor();
-            config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
+            if (!ScoreProcessor.Mode.Disabled)
+                config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
 
             Children = new Drawable[]
             {