public override void Finish()
 {
     if (Active)
     {
         CurrentValue = 0;
         DoFlicker();
     }
     ActiveFlickerObjects.Clear();
     InactiveFlickerObjects.Clear();
     base.Finish();
 }
        private void DoFlicker()
        {
            MatrixElementType I = GetEffectValue(0);

            int V = CurrentValue.Limit(0, 255);

            if (V > 0)
            {
                if (!Active)
                {
                    Table.Pinball.Alarms.RegisterIntervalAlarm(RefreshIntervalMs, DoFlicker);
                    Active = true;
                }

                //Effect is active (V>0)
                if (V > 0 && FadeMode == FadeModeEnum.OnOff)
                {
                    V = 255;
                }

                int NumberOfLeds = AreaWidth * AreaHeight;
                int FlickerLeds  = ((int)((double)NumberOfLeds / 100 * Density)).Limit(1, NumberOfLeds);


                int Min = MinFlickerDurationMs;
                int Max = MaxFlickerDurationMs;
                if (Max < Min)
                {
                    int Tmp = Min; Min = Max; Max = Tmp;
                }

                //if (Min != Max && ActiveFlickerObjects.Count.IsBetween(0,FlickerLeds-1))
                //{
                //    int Avg = (Min + Max / 2) - Min;
                //    int NewObjectsAvg = ((FlickerLeds * Avg) - ActiveFlickerObjects.Sum(FO => FO.DurationMs)) / (FlickerLeds - ActiveFlickerObjects.Count);
                //    int NewObjectsAvgChange = Avg - NewObjectsAvg;

                //    if (NewObjectsAvgChange < 0)
                //    {
                //        //Increase min
                //        Min = (Min + Math.Abs(NewObjectsAvgChange) * 2).Limit(Min, Max);

                //    }
                //    else
                //    {
                //        //Decrease max
                //        Max = (Max - NewObjectsAvgChange * 2).Limit(Min, Max);
                //    }
                //}


                while (ActiveFlickerObjects.Count < FlickerLeds && InactiveFlickerObjects.Count > 0)
                {
                    FlickerObject FO = InactiveFlickerObjects[R.Next(InactiveFlickerObjects.Count)];
                    InactiveFlickerObjects.Remove(FO);

                    FO.StartTimestamp = DateTime.Now;
                    FO.DurationMs     = R.Next(Min, Max) + FlickerFadeDownDurationMs;
                    ActiveFlickerObjects.Add(FO);
                }

                DateTime CurrentTimestamp = DateTime.Now;

                for (int i = ActiveFlickerObjects.Count - 1; i >= 0; i--)
                {
                    FlickerObject FO = ActiveFlickerObjects[i];

                    int FV;
                    int AgeMs = (int)(DateTime.Now - FO.StartTimestamp).TotalMilliseconds;
                    if (AgeMs > FO.DurationMs + FlickerFadeDownDurationMs)
                    {
                        if (AgeMs > (FO.DurationMs + FlickerFadeDownDurationMs) * 2 || R.NextDouble() > .5)
                        {
                            //Remove element
                            ActiveFlickerObjects.Remove(FO);
                            InactiveFlickerObjects.Add(FO);
                        }
                        FV = 0;
                    }
                    else if (FlickerFadeUpDurationMs > 0 && AgeMs < FlickerFadeUpDurationMs && AgeMs < FO.DurationMs)
                    {
                        //Fade up
                        FV = (int)((double)V / FlickerFadeUpDurationMs * AgeMs);
                        //Log.Write("U: " + FV.ToString());
                    }
                    else if (AgeMs > FO.DurationMs && FlickerFadeDownDurationMs > 0)
                    {
                        //Fade down
                        if (FO.DurationMs < FlickerFadeUpDurationMs)
                        {
                            FV = (int)((double)V / FlickerFadeUpDurationMs * FO.DurationMs);
                        }
                        else
                        {
                            FV = V;
                        }
                        FV = FV - (int)((double)FV / FlickerFadeDownDurationMs * (AgeMs - FO.DurationMs));
                        //Log.Write("D: " + FV.ToString());
                    }
                    else
                    {
                        //Full on
                        FV = V;

                        //Log.Write("F: " + FV.ToString());
                    }
                    FV = FV.Limit(0, 255);

                    MatrixLayer[FO.X, FO.Y] = GetEffectValue(FV);
                }
            }
            else
            {
                foreach (FlickerObject FO in ActiveFlickerObjects)
                {
                    MatrixLayer[FO.X, FO.Y] = I;
                }
                InactiveFlickerObjects.AddRange(ActiveFlickerObjects);
                ActiveFlickerObjects.Clear();
                Table.Pinball.Alarms.UnregisterIntervalAlarm(DoFlicker);
                Active = false;
            }
        }