From 8b6bc09b8f0c0dd48879fe05adb5f614aeb4dc29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= <dach.bartlomiej@gmail.com>
Date: Mon, 14 Dec 2020 23:02:33 +0100
Subject: [PATCH] Implement drum roll application

---
 .../TestSceneDrumRollApplication.cs           | 39 +++++++++++++++++++
 .../Objects/Drawables/DrawableDrumRoll.cs     | 34 ++++++++++------
 2 files changed, 62 insertions(+), 11 deletions(-)
 create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs

diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs
new file mode 100644
index 0000000000..54450e27db
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs
@@ -0,0 +1,39 @@
+// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Rulesets.Taiko.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Taiko.Tests
+{
+    public class TestSceneDrumRollApplication : HitObjectApplicationTestScene
+    {
+        [Test]
+        public void TestApplyNewDrumRoll()
+        {
+            var drumRoll = new DrawableDrumRoll();
+
+            AddStep("apply new drum roll", () => drumRoll.Apply(PrepareObject(new DrumRoll
+            {
+                StartTime = 300,
+                Duration = 500,
+                IsStrong = false,
+                TickRate = 2
+            }), null));
+
+            AddHitObject(drumRoll);
+            RemoveHitObject(drumRoll);
+
+            AddStep("apply new drum roll", () => drumRoll.Apply(PrepareObject(new DrumRoll
+            {
+                StartTime = 150,
+                Duration = 400,
+                IsStrong = true,
+                TickRate = 16
+            }), null));
+
+            AddHitObject(drumRoll);
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
index 4925b6fdfc..ede7453804 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
@@ -3,6 +3,7 @@
 
 using System;
 using System.Linq;
+using JetBrains.Annotations;
 using osu.Framework.Allocation;
 using osu.Framework.Utils;
 using osu.Game.Graphics;
@@ -31,15 +32,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
         /// </summary>
         private int rollingHits;
 
-        private Container tickContainer;
+        private readonly Container tickContainer;
 
         private Color4 colourIdle;
         private Color4 colourEngaged;
 
-        public DrawableDrumRoll(DrumRoll drumRoll)
+        public DrawableDrumRoll()
+            : this(null)
+        {
+        }
+
+        public DrawableDrumRoll([CanBeNull] DrumRoll drumRoll)
             : base(drumRoll)
         {
             RelativeSizeAxes = Axes.Y;
+
+            Content.Add(tickContainer = new Container
+            {
+                RelativeSizeAxes = Axes.Both,
+                Depth = float.MinValue
+            });
         }
 
         [BackgroundDependencyLoader]
@@ -47,12 +59,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
         {
             colourIdle = colours.YellowDark;
             colourEngaged = colours.YellowDarker;
-
-            Content.Add(tickContainer = new Container
-            {
-                RelativeSizeAxes = Axes.Both,
-                Depth = float.MinValue
-            });
         }
 
         protected override void LoadComplete()
@@ -68,6 +74,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
             updateColour();
         }
 
+        protected override void OnFree()
+        {
+            base.OnFree();
+            rollingHits = 0;
+        }
+
         protected override void AddNestedHitObject(DrawableHitObject hitObject)
         {
             base.AddNestedHitObject(hitObject);
@@ -114,7 +126,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
 
             rollingHits = Math.Clamp(rollingHits, 0, rolling_hits_for_engaged_colour);
 
-            updateColour();
+            updateColour(100);
         }
 
         protected override void CheckForResult(bool userTriggered, double timeOffset)
@@ -156,10 +168,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
 
         protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRoll.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this);
 
-        private void updateColour()
+        private void updateColour(double fadeDuration = 0)
         {
             Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1);
-            (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, 100);
+            (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration);
         }
 
         private class StrongNestedHit : DrawableStrongNestedHit