/// <summary>
 ///
 /// </summary>
 void Follow()
 {
     Agent.stoppingDistance = 3;
     lookToDirection        = false;
     SetCrouch(false);
     Speed             = defaultSpeed;
     Agent.destination = TargetPosition;
     if (Agent.remainingDistance <= 3)
     {
         if (Cover(false, true))
         {
             AgentState = AIAgentState.Covering;
         }
         else
         {
             Look();
         }
         AIWeapon.Fire(bl_AIShooterWeapon.FireReason.Forced);
         SetDebug = 20;
     }
     else
     {
         AgentState = AIAgentState.Following;
         AIWeapon.Fire();
     }
 }
    /// <summary>
    /// If player not in range then the AI patrol in map
    /// </summary>
    void RandomPatrol(bool precision)
    {
        if (death)
        {
            return;
        }

        float pre = PatrolRadius;

        if (precision)
        {
            if (TargetDistance < LookRange)
            {
                if (Target == null)
                {
                    Target = GetNearestPlayer;
                }
                AgentState = AIAgentState.Looking;
                SetDebug   = 23;
            }
            else
            {
                AgentState = AIAgentState.Searching;
                SetDebug   = 16;
            }
            pre = 8;
        }
        else
        {
            AgentState     = AIAgentState.Patroling;
            ForceCoverFire = false;
            SetDebug       = 22;
        }
        lookToDirection   = false;
        AIWeapon.isFiring = false;
        if (!Agent.hasPath || TargetDistance <= 5.2f || (time - lastPathTime) > 7)
        {
            bool    toAnCover       = (Random.Range(0, 20) >= 18);//probability of get a cover point as random destination
            Vector3 randomDirection = TargetPosition + (Random.insideUnitSphere * pre);
            if (toAnCover)
            {
                randomDirection = CoverManager.GetCoverOnRadius(transform, 20).transform.position;
            }
            if (Target == null && m_GameMode == GameMode.FFA)
            {
                randomDirection += m_Transform.localPosition;
            }
            NavMeshHit hit;
            NavMesh.SamplePosition(randomDirection, out hit, pre, 1);
            finalPosition = hit.position;
            lastPathTime  = time + Random.Range(0, 5);
            Speed         = (Random.Range(0, 5) == 3) ? 4 : 6;
            SetCrouch(false);
        }
        else
        {
            SetDebug = 17;
        }
        Agent.SetDestination(finalPosition);
    }
 /// <summary>
 ///
 /// </summary>
 void OnTargetInSight(bool overrideCover)
 {
     if (AgentState == AIAgentState.Following || AIHealth.Health <= 50)
     {
         if (!Cover(overrideCover) || CanCover(17) || AllOrNothing)
         {
             Follow();
             AgentState = AIAgentState.Following;
             SetDebug   = 11;
         }
         else
         {
             if (Target != null)
             {
                 AIWeapon.Fire(bl_AIShooterWeapon.FireReason.OnMove);
             }
             if (!strafing)
             {
                 strafingTime += delta;
                 if (strafingTime >= 5)
                 {
                     strafing = true;
                     Invoke("ResetStrafing", 4);
                 }
                 SetCrouch(true);
                 SetDebug = 12;
             }
             else
             {
                 if (strafingTime > 0)
                 {
                     strafingPosition = m_Transform.localPosition + m_Transform.TransformDirection(m_Transform.localPosition + (Vector3.right * Random.Range(-3, 3)));
                     strafingTime     = 0;
                 }
                 Agent.destination = strafingPosition;
                 SetCrouch(false);
                 SetDebug = 18;
             }
         }
     }
     else if (AgentState == AIAgentState.Covering)
     {
         if (CanCover(5) && TargetDistance >= 7)
         {
             Cover(true);
             SetDebug = 13;
         }
         else
         {
             SetDebug = 14;
         }
     }
     else
     {
         Look();
         SetDebug = 15;
     }
 }
    /// <summary>
    ///
    /// </summary>
    bool Cover(bool overridePoint, bool toTarget = false)
    {
        Transform t = (!toTarget) ? transform : Target;

        if (overridePoint)
        {
            if (Agent.pathStatus == NavMeshPathStatus.PathComplete)
            {
                //look for another cover point
                CoverPoint = CoverManager.GetCloseCover(t, CoverPoint);
            }
        }
        else
        {
            //look for a near cover point
            CoverPoint = CoverManager.GetCloseCover(t);
        }
        if (CoverPoint != null)
        {
            Agent.stoppingDistance = 0.1f;
            Speed = playerInFront ? defaultSpeed : 6;
            Agent.SetDestination(CoverPoint.transform.position);
            AgentState = AIAgentState.Covering;
            CoverTime  = time;
            AIWeapon.Fire(bl_AIShooterWeapon.FireReason.OnMove);
            return(true);
        }
        else
        {
            //if there are not a near cover point
            if (Target != null)
            {
                //follow target
                Agent.SetDestination(Target.position);
                Speed      = playerInFront ? defaultSpeed : 7;
                personal   = true;
                AgentState = AIAgentState.Searching;
            }
            else
            {
                CoverPoint = CoverManager.GetCloseCoverForced(transform);
                Agent.SetDestination(CoverPoint.transform.position);
                Speed = defaultSpeed;
            }
            return(false);
        }
    }
    /// <summary>
    ///
    /// </summary>
    void TargetControll()
    {
        float Distance = bl_UtilityHelper.Distance(Target.position, m_Transform.localPosition);

        if (Distance >= LosseRange)
        {
            if (AgentState == AIAgentState.Following || personal || AgentState == AIAgentState.Searching)
            {
                RandomPatrol(true);
                SetDebug = 7;
            }
            else
            {
                photonView.RPC("ResetTarget", RpcTarget.All);
                RandomPatrol(false);
                AgentState = AIAgentState.Patroling;
                SetDebug   = 8;
            }
            Speed = defaultSpeed;
            if (!AIWeapon.isFiring)
            {
                Anim.SetInteger("UpperState", 4);
            }
        }
        else if (Distance > FollowRange && Distance < LookRange)//look range
        {
            OnTargetInSight(false);
        }
        else if (Distance <= FollowRange)
        {
            Follow();
        }
        else if (Distance < LosseRange)
        {
            OnTargetInSight(true);
        }
        else
        {
            Debug.Log("Unknown state: " + Distance);
            SetDebug = 10;
        }
    }
    /// <summary>
    ///
    /// </summary>
    void SwichCover()
    {
        if (Agent.pathStatus != NavMeshPathStatus.PathComplete)
        {
            return;
        }

        if (SwitchCoverTimes <= 3)
        {
            Cover(true, true);
            SwitchCoverTimes++;
        }
        else
        {
            AgentState = AIAgentState.Following;
            Agent.SetDestination(TargetPosition);
            SwitchCoverTimes = 0;
            AllOrNothing     = true;
        }
    }
    /// <summary>
    /// Force AI to look the target
    /// </summary>
    void Look()
    {
        if (AgentState != AIAgentState.Covering)
        {
            if (lookTime >= 5)
            {
                AgentState = AIAgentState.Following;
                lookTime   = 0;
                return;
            }
            lookTime  += delta;
            AgentState = AIAgentState.Looking;
        }
        Quaternion rotation = Quaternion.LookRotation(TargetPosition - m_Transform.localPosition);

        m_Transform.rotation = Quaternion.Slerp(m_Transform.rotation, rotation, delta * RotationLerp);
        AIWeapon.Fire();
        SetCrouch(playerInFront);
        Speed           = playerInFront ? defaultSpeed : 5.5f;
        lookToDirection = false;
    }
 /// <summary>
 ///
 /// </summary>
 void OnCovering()
 {
     if (Target != null)
     {
         float Distance = TargetDistance;
         if (Distance <= LookRange && playerInFront)//if in look range and in front, start follow him and shot
         {
             if (!strafing)
             {
                 AgentState = AIAgentState.Following;
                 Agent.SetDestination(Target.position);
                 SetDebug = 1;
             }
             else
             {
                 AgentState = AIAgentState.Covering;
                 Agent.SetDestination(strafingPosition);
                 SetDebug = 19;
             }
             AIWeapon.Fire();
         }
         else if (Distance > LosseRange && (time - CoverTime) >= 7)// if out of line of sight, start searching him
         {
             AgentState = AIAgentState.Searching;
             SetCrouch(false);
             AIWeapon.Fire(bl_AIShooterWeapon.FireReason.OnMove);
             SetDebug = 2;
         }
         else if (ForceCoverFire && !ObstacleBetweenTarget)//if in cover and still get damage, start shoot at him
         {
             AIWeapon.Fire(bl_AIShooterWeapon.FireReason.Forced);
             if (CanCover(10))
             {
                 SwichCover();
             }
             SetDebug = 3;
         }
         else if (CanCover(10) && Distance >= 7)
         {
             SwichCover();
             AIWeapon.Fire(bl_AIShooterWeapon.FireReason.OnMove);
             SetDebug = 4;
         }
         else
         {
             if (playerInFront)
             {
                 AIWeapon.Fire();
                 SetDebug = 5;
             }
             else
             {
                 AIWeapon.Fire(bl_AIShooterWeapon.FireReason.Forced);
                 Look();
                 SetCrouch(false);
                 SetDebug = 6;
             }
         }
     }
     if (Agent.pathStatus == NavMeshPathStatus.PathComplete)
     {
         if (CoverPoint != null && CoverPoint.Crouch)
         {
             SetCrouch(true);
         }
     }
     if (lookToDirection)
     {
         LookToHitDirection();
     }
     else
     {
         Quaternion rotation = Quaternion.LookRotation(Target.position - m_Transform.localPosition);
         m_Transform.rotation = Quaternion.Slerp(m_Transform.rotation, rotation, delta * RotationLerp);
     }
 }