// INTERNALS

    private void InternalSetResults(tnSubbuteoMatchController i_MathController)
    {
        if (i_MathController == null)
        {
            return;
        }

        // Team 0

        tnSubbuteoMatchTeamResults teamResults0 = (tnSubbuteoMatchTeamResults)i_MathController.GetTeamResultsByIndex(0);

        if (teamResults0 != null)
        {
            int        teamId0   = teamResults0.id;
            tnTeamData teamData0 = tnGameData.GetTeamDataMain(teamId0);

            if (m_Team0Flag != null)
            {
                m_Team0Flag.sprite = teamData0.flag;
            }

            if (m_Team0Name != null)
            {
                m_Team0Name.text = teamData0.name;
            }

            if (m_Team0Score != null)
            {
                m_Team0Score.text = teamResults0.score.ToString();
            }
        }

        // Team 1

        tnSubbuteoMatchTeamResults teamResults1 = (tnSubbuteoMatchTeamResults)i_MathController.GetTeamResultsByIndex(1);

        if (teamResults1 != null)
        {
            int        teamId1   = teamResults1.id;
            tnTeamData teamData1 = tnGameData.GetTeamDataMain(teamId1);

            if (m_Team1Flag != null)
            {
                m_Team1Flag.sprite = teamData1.flag;
            }

            if (m_Team1Name != null)
            {
                m_Team1Name.text = teamData1.name;
            }

            if (m_Team1Score != null)
            {
                m_Team1Score.text = teamResults1.score.ToString();
            }
        }
    }
    // FUNCTORS

    private static int SortFunctor(tnTeamResults i_Res1, tnTeamResults i_Res2)
    {
        tnSubbuteoMatchTeamResults results1 = (tnSubbuteoMatchTeamResults)i_Res1;
        tnSubbuteoMatchTeamResults results2 = (tnSubbuteoMatchTeamResults)i_Res2;

        if (results1.score > results2.score) return -1;
        if (results1.score < results2.score) return 1;

        return 0;
    }
    // tnBaseMatchController's interface

    protected override bool Draw()
    {
        bool retValue = true;

        for (int teamIndex = 0; teamIndex < teamsCount - 1; ++teamIndex)
        {
            tnSubbuteoMatchTeamResults resultsA = (tnSubbuteoMatchTeamResults)GetTeamResultsByIndex(teamIndex);
            tnSubbuteoMatchTeamResults resultsB = (tnSubbuteoMatchTeamResults)GetTeamResultsByIndex(teamIndex + 1);

            if (resultsA == null)
                continue;

            if (resultsB == null)
                continue;

            bool draw = (resultsA.score == resultsB.score);
            retValue &= draw;
        }

        return retValue;
    }
    // LOGIC

    public void Config(tnSubbuteoMatchController i_Controller)
    {
        if (viewInstance != null)
        {
            if (i_Controller == null)
            {
                return;
            }

            // Team 0

            tnSubbuteoMatchTeamResults teamResults0 = (tnSubbuteoMatchTeamResults)i_Controller.GetTeamResultsByIndex(0);
            if (teamResults0 != null)
            {
                int        teamId0   = teamResults0.id;
                tnTeamData teamData0 = tnGameData.GetTeamDataMain(teamId0);

                string name  = teamData0.name;
                int    score = teamResults0.score;
                Sprite flag  = teamData0.flag;

                viewInstance.SetTeam0(name, score, flag);
            }

            // Team 1

            tnSubbuteoMatchTeamResults teamResults1 = (tnSubbuteoMatchTeamResults)i_Controller.GetTeamResultsByIndex(1);
            if (teamResults1 != null)
            {
                int        teamId1   = teamResults1.id;
                tnTeamData teamData1 = tnGameData.GetTeamDataMain(teamId1);

                string name  = teamData1.name;
                int    score = teamResults1.score;
                Sprite flag  = teamData1.flag;

                viewInstance.SetTeam1(name, score, flag);
            }
        }
    }
    protected override void OnGoal(tnGoalEventParams i_Params)
    {
        base.OnGoal(i_Params);

        int currentTick = TrueSyncManager.ticksMain;

        if (!m_GoalEffectsTicks.Contains(currentTick))
        {
            // Play effects.

            SfxPlayer.PlayMain(m_GoalSfx);

            // Play celebration animation and screen shake.

            tnScreenShake screenShake = null;
            tnGameCamera gameCamera = cameraGo.GetComponent<tnGameCamera>();
            if (gameCamera != null)
            {
                screenShake = gameCamera.GetComponentInChildren<tnScreenShake>();
            }

            if (m_CelebrationPanel != null)
            {
                m_CelebrationPanel.SetCelebrationText(i_Params.scorerId);
                m_CelebrationPanel.StartCelebration();
            }

            if (screenShake != null)
            {
                screenShake.ForceShake(m_CelebrationShakeTime, m_CelebrationShakeAmount, ShakeMode.Interruput);
            }

            m_GoalEffectsTicks.Add(currentTick);
        }

        // Update results.

        for (int teamResultsIndex = 0; teamResultsIndex < teamsCount; ++teamResultsIndex)
        {
            tnSubbuteoMatchTeamResults teamResults = (tnSubbuteoMatchTeamResults)GetTeamResultsByIndex(teamResultsIndex);
            if (teamResults != null)
            {
                if (teamResults.id != i_Params.teamId) // Assign a score to the team.
                {
                    ++teamResults.score;
                }
            }
        }

        if (i_Params.hasValidScorer)
        {
            if (!i_Params.isOwnGoal)
            {
                tnSubbuteoMatchCharacterResults characterResults = (tnSubbuteoMatchCharacterResults)GetCharacterResultsById(i_Params.scorerId);
                if (characterResults != null)
                {
                    ++characterResults.goalScored;
                }
            }
        }
    }
    protected override void OnEndMatch()
    {
        base.OnEndMatch();

        bool online = !PhotonNetwork.offlineMode;
        tnEndMatchEventParams param = new tnEndMatchEventParams(online);

        // Compute human players.

        param.SetGameModeId(gameModeId);
        param.SetBallId(ballId);
        param.SetStadiumId(stadiumId);
        param.SetHasReferee(hasReferee);
        param.SetGoldenGoalEnabled(goldenGoalEnabled);
        param.SetGoldenGoal(goldenGoal);

        tnSubbuteoMatchTeamResults teamAResults = (tnSubbuteoMatchTeamResults)GetTeamResultsByIndex(0);
        if (teamAResults != null)
        {
            param.SetTeamAId(teamAResults.id);
            param.SetScoreA(teamAResults.score);
            param.SetTeamASize(teamAResults.charactersResultsCount);

            int humanPlayers = 0;

            if (!online)
            {
                for (int index = 0; index < teamAResults.charactersResultsCount; ++index)
                {
                    tnCharacterResults characterResults = teamAResults.GetCharacterResults(index);
                    if (characterResults != null)
                    {
                        if (characterResults.isHuman)
                        {
                            ++humanPlayers;
                        }
                    }
                }
            }
            else
            {
                humanPlayers = teamAResults.charactersResultsCount;
            }

            param.SetTeamAHumanPlayers(humanPlayers);
        }

        tnSubbuteoMatchTeamResults teamBResults = (tnSubbuteoMatchTeamResults)GetTeamResultsByIndex(1);
        if (teamBResults != null)
        {
            param.SetTeamBId(teamBResults.id);
            param.SetScoreB(teamBResults.score);
            param.SetTeamBSize(teamBResults.charactersResultsCount);

            int humanPlayers = 0;

            if (!online)
            {
                for (int index = 0; index < teamBResults.charactersResultsCount; ++index)
                {
                    tnCharacterResults characterResults = teamBResults.GetCharacterResults(index);
                    if (characterResults != null)
                    {
                        if (characterResults.isHuman)
                        {
                            ++humanPlayers;
                        }
                    }
                }
            }
            else
            {
                humanPlayers = teamBResults.charactersResultsCount;
            }

            param.SetTeamBHumanPlayers(humanPlayers);
        }

        // Compute local characters and teams.

        for (int index = 0; index < localCharactersCount; ++index)
        {
            GameObject character = GetLocalCharacterByIndex(index);

            if (character == null)
                continue;

            tnCharacterInfo characterInfo = character.GetComponent<tnCharacterInfo>();
            if (characterInfo != null)
            {
                int characterId = characterInfo.characterId;
                int teamId = characterInfo.teamId;

                param.AddLocalCharacter(characterId);
                param.AddLocalTeam(teamId);
            }
        }

        // Raise event.

        Messenger.Broadcast<tnEndMatchEventParams>("MatchEnded", param);
    }