// Normal state
    private int NormalUpdate()
    {
        targetVelocity = Vector2.zero;

        //
        // todo - create weapon classes to define the attack speed, type of attack, etc
        //
        if (CrossPlatformInputManager.GetButton("Attack"))
        {
            // todo - later on we will base this on weapon type
            InventoryItem weapon = inventoryController.GetCurrentWeapon();
            if (weapon.id == 0)
            {
                // Melee Attack
                if (slashCooldownTimer <= 0)
                {
                    MeleeAttack();
                    slashCooldownTimer = slashCooldownTime;
                }
            }
            else if (weapon.id == 1)
            {
                // Range Attack
                if (shootTimer <= 0)
                {
                    RangeAttack();
                    shootTimer = shootTime;
                }
            }
        }

        if (CrossPlatformInputManager.GetButtonUp("ChangeWeapon"))
        {
            inventoryController.ChangeWeapon();
        }

        // Force Move X
        if (forceMoveXTimer > 0)
        {
            forceMoveXTimer -= Time.deltaTime;
            moveX            = forceMoveX;
        }
        else
        {
            // Horizontal Input
            if (CrossPlatformInputManager.GetButton("Horizontal"))
            {
                moveX = Mathf.Sign(CrossPlatformInputManager.GetAxis("Horizontal"));

                if (grounded)
                {
                    animator.SetBool("Running", true);
                }
            }
            else
            {
                moveX = 0;
                animator.SetBool("Running", false);
            }
        }

        if (grounded)
        {
            // Vertical Input
            if (CrossPlatformInputManager.GetButton("Vertical"))
            {
                // todo: manual camera control doesn't work when the player is near the boundaries in the opposite direction
                float verticalCameraOffset = 0f;
                float yInputDir            = Mathf.Sign(CrossPlatformInputManager.GetAxis("Vertical"));
                if (yInputDir < 0)
                {
                    verticalCameraOffset -= 3f;

                    if (!ducking)
                    {
                        Duck();
                    }
                }
                else
                {
                    verticalCameraOffset += 3f;
                }

                cameraController.SetVerticalOffset(verticalCameraOffset);
            }
            else
            {
                cameraController.SetVerticalOffset(0f);

                if (ducking)
                {
                    Unduck();
                }
            }

            animator.SetBool("Jumping", false);

            if (doubleJumpEnabled)
            {
                canDoubleJump = true;
            }
        }
        else if (!grounded && velocity.y < 0)
        {
            // todo - later replace this with falling animation
            animator.SetBool("Running", false);
        }

        // approach the max speed with acceleration or deceleration
        if (Mathf.Abs(horizontalSpeed) > maxHorizontalSpeed && Mathf.Sign(horizontalSpeed) == moveX)
        {
            horizontalSpeed = Mathf.MoveTowards(horizontalSpeed, moveX * maxHorizontalSpeed, horizontalDeceleration * Time.deltaTime);
        }
        else
        {
            horizontalSpeed = Mathf.MoveTowards(horizontalSpeed, moveX * maxHorizontalSpeed, horizontalAcceleration * Time.deltaTime);
        }

        // stop if speed is below the minimum horizontal speed
        if (Mathf.Abs(horizontalSpeed) <= minimumHorizontalSpeed)
        {
            horizontalSpeed = 0.0f;
        }

        // face the correct way
        if (horizontalSpeed != 0 && facingDirection != Mathf.Sign(horizontalSpeed))
        {
            facingDirection = (int)Mathf.Sign(horizontalSpeed);
        }

        // Dashing
        if (CanDash)
        {
            return(dashState);
        }

        modifiedMaxFall = maxFall;

        // Wall Slide
        if (!grounded && moveX == facingDirection)
        {
            WallSlide();
        }

        // Gravity
        ApplyGravity();

        // graceful jump
        if (grounded)
        {
            jumpGraceTimer = jumpGraceTime;

            if (jumpInputBufferTimer > 0)
            {
                Jump();
            }
        }
        else if (jumpGraceTimer > 0)
        {
            jumpGraceTimer -= Time.deltaTime;
        }

        if (jumpInputBufferTimer > 0)
        {
            jumpInputBufferTimer -= Time.deltaTime;
        }

        // variable jumping
        if (jumpVarTimer > 0)
        {
            VariableJump(ref jumpVarTimer);
        }
        else if (secondJumpVarTimer > 0)
        {
            VariableJump(ref secondJumpVarTimer);
        }

        if (CrossPlatformInputManager.GetButtonDown("Jump"))
        {
            jumpInputBufferTimer = jumpInputBufferTime;
            if (jumpGraceTimer > 0)
            {
                Jump();
            }
            else if (!grounded)
            {
                if (WallJumpCheck(facingDirection))
                {
                    WallJump(-facingDirection);
                }
                else if (doubleJumpEnabled && canDoubleJump)
                {
                    SecondJump();
                    canDoubleJump = false;
                }
            }
        }

        targetVelocity.x = horizontalSpeed;

        return(normalState);
    }