public void ProgressSliderHandler()
    {
        int            shotIndexInPoint = (int)progressSlider.value;
        ShotDataObject currentShot      = shotDataList[currentShotIndex];

        SetCurrentShot(currentShot.pointBeginningShotIndex + shotIndexInPoint);
    }
    public void SetCurrentShot(int shotIndex)
    {
        currentShotIndex = shotIndex;
        if (currentShotIndex >= shotDataList.Count)
        {
            playing          = false;
            currentShotIndex = 0;
            return;
        }
        currentShotTime = 0;
        ShotDataObject currentShot = shotDataList[currentShotIndex];

        ball.position = currentShot.Evaluate(currentShotTime);
        if (currentShot.shot["category"] == "serve")
        {
            if (playing)
            {
                Serve();
            }
            else
            {
                waitForServe = true;
            }
        }
        else
        {
            GetCurrentPlayerController().shotCallback += delegate()
            {
                StartCoroutine(MakeCurrentPlayerMoveTowardsCenter());
            };
            SetOpponentShot();
        }

        UpdateUI();
    }
 private void Update()
 {
     if (playing && !waitForServe)
     {
         ShotDataObject currentShot = shotDataList[currentShotIndex];
         ball.position = currentShot.Evaluate(currentShotTime);
         //Debug.Log(currentShotTime + "/" + currentShot.shotDuration);
         currentShotTime += Time.deltaTime;
         if (currentShotTime >= currentShot.shotDuration)
         {
             if (currentShot.shot["point"] == "no" && currentShot.shot["error"] == "none")
             {
                 SetCurrentShot(currentShotIndex + 1);
             }
             else
             {
                 if (currentShot.shot["error"] != "none")
                 {
                     PointLost();
                 }
                 else
                 {
                     PointWin();
                 }
             }
             UpdateUI();
         }
     }
 }
 private void SetOpponentShot()
 {
     if (currentShotIndex < shotDataList.Count - 1)
     {
         ShotDataObject currentShot = shotDataList[currentShotIndex];
         if (currentShot.shot["point"] == "no" && currentShot.shot["error"] == "none")
         {
             ShotDataObject         nextShot           = shotDataList[currentShotIndex + 1];
             TennisPlayerController opponentController = GetCurrentOpponentController();
             opponentController.MakeShot(nextShot.startPosition, nextShot.shot["shotType"], currentShot.shotDuration);
         }
     }
 }
    private void PopulateShotList()
    {
        shotDataList.Clear();
        jsonShotToShotData.Clear();

        if (matchJSON != null)
        {
            TennisSim.Utility.RemoveAllChildren(shotListContainer);

            int setNumber = 1;
            foreach (JSONArray setData in matchJSON["sets"])
            {
                CreateListItemText("Set " + setNumber + " (" + setData[0][0] + "/" + setData[0][1] + ")", 0);
                setNumber++;

                int gameNumber = 1;
                foreach (JSONArray gameData in setData[1]["games"])
                {
                    CreateListItemText("Game " + gameNumber + " (" + gameData[0][0] + "/" + gameData[0][1] + ")", 1);
                    gameNumber++;

                    bool oddPoint = false;
                    foreach (JSONArray pointData in gameData[1]["points"])
                    {
                        Button         pointButton   = CreateListItemButton("Point (" + PointsToString(pointData[0][0], pointData[0][1]) + ")", 2).GetComponent <Button>();
                        ShotDataObject beginningShot = null;

                        int shotNumber = 0;
                        int pointBeginningShotIndex = shotDataList.Count;
                        foreach (JSONNode shotData in pointData[1]["shots"])
                        {
                            ShotDataObject shotDataObject = new ShotDataObject();
                            shotDataObject.set                     = setData;
                            shotDataObject.game                    = gameData;
                            shotDataObject.point                   = pointData;
                            shotDataObject.shot                    = shotData;
                            shotDataObject.shotIndexInPoint        = shotNumber;
                            shotDataObject.pointBeginningShotIndex = pointBeginningShotIndex;
                            shotDataObject.oddPoint                = oddPoint;
                            shotDataObject.pointButton             = pointButton;
                            shotNumber++;

                            shotDataList.Add(shotDataObject);
                            jsonShotToShotData.Add(shotData, shotDataObject);
                            if (beginningShot == null)
                            {
                                beginningShot = shotDataObject;
                            }
                        }

                        pointButton.onClick.AddListener(delegate()
                        {
                            SetCurrentShot(beginningShot);
                            Pause();
                        });

                        pointButtons.Add(pointButton);

                        oddPoint = !oddPoint;
                    }
                }
            }
        }

        SetCurrentShot(0);
    }
 public void SetCurrentShot(ShotDataObject shotDataObject)
 {
     SetCurrentShot(shotDataList.IndexOf(shotDataObject));
 }
    private void PickShotStartPosition(ShotDataObject prevShot, ShotDataObject currentShot, PointPicker pointPicker, TennisPlayerController playerController)
    {
        if (prevShot != null)
        {
            float[] xyWeightMultiplier = new float[6];
            float[] heightWeights      = new float[3];
            if (prevShot.shot["category"] == "serve")
            {
                // Current rally can only be around the cross course area.
                xyWeightMultiplier[1] = .9f;
                xyWeightMultiplier[4] = 1;

                if (prevShot.oddPoint)
                {
                    xyWeightMultiplier[0] = .9f;
                    xyWeightMultiplier[3] = .9f;

                    if (prevShot.shot["direction"] == "wide")
                    {
                        xyWeightMultiplier[0] *= 3;
                        xyWeightMultiplier[3] *= 3;
                    }
                }
                else
                {
                    xyWeightMultiplier[2] = .9f;
                    xyWeightMultiplier[5] = .9f;

                    if (prevShot.shot["direction"] == "wide")
                    {
                        xyWeightMultiplier[2] *= 3;
                        xyWeightMultiplier[5] *= 3;
                    }
                }

                if (prevShot.shot["direction"] == "downTheT")
                {
                    xyWeightMultiplier[1] *= 4;
                    xyWeightMultiplier[4] *= 4;
                }
            }
            else
            {
                xyWeightMultiplier[0] = 1;
                xyWeightMultiplier[1] = 1;
                xyWeightMultiplier[2] = 1;
                xyWeightMultiplier[3] = 1;
                xyWeightMultiplier[4] = 1;
                xyWeightMultiplier[5] = 1;

                if (prevShot.shot["direction"] == "right")
                {
                    xyWeightMultiplier[2] *= 1.4f;
                    xyWeightMultiplier[5] *= 1.4f;
                }
                if (prevShot.shot["direction"] == "downTheCourt")
                {
                    xyWeightMultiplier[1] *= 1.4f;
                    xyWeightMultiplier[4] *= 1.4f;
                }
                if (prevShot.shot["direction"] == "left")
                {
                    xyWeightMultiplier[0] *= 1.4f;
                    xyWeightMultiplier[3] *= 1.4f;
                }

                if (currentShot.shot["shotType"] == "forehandGround" || currentShot.shot["shotType"] == "forehandSlice" ||
                    currentShot.shot["shotType"] == "forehandVolley" || currentShot.shot["shotType"] == "forehandLob" ||
                    currentShot.shot["shotType"] == "forehandHalfVolley" || currentShot.shot["shotType"] == "forehandSwingingVolley")
                {
                    xyWeightMultiplier[2] *= 1.4f;
                    xyWeightMultiplier[5] *= 1.4f;
                }
                if (currentShot.shot["shotType"] == "backhandGround" || currentShot.shot["shotType"] == "backhandSlice" ||
                    currentShot.shot["shotType"] == "backhandVolley" || currentShot.shot["shotType"] == "backhandLob" ||
                    currentShot.shot["shotType"] == "backhandHalfVolley" || currentShot.shot["shotType"] == "backhandSwingingVolley")
                {
                    xyWeightMultiplier[0] *= 1.4f;
                    xyWeightMultiplier[3] *= 1.4f;
                }
                if (currentShot.shot["shotType"] == "forehandOverhead" || currentShot.shot["shotType"] == "backhandOverhead")
                {
                    xyWeightMultiplier[0] *= 1.4f;
                    xyWeightMultiplier[1] *= 1.4f;
                    xyWeightMultiplier[2] *= 1.4f;
                }
                if (currentShot.shot["shotType"] == "forehandGround" || currentShot.shot["shotType"] == "backhandGround" ||
                    currentShot.shot["shotType"] == "forehandDropShot" || currentShot.shot["shotType"] == "backhandDropShot")
                {
                    xyWeightMultiplier[3] *= 1.4f;
                    xyWeightMultiplier[4] *= 1.4f;
                    xyWeightMultiplier[5] *= 1.4f;
                }

                if (prevShot.shot["position"] == "approach")
                {
                    xyWeightMultiplier[1] *= 1.4f;
                }
                if (prevShot.shot["position"] == "net")
                {
                    xyWeightMultiplier[1] *= 4f;
                }
                if (prevShot.shot["position"] == "baseline")
                {
                    xyWeightMultiplier[3] *= 2;
                    xyWeightMultiplier[4] *= 2;
                    xyWeightMultiplier[5] *= 2;
                }

                if (prevShot.shot["depth"] == "serviceBox")
                {
                    xyWeightMultiplier[0] *= 4;
                    xyWeightMultiplier[1] *= 4;
                    xyWeightMultiplier[2] *= 4;
                }
                if (prevShot.shot["depth"] == "baseline")
                {
                    xyWeightMultiplier[3] *= 4;
                    xyWeightMultiplier[4] *= 4;
                    xyWeightMultiplier[5] *= 4;
                }

                if (prevShot.shot["shotType"] == "forehandLob" || prevShot.shot["shotType"] == "backhandLob")
                {
                    xyWeightMultiplier[3] *= 2;
                    xyWeightMultiplier[4] *= 2;
                    xyWeightMultiplier[5] *= 2;
                }
            }

            currentShot.shotDuration  = UnityEngine.Random.Range(1.1f, 1.2f);
            currentShot.startPosition = pointPicker.PickRandomWithMultiplier(xyWeightMultiplier);

            if (currentShot.startPosition.y == 0 || currentShot.startPosition.y == float.NaN)
            {
                currentShot.startPosition.y = heightPicker.PickPointByWeights(1, 2, 0).y;
            }
            // We want to pick the exact height because of animation complication.
            // This may change later on.
            currentShot.startPosition.y = playerController.GetShotPoint(currentShot.shot["shotType"]).y;
        }
        else
        {
            // Current shot is a serve
            if (currentShot.oddPoint)
            {
                currentShot.startPosition = pointPicker.PickRandomWithMultiplier(0, 0, 0, 1, 2, 0);
            }
            else
            {
                currentShot.startPosition = pointPicker.PickRandomWithMultiplier(0, 0, 0, 0, 2, 1);
            }
            currentShot.shotDuration    = UnityEngine.Random.Range(.9f, .96f);
            currentShot.startPosition.y = playerController.GetShotPoint("serve").y;
        }
    }
    private void AnalyzeShots()
    {
        for (int i = 0; i < shotDataList.Count; i++)
        {
            PointPicker            playerPointPicker, opponentPointPicker;
            TennisPlayerController playerController, opponentController;
            ShotDataObject         shot = shotDataList[i];
            JSONNode shotJSON           = shot.shot;

            //Debug.Log(shotJSON["player"] + ", " + (shotJSON["player"] == 0));
            if (shotJSON["player"] == 0)
            {
                playerPointPicker   = player1XYPicker;
                opponentPointPicker = player2XYPicker;
                playerController    = player1Controller;
                opponentController  = player2Controller;
            }
            else
            {
                playerPointPicker   = player2XYPicker;
                opponentPointPicker = player1XYPicker;
                playerController    = player2Controller;
                opponentController  = player1Controller;
            }

            if (shotJSON["category"] == "serve")
            {
                PickShotStartPosition(null, shot, playerPointPicker, playerController);
            }

            if (shotJSON["point"] == "no" && shotJSON["error"] == "none")
            {
                ShotDataObject nextShot = shotDataList[i + 1];
                PickShotStartPosition(shot, nextShot, opponentPointPicker, playerController);
                shot.endPosition = nextShot.startPosition;
                if (nextShot.shot["shotType"] == "forehandVolley" || nextShot.shot["shotType"] == "backhandVolley")
                {
                    shot.shotDuration *= .92f;
                    shot.ProcessShotWithoutBounce(netPicker.PickRandomWithMultiplier(.8f, 1));
                }
                else
                {
                    shot.ProcessShotWithBounce(netPicker.PickRandomWithMultiplier(.8f, 1));
                }
            }
            else
            {
                if (shot.shot["error"] == "net")
                {
                    shot.endPosition   = playerPointPicker.PickRandomWithMultiplier(1, 1, 1, 0, 0, 0);
                    shot.endPosition.y = heightPicker.PickRandomWithMultiplier(.03f, 1, 0).y;
                }
                else if (shot.shot["error"] == "wide")
                {
                    // Randomly pick a side to drop the ball out side
                    if (UnityEngine.Random.value > .5f)
                    {
                        shot.endPosition = opponentPointPicker.PickRandomWithMultiplier(1, 0, 0, 1, 0, 0);
                    }
                    else
                    {
                        shot.endPosition = opponentPointPicker.PickRandomWithMultiplier(0, 0, 1, 0, 0, 1);
                    }
                }
                else if (shot.shot["error"] == "deep")
                {
                    shot.endPosition = opponentPointPicker.PickRandomWithMultiplier(0, 0, 0, 1, 1, 1);
                }
                else if (shot.shot["error"] == "wideAndDeep")
                {
                    // Randomly pick a side to drop the ball out side
                    if (UnityEngine.Random.value > .5f)
                    {
                        shot.endPosition = opponentPointPicker.PickPointByWeights(0, 0, 0, 1, 0, 0);
                    }
                    else
                    {
                        shot.endPosition = opponentPointPicker.PickPointByWeights(0, 0, 0, 0, 0, 1);
                    }
                }
                else
                {
                    shot.endPosition = opponentPointPicker.PickRandomWithMultiplier(1, 1, 1, .4f, .4f, .4f);
                }
                if (shot.shot["error"] != "net")
                {
                    shot.ProcessShotWithoutBounce(netPicker.PickRandomWithMultiplier(.8f, 1));
                    shot.shotDuration = UnityEngine.Random.Range(.8f, .85f);
                }
                else
                {
                    Vector3 midPoint = Vector3.Lerp(shot.startPosition, shot.endPosition, .5f) + Vector3.up * UnityEngine.Random.Range(.17f, .41f);
                    shot.ProcessShotWithoutBounce(midPoint);
                    shot.shotDuration = UnityEngine.Random.Range(.37f, .56f);
                    //TennisSim.Utility.LogMultiple(shot.startPosition, midPoint, shot.endPosition);
                }
            }
            //Debug.Log(i + ": " + shot.startPosition + ", " + shot.endPosition);
        }
    }
    public void UpdateUI()
    {
        ShotDataObject currentShot = shotDataList[currentShotIndex];

        progressSlider.maxValue = currentShot.point[1]["shots"].Count;
        progressSlider.value    = currentShot.shotIndexInPoint;

        string matchInfoString = "";

        matchInfoString += "Tournament: \n" + matchJSON["tournament"];
        matchInfoString += "\n";
        matchInfoString += "\n";

        matchInfoString += "Player 1: " + matchJSON["players"][0];
        matchInfoString += "\n";
        matchInfoString += "Match score: " + currentShot.set[0][0];
        matchInfoString += "\n";
        matchInfoString += "Set score: " + currentShot.game[0][0];
        matchInfoString += "\n";
        matchInfoString += "\n";

        matchInfoString += "Player 2: " + matchJSON["players"][1];
        matchInfoString += "\n";
        matchInfoString += "Match score: " + currentShot.set[0][1];
        matchInfoString += "\n";
        matchInfoString += "Set score: " + currentShot.game[0][1];
        matchInfoString += "\n";
        matchInfoString += "\n";

        matchInfoString += "Game score: " + PointsToString(currentShot.point[0][0], currentShot.point[0][1]);
        matchInfoString += "\n";
        matchInfoString += "\n";

        matchInfoString += "Shot by: " + matchJSON["players"][(int)currentShot.shot["player"]];
        matchInfoString += "\n";
        matchInfoString += "Shot type: " + TennisSim.Utility.CapitalizeFirstCharacter(TennisSim.Utility.Decamelize(currentShot.shot["shotType"]));
        matchInfoString += "\n";
        matchInfoString += "Shot category: " + TennisSim.Utility.CapitalizeFirstCharacter(currentShot.shot["category"]);
        matchInfoString += "\n";
        matchInfoString += "Shot depth: " + TennisSim.Utility.CapitalizeFirstCharacter(currentShot.shot["depth"]);
        matchInfoString += "\n";
        matchInfoString += "Shot direction: " + TennisSim.Utility.CapitalizeFirstCharacter(currentShot.shot["direction"]);
        matchInfoString += "\n";
        matchInfoString += "Point: " + TennisSim.Utility.CapitalizeFirstCharacter(TennisSim.Utility.Decamelize(currentShot.shot["point"]));
        matchInfoString += "\n";
        matchInfoString += "Error: " + TennisSim.Utility.CapitalizeFirstCharacter(TennisSim.Utility.Decamelize(currentShot.shot["error"]));
        matchInfoString += "\n";

        matchInfo.text = matchInfoString;

        foreach (Button pointButton in pointButtons)
        {
            ColorBlock temp = pointButton.colors;
            if (pointButton == currentShot.pointButton)
            {
                temp.normalColor = new Color(.106f, 455f, 0);
            }
            else
            {
                temp.normalColor = Color.black;
            }
            pointButton.colors = temp;
        }
    }