IEnumerator ReloadRoutine()
    {
        hasAttackInterruptReload = false;
        if (!isReloading && CurrentEquippedWeapon.CanReload())
        {
            isReloading = true;
            if (WeaponData != null)
            {
                reloadDuration  = WeaponData.reloadDuration;
                startReloadTime = Time.unscaledTime;
                if (WeaponData.clipOutFx != null && AudioManager.Singleton != null)
                {
                    AudioSource.PlayClipAtPoint(WeaponData.clipOutFx, TempTransform.position, AudioManager.Singleton.sfxVolumeSetting.Level);
                }
                yield return(new WaitForSeconds(reloadDuration));

                if (isServer)
                {
                    var equippedWeapon = CurrentEquippedWeapon;
                    equippedWeapon.Reload();
                    equippedWeapons[selectWeaponIndex] = equippedWeapon;
                    equippedWeapons.Dirty(selectWeaponIndex);
                }
                if (WeaponData.clipInFx != null && AudioManager.Singleton != null)
                {
                    AudioSource.PlayClipAtPoint(WeaponData.clipInFx, TempTransform.position, AudioManager.Singleton.sfxVolumeSetting.Level);
                }
            }
            // If player still attacking, random new attacking action id
            if (isServer && attackingActionId >= 0 && WeaponData != null)
            {
                attackingActionId = WeaponData.GetRandomAttackAnimation().actionId;
            }
            yield return(new WaitForEndOfFrame());

            isReloading = false;
            if (isLocalPlayer)
            {
                // If weapon is reload one ammo at a time (like as shotgun), automatically reload more bullets
                // When there is no attack interrupt while reload
                if (WeaponData != null && WeaponData.reloadOneAmmoAtATime && CurrentEquippedWeapon.CanReload())
                {
                    if (!hasAttackInterruptReload)
                    {
                        Reload();
                    }
                    else
                    {
                        Attack();
                    }
                }
            }
        }
    }
 protected void Reload()
 {
     if (isPlayingAttackAnim || isReloading || !CurrentEquippedWeapon.CanReload())
     {
         return;
     }
     if (isLocalPlayer)
     {
         CmdReload();
     }
 }
    protected void Attack()
    {
        if (isLocalPlayer)
        {
            // If attacking while reloading, determines that it is reload interrupting
            if (isReloading && FinishReloadTimeRate > 0.8f)
            {
                hasAttackInterruptReload = true;
            }
        }
        if (isPlayingAttackAnim || isReloading || !CurrentEquippedWeapon.CanShoot())
        {
            return;
        }

        if (attackingActionId < 0 && isLocalPlayer)
        {
            CmdAttack();
        }
    }
    IEnumerator AttackRoutine(int actionId)
    {
        if (!isPlayingAttackAnim &&
            !isReloading &&
            CurrentEquippedWeapon.CanShoot() &&
            Hp > 0 &&
            characterModel != null &&
            characterModel.TempAnimator != null)
        {
            isPlayingAttackAnim = true;
            var             animator = characterModel.TempAnimator;
            AttackAnimation attackAnimation;
            if (WeaponData != null &&
                WeaponData.AttackAnimations.TryGetValue(actionId, out attackAnimation))
            {
                // Play attack animation
                animator.SetBool("DoAction", false);
                yield return(new WaitForEndOfFrame());

                animator.SetBool("DoAction", true);
                animator.SetInteger("ActionID", attackAnimation.actionId);

                // Wait to launch damage entity
                var speed             = attackAnimation.speed;
                var animationDuration = attackAnimation.animationDuration;
                var launchDuration    = attackAnimation.launchDuration;
                if (launchDuration > animationDuration)
                {
                    launchDuration = animationDuration;
                }
                yield return(new WaitForSeconds(launchDuration / speed));

                // Launch damage entity on server only
                if (isServer)
                {
                    WeaponData.Launch(this, attackAnimation.isAnimationForLeftHandWeapon);
                    var equippedWeapon = CurrentEquippedWeapon;
                    equippedWeapon.DecreaseAmmo();
                    equippedWeapons[selectWeaponIndex] = equippedWeapon;
                    equippedWeapons.Dirty(selectWeaponIndex);
                }

                // Random play shoot sounds
                if (WeaponData.attackFx != null && WeaponData.attackFx.Length > 0 && AudioManager.Singleton != null)
                {
                    AudioSource.PlayClipAtPoint(WeaponData.attackFx[Random.Range(0, WeaponData.attackFx.Length - 1)], TempTransform.position, AudioManager.Singleton.sfxVolumeSetting.Level);
                }

                // Wait till animation end
                yield return(new WaitForSeconds((animationDuration - launchDuration) / speed));
            }
            // If player still attacking, random new attacking action id
            if (isServer && attackingActionId >= 0 && WeaponData != null)
            {
                attackingActionId = WeaponData.GetRandomAttackAnimation().actionId;
            }
            yield return(new WaitForEndOfFrame());

            // Attack animation ended
            animator.SetBool("DoAction", false);
            isPlayingAttackAnim = false;
        }
    }
    protected virtual void UpdateInput()
    {
        if (!isLocalPlayer || Hp <= 0)
        {
            return;
        }

        bool canControl = true;
        var  fields     = FindObjectsOfType <InputField>();

        foreach (var field in fields)
        {
            if (field.isFocused)
            {
                canControl = false;
                break;
            }
        }

        isMobileInput = Application.isMobilePlatform;
#if UNITY_EDITOR
        isMobileInput = GameInstance.Singleton.showJoystickInEditor;
#endif
        InputManager.useMobileInputOnNonMobile = isMobileInput;

        var canAttack = isMobileInput || !EventSystem.current.IsPointerOverGameObject();
        inputMove      = Vector2.zero;
        inputDirection = Vector2.zero;
        inputAttack    = false;
        if (canControl)
        {
            inputMove = new Vector2(InputManager.GetAxis("Horizontal", false), InputManager.GetAxis("Vertical", false));

            // Jump
            if (!inputJump)
            {
                inputJump = InputManager.GetButtonDown("Jump") && isGround && !isDashing;
            }

            // Attack, Can attack while not dashing
            if (!isDashing)
            {
                if (isMobileInput)
                {
                    inputDirection = new Vector2(InputManager.GetAxis("Mouse X", false), InputManager.GetAxis("Mouse Y", false));
                    if (canAttack)
                    {
                        inputAttack = inputDirection.magnitude != 0;
                    }
                }
                else
                {
                    inputDirection = (InputManager.MousePosition() - targetCamera.WorldToScreenPoint(TempTransform.position)).normalized;
                    if (canAttack)
                    {
                        inputAttack = InputManager.GetButton("Fire1");
                    }
                }
                if (InputManager.GetButtonDown("Reload"))
                {
                    Reload();
                }
                if (GameplayManager.Singleton.autoReload &&
                    CurrentEquippedWeapon.currentAmmo == 0 &&
                    CurrentEquippedWeapon.CanReload())
                {
                    Reload();
                }
            }

            // Dash
            if (!isDashing)
            {
                isDashing = InputManager.GetButtonDown("Dash") && isGround;
                if (isDashing)
                {
                    inputAttack   = false;
                    dashInputMove = new Vector2(TempTransform.forward.x, TempTransform.forward.z).normalized;
                    dashingTime   = Time.unscaledTime;
                    CmdDash();
                }
            }
        }
    }