public bool Tick(VMEODNCDanceFloorPlugin p)
        {
            var mat = Matrix.CreateRotationZ(-Direction);
            var ctr = new Vector2(p.ScreenWidth, p.ScreenHeight) / 2 + new Vector2(-0.25f);
            var sd  = p.ScreenDiag;
            var sw  = p.ScreenWidth;
            var sh  = p.ScreenHeight;

            switch (Type)
            {
            case VMEODNCParticleType.Line:
                //by default we're an x line, starting from the bottom and going up.
                var base1 = new Vector2(-sd, sd / 2 - Frame);
                var base2 = new Vector2(sd, sd / 2 - Frame);
                base1 = Vector2.Transform(base1, mat) + ctr;
                base2 = Vector2.Transform(base2, mat) + ctr;
                p.DrawOutline(base1, base2, 0);
                p.DrawLine(base1, base2, Color);
                return(Frame < sd);

            case VMEODNCParticleType.Arrow:
                //draws an arrow towards the correct direction
                var arrowr = Frame;
                var arrow  = new Vector2[]
                {
                    new Vector2(0, 16 - arrowr),
                    new Vector2(0, 8 - arrowr),
                    new Vector2(5, 13 - arrowr),
                    new Vector2(-5, 13 - arrowr),

                    new Vector2(0, 9.25f - arrowr),
                    new Vector2(5, 14.25f - arrowr),
                    new Vector2(-5, 14.25f - arrowr)
                }.Select(x => Vector2.Transform(x, mat) + ctr).ToArray();

                p.DrawOutline(arrow[0], arrow[1], 0);
                p.DrawOutline(arrow[1], arrow[2], 0);
                p.DrawOutline(arrow[1], arrow[3], 0);
                p.DrawOutline(arrow[4], arrow[5], 0);
                p.DrawOutline(arrow[4], arrow[6], 0);

                p.DrawLine(arrow[0], arrow[1], Color);
                p.DrawLine(arrow[1], arrow[2], Color);
                p.DrawLine(arrow[1], arrow[3], Color);
                p.DrawLine(arrow[4], arrow[5], Color);
                p.DrawLine(arrow[4], arrow[6], Color);

                return(Frame < (sd + 8));

            case VMEODNCParticleType.Rect:
                //shrinks a rectangle in from the screen edges
                var rect = new Rectangle(Frame, Frame, sw - Frame * 2, sh - Frame * 2);

                p.DrawRect(new Rectangle(rect.Left - 1, rect.Top - 1, 3, rect.Height), 0);
                p.DrawRect(new Rectangle(rect.Right - 2, rect.Top - 1, 3, rect.Height), 0);
                p.DrawRect(new Rectangle(rect.Left - 1, rect.Top - 1, rect.Width, 3), 0);
                p.DrawRect(new Rectangle(rect.Left - 1, rect.Bottom - 2, rect.Width, 3), 0);

                p.DrawRect(new Rectangle(rect.Left, rect.Top, 1, rect.Height), Color);
                p.DrawRect(new Rectangle(rect.Right - 1, rect.Top, 1, rect.Height), Color);
                p.DrawRect(new Rectangle(rect.Left, rect.Top, rect.Width, 1), Color);
                p.DrawRect(new Rectangle(rect.Left, rect.Bottom - 1, rect.Width, 1), Color);
                return(Frame < sw / 2);

            case VMEODNCParticleType.Colder:
                //pulses out from the center, either at the top or bottom of the dance floor
                var fm   = Frame % (sw / 2);
                var ypos = (GroupID % 2 == 0) ? 0 : sh - 2;

                var xp1 = sw / 2 - fm;
                var xp2 = sw / 2 + fm;

                p.DrawRect(new Rectangle(0, ypos, sw, 2), (byte)0);

                p.DrawRect(new Rectangle(xp1 - 1, ypos, 3, 2), (byte)(Color + 1));
                p.DrawRect(new Rectangle(xp2 - 1, ypos, 3, 2), (byte)(Color + 1));

                p.DrawRect(new Rectangle(xp1, ypos, 1, 2), (byte)(Color));
                p.DrawRect(new Rectangle(xp2, ypos, 1, 2), (byte)(Color));

                return(Frame < sw * 2);
            }
            return(false);
        }