public Vector2D Add(float f)
 {
     Vector2D result = new Vector2D(this);
     result.x += f;
     result.y += f;
     return (result);
 }
 public Vector2D Add(Vector2D lhs, Vector2D rhs)
 {
     Vector2D result = new Vector2D(lhs);
     result.x += rhs.x;
     result.y += rhs.y;
     return (result);
 }
 public Vector2D Add(Vector2D v)
 {
     Vector2D result = new Vector2D(this);
     result.X += v.X;
     result.Y += v.Y;
     return (result);
 }
 public Vector2D Multiply(Vector2D lhs, double rhs)
 {
     Vector2D result = new Vector2D(lhs);
     result.x *= rhs;
     result.y *= rhs;
     return (result);
 }
 public Vector2D Multiply(double lhs, Vector2D rhs)
 {
     Vector2D result = new Vector2D(rhs);
     result.x *= lhs;
     result.y *= lhs;
     return (result);
 }
 public float Dot(Vector2D v)
 {
     return ((float)(x * v.X + y * v.Y));
 }
 public Vector2D Subtract(Vector2D v)
 {
     Vector2D result = new Vector2D(this);
     result.X -= v.X;
     result.Y -= v.Y;
     return (result);
 }
 public Vector2D(Vector2D v)
 {
     this.x = v.x;
     this.y = v.y;
 }
 public Vector2D Subtract(Vector2D lhs, Vector2D rhs)
 {
     Vector2D result = new Vector2D(lhs);
     result.x -= rhs.x;
     result.y -= rhs.y;
     return (result);
 }
        public Vector2D Normalize()
        {
            float l = Length();
            Vector2D result = new Vector2D(this);
            result.x = result.x / l;
            result.y = result.y / l;

            if (double.IsNaN(result.x) || double.IsNaN(result.y))
                l = l;
            return result;
        }
 public Vector2D Multiply(double d)
 {
     Vector2D result = new Vector2D(this);
     result.x *= d;
     result.y *= d;
     return (result);
 }
        private MoveResult MoveDiscoids()
        {
            if (!started)
                return null;

            MoveResult moveResult = new MoveResult() { DiscoidPositions = new List<DiscoidPosition>(), IsTurnOver = false };

            //Flag indicating that the program is still calculating
            //the positions, that is, the balls are still in an inconsistent state.
            calculatingPositions = true;

            foreach (Discoid discoid in discoids)
            {
                if (Math.Abs(discoid.Position.X) < 5 && Math.Abs(discoid.Position.Y) < 5 && Math.Abs(discoid.TranslateVelocity.X) < 10 && Math.Abs(discoid.TranslateVelocity.Y) < 10)
                {
                    discoid.Position.X =
                    discoid.Position.Y = 0;

                    discoid.TranslateVelocity = new Vector2D(0, 0);
                }
            }

            bool conflicted = true;

            //process this loop as long as some balls are still colliding
            while (conflicted)
            {
                conflicted = false;

                bool someCollision = true;
                while (someCollision)
                {
                    foreach (Goal goal in goals)
                    {
                        bool inGoal = goal.IsBallInGoal(ball);
                    }

                    someCollision = false;
                    foreach (Discoid discoidA in discoids)
                    {
                        if (discoidA is Player)
                        {
                            if (!((Player)discoidA).IsPlaying)
                                break;
                        }

                        //Resolve collisions between balls and each of the 6 borders in the table
                        RectangleCollision borderCollision = RectangleCollision.None;
                        foreach (TableBorder tableBorder in tableBorders)
                        {
                            borderCollision = tableBorder.Colliding(discoidA);

                            //if (borderCollision != RectangleCollision.None && !discoidA.IsBallInGoal)
                            if (borderCollision != RectangleCollision.None)
                            {
                                someCollision = true;
                                tableBorder.ResolveCollision(discoidA, borderCollision);
                            }
                        }

                        //Resolve collisions between players
                        foreach (Discoid discoidB in discoids)
                        {
                            if (discoidB is Player)
                            {
                                if (!((Player)discoidB).IsPlaying)
                                    break;
                            }

                            if (discoidA != discoidB)
                            {
                                //if (discoidA.Colliding(discoidB) && !discoidA.IsBallInGoal && !discoidB.IsBallInGoal)
                                if (discoidA.Colliding(discoidB))
                                {
                                    if ((discoidA is Player && discoidB is Ball) ||
                                        (discoidB is Player && discoidA is Ball))
                                    {
                                        Player p = null;
                                        Ball b = null;
                                        if (discoidA is Player)
                                        {
                                            p = (Player)discoidA;
                                            b = (Ball)discoidB;
                                        }
                                        else
                                        {
                                            p = (Player)discoidB;
                                            b = (Ball)discoidA;
                                        }

                                        turnEvents.Add(new PlayerToBallContact(currentGame.PlayingTeamID, p, new Point(ball.Position.X, ball.Position.Y)));
                                    }
                                    else if (discoidA is Player && discoidB is Player)
                                    {
                                        if (
                                            (((Player)discoidA).Team.TeamID != currentGame.PlayingTeamID) ||
                                            ((Player)discoidB).Team.TeamID != currentGame.PlayingTeamID)
                                        {
                                            PlayerToPlayerContact p2p = new PlayerToPlayerContact(currentGame.PlayingTeamID, (Player)discoidA, (Player)discoidB, new Point(discoidA.Position.X, discoidA.Position.Y));

                                            var q = from te in turnEvents
                                                    where te is PlayerToBallContact
                                                    where ((PlayerToBallContact)te).Player.Team.TeamID == currentGame.PlayingTeamID
                                                    select te;

                                            if (!q.Any())
                                            {
                                                turnEvents.Add(p2p);
                                                Player p = null;
                                                if (((Player)discoidA).Team.TeamID == currentGame.PlayingTeamID)
                                                {
                                                    p = (Player)discoidA;
                                                }
                                                else
                                                {
                                                    p = (Player)discoidB;
                                                }
                                             }
                                        }
                                    }

                                    if (discoidA.Points == 0)
                                    {
                                        strokenPlayers.Add(discoidB);
                                    }
                                    else if (discoidB.Points == 0)
                                    {
                                        strokenPlayers.Add(discoidA);
                                    }

                                    while (discoidA.Colliding(discoidB))
                                    {
                                        someCollision = true;
                                        discoidA.ResolveCollision(discoidB);
                                    }
                                }
                            }
                        }

                        //Calculate ball's translation velocity (movement) as well as the spin velocity.
                        //The friction coefficient is used to decrease ball's velocity
                        if (discoidA.TranslateVelocity.X != 0.0d ||
                            discoidA.TranslateVelocity.Y != 0.0d)
                        {
                            double signalXVelocity = discoidA.TranslateVelocity.X >= 0.0f ? 1.0f : -1.0f;
                            double signalYVelocity = discoidA.TranslateVelocity.Y >= 0.0f ? 1.0f : -1.0f;
                            double absXVelocity = Math.Abs(discoidA.TranslateVelocity.X);
                            double absYVelocity = Math.Abs(discoidA.TranslateVelocity.Y);

                            Vector2D absVelocity = new Vector2D(absXVelocity, absYVelocity);

                            Vector2D normalizedDiff = new Vector2D(absVelocity.X, absVelocity.Y);
                            normalizedDiff.Normalize();

                            absVelocity.X = absVelocity.X * (1.0f - discoidA.Friction) - normalizedDiff.X * discoidA.Friction;
                            absVelocity.Y = absVelocity.Y * (1.0f - discoidA.Friction) - normalizedDiff.Y * discoidA.Friction;

                            if (absVelocity.X < 0f)
                                absVelocity.X = 0f;

                            if (absVelocity.Y < 0f)
                                absVelocity.Y = 0f;

                            double vx = absVelocity.X * signalXVelocity;
                            double vy = absVelocity.Y * signalYVelocity;

                            if (double.IsNaN(vx))
                                vx = 0;

                            if (double.IsNaN(vy))
                                vy = 0;

                            discoidA.TranslateVelocity = new Vector2D(vx, vy);
                        }

                        //Calculate ball's translation velocity (movement) as well as the spin velocity.
                        //The friction coefficient is used to decrease ball's velocity
                        if (discoidA.VSpinVelocity.X != 0.0d || discoidA.VSpinVelocity.Y != 0.0d)
                        {
                            double signalXVelocity = discoidA.VSpinVelocity.X >= 0.0f ? 1.0f : -1.0f;
                            double signalYVelocity = discoidA.VSpinVelocity.Y >= 0.0f ? 1.0f : -1.0f;
                            double absXVelocity = Math.Abs(discoidA.VSpinVelocity.X);
                            double absYVelocity = Math.Abs(discoidA.VSpinVelocity.Y);

                            Vector2D absVelocity = new Vector2D(absXVelocity, absYVelocity);

                            Vector2D normalizedDiff = new Vector2D(absVelocity.X, absVelocity.Y);
                            normalizedDiff.Normalize();

                            absVelocity.X = absVelocity.X - normalizedDiff.X * discoidA.Friction / 1.2f;
                            absVelocity.Y = absVelocity.Y - normalizedDiff.Y * discoidA.Friction / 1.2f;

                            if (absVelocity.X < 0f)
                                absVelocity.X = 0f;

                            if (absVelocity.Y < 0f)
                                absVelocity.Y = 0f;

                            discoidA.VSpinVelocity = new Vector2D(absVelocity.X * signalXVelocity, absVelocity.Y * signalYVelocity);
                        }
                    }

                    //Calculate the ball position based on both the ball's translation velocity and vertical spin velocity.
                    foreach (Discoid discoid in discoids)
                    {
                        discoid.Position.X += discoid.TranslateVelocity.X + discoid.VSpinVelocity.X;
                        discoid.Position.Y += discoid.TranslateVelocity.Y + discoid.VSpinVelocity.Y;
                    }
                }

                conflicted = false;
            }

            double totalVelocity = 0;
            foreach (Discoid discoid in discoids)
            {
                totalVelocity += discoid.TranslateVelocity.X;
                totalVelocity += discoid.TranslateVelocity.Y;
            }

            calculatingPositions = false;

            bool isTurnOver = false;
            if (Math.Abs(totalVelocity) < 0.005 && Math.Abs(lastTotalVelocity) > 0)
            {
                totalVelocity = 0;
                foreach(Discoid d in discoids)
                {
                    d.TranslateVelocity = new Vector2D(0, 0);
                }
                //MoveDiscoids();
                //poolState = PoolState.AwaitingShot;
                if (!goals[0].IsBallInGoal(ball) && !goals[1].IsBallInGoal(ball))
                {
                    ball.IsBallInGoal = false;
                }

                if (Math.Abs(lastTotalVelocity) > 0 && hasPendingGoalResolution)
                {
                    //ResetPlayerPositions(currentGame.Teams[currentGame.Team1ID], currentGame.Teams[currentGame.Team2ID], rootCanvas, discoids, goalPost00Point.X, goalPost10Point.X, rowTopEscapeArea.Height.Value, fieldHeight - rowTopEscapeArea.Height.Value);
                    //ball.X = (goalPost00Point.X + goalPost10Point.X) / 2;
                    //ball.Y = (rowTopEscapeArea.Height.Value + fieldHeight - rowTopEscapeArea.Height.Value) / 2;
                }
                ProcessAfterTurn();
                isTurnOver = true;
                GameHelper.Instance.IsMovingDiscoids = false;

                if (scoreControl.Time > totalTime)
                {
                    Team selectedTeam = currentGame.Team1;
                    currentGame = GetNextGame(selectedTeamID, currentGame.Date);

                    LoadPlayerFaces();
                    ResetPlayerPositions(currentGame.Teams[currentGame.Team1ID], currentGame.Teams[currentGame.Team2ID], rootCanvas, discoids, goalPost00Point.X, goalPost10Point.X, rowTopEscapeArea.Height.Value, fieldHeight - rowTopEscapeArea.Height.Value);

                    scoreControl.Team1Name = currentGame.Team1ID;
                    scoreControl.Team1Score = currentGame.Scores[currentGame.Team1ID];
                    scoreControl.Team2Name = currentGame.Team2ID;
                    scoreControl.Team2Score = currentGame.Scores[currentGame.Team2ID];
                    scoreControl.PlayingTeamID = currentGame.PlayingTeamID;
                    scoreControl.Time = new DateTime(1, 1, 1, 0, 0, 1);

                    ball.ResetPosition();
                    bf.SetValue(Canvas.LeftProperty, ball.Position.X - ball.Radius);
                    bf.SetValue(Canvas.TopProperty, ball.Position.Y - ball.Radius);
                }
            }
            lastTotalVelocity = totalVelocity;

            //playerPositionList = GetBallPositionList();

            return new MoveResult() { DiscoidPositions = moveResult.DiscoidPositions, IsTurnOver = isTurnOver };
        }
        void HitPlayer(double x, double y)
        {
            if (scoreControl.Time.Minute == 0 && scoreControl.Time.Second == 0)
            {
                scoreControl.Time = new DateTime(1, 1, 1, 0, 0, 1);
                clockTimer.Start();
            }

            GameHelper.Instance.IsMovingDiscoids = true;
            turnEvents.Clear();
            foreach (PlayerFace pf in playerFaces)
            {
                pf.UnSelect();
            }

            started = true;

            double ballStrength = 50;

            if (currentGame.Team1ID == currentGame.PlayingTeamID)
            {
                ballStrength = currentGame.Team1BallStrength;
            }
            else
            {
                ballStrength = currentGame.Team2BallStrength;
            }

            double v = (ballStrength / 100.0) * 30.0;

            Player selectedPlayer = GameHelper.Instance.CurrentSelectedPlayer;

            ShowPlayerInfo(selectedPlayer);

            double dx = x - GameHelper.Instance.CurrentSelectedPlayer.Position.X;
            double dy = y - GameHelper.Instance.CurrentSelectedPlayer.Position.Y;
            double h = (float)(Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2)));
            double sin = dy / h;
            double cos = dx / h;
            selectedPlayer.IsBallInGoal = false;
            selectedPlayer.TranslateVelocity = new Vector2D(v * cos, v * sin);
            Vector2D normalVelocity = new Vector2D(selectedPlayer.TranslateVelocity.X, selectedPlayer.TranslateVelocity.Y);
            normalVelocity.Normalize();

            //Calculates the top spin/back spin velocity, in the same direction as the normal velocity, but in opposite angle
            double topBottomVelocityRatio = selectedPlayer.TranslateVelocity.Length() * (targetVector.Y / 100.0f);
            selectedPlayer.VSpinVelocity = new Vector2D(-1.0f * topBottomVelocityRatio * normalVelocity.X, -1.0f * topBottomVelocityRatio * normalVelocity.Y);

            //xSound defines if the sound is coming from the left or the right
            double xSound = (double)(selectedPlayer.Position.X - 300.0f) / 300.0f;

            //CreateSnapshot(GetBallPositionList());

            //if (currentGameState != GameState.TestShot)
            //{
            //    PlayCue(GameSound.Shot01);
            //}

            //Calculates the ball positions as long as there are moving balls
            //MoveBalls();

            fallenBallsProcessed = false;
        }