using UnityEngine;
using System.Collections;

public class PlayerSniper_Movement : MonoBehaviour
{
    // NOTE TO "Drag and Drop" USAGE
    // THIS USES FEET AS A UNIT. FUCKING SUE ME.
    // (1<<8) IS COLLISION MASK FOR WORLD. DEAL.
    // THIS REQUIRES A SPECIFIC PREFAB/GAMEOBJECT LAYOUT. SEE ACCOMPANYING IMAGE.
    // PROBLEMS WITH THE RIFLE? COMMENT OUT "m_rifle" AND "PlayerSniper_Rifle" EVERYWHERE
    // THIS USES NONSTANDARD INPUTS
    //      TurnX = horizontal turning
    //      TurnY = vertical turning
    //      MoveY = forward/back movement
    //      MoveX = strafing movement
    //      Vertical = jump/crouch (+1/-1)
    //      Speed = sprint toggle
    // ALL THE MAGIC IS IN "FindLedge()" AND "FindStep()"
    // THE MAIN LEDGE CHECK IDEA IS IMPLEMENTED THERE.

    // Delegate type for next state
    public delegate void StateDelegate(out StateDelegate nextState);

    protected Transform m_camera;
    protected Vector3 m_head_angle;
    protected Vector3 m_head_offset;
    protected Vector3 m_body_angle;

    protected Vector3 m_head_punch;
    protected Vector3 m_head_punch_actual;
    protected float m_head_punch_angle;

    protected float m_head_fov;
    protected float m_head_fov_actual;
    protected float m_head_fov_offset;

    protected float m_head_bob;
    protected float m_head_bob_actual;
    protected float m_head_bob_counter;
    protected float m_head_bob_speed;

    StateDelegate m_state;

    private bool m_nextUpdateReady;

    protected Vector3 m_turnInput;
    protected Vector3 m_moveInput;
    protected Vector3 m_moveInput_Previous;
    protected Vector3 m_buttonInput;
    protected Vector3 m_buttonInput_Previous;
    protected Vector3 m_buttonInput_Toggle;

    protected float m_currentHeight;

    protected bool  m_grounded;
    protected float m_groundDistance;
    protected Vector3 m_groundNormal;
    protected float m_groundHitSpeed;

    protected Vector3 m_ledgePosition;
    protected Vector3 m_ledgeNormal;
    protected bool m_ledgeClimbable;
    protected float m_ledgeClimbtime;

    protected bool m_plCrouching;
    protected bool m_plSprinting;

    protected float m_turnSpeed;
    protected bool m_turnPersist;
    protected Vector3 m_turnPersistence;

    PlayerSniper_Rifle m_rifle;

	// Initialize system
	void Start ()
    {
        m_camera = transform.Find("Camera");
        m_rifle = transform.Find("Rifle").GetComponent<PlayerSniper_Rifle>();

        m_state = this.Movestate_Walk;

        m_head_angle = new Vector3(0, 0, 0);
        m_body_angle = new Vector3(0, 0, 0);
        m_head_offset = new Vector3(0, 4.4f, 0);

        m_currentHeight = 4.4f;

        m_nextUpdateReady = false;

        m_turnSpeed = 1.0f;
        m_turnPersist = false;
	}

    // Input Step
    void Update()
    {
        Screen.lockCursor = true;
        // Reduce amount of turn values in already
        if (!m_turnPersist)
        {
            m_turnInput.x -= Mathf.Min(Mathf.Abs(m_turnInput.x), Time.deltaTime * 360.0f) * Mathf.Sign(m_turnInput.x);
            m_turnInput.y -= Mathf.Min(Mathf.Abs(m_turnInput.y), Time.deltaTime * 720.0f) * Mathf.Sign(m_turnInput.y);
        }
        // Grab turn input now
        m_turnInput.x -= (Input.GetAxis("TurnY") + (Input.GetAxis("TurnY_JS") * Time.deltaTime * 100)) * 5 * m_turnSpeed;
        m_turnInput.y += (Input.GetAxis("TurnX") + (Input.GetAxis("TurnX_JS") * Time.deltaTime * 100)) * 5 * m_turnSpeed;
        if (m_turnPersist)
        {
            Vector3 t_prevInput = m_turnInput;
            m_turnInput += m_turnPersistence * Time.deltaTime * 4.0f;
            if (t_prevInput.magnitude > m_turnPersistence.magnitude * 0.9f)
            {
                m_turnPersistence = t_prevInput;
            }
            else
            {
                m_turnPersistence -= m_turnPersistence.normalized * Mathf.Min(m_turnPersistence.magnitude, Time.deltaTime * 0.5f);
            }
        }
        else
        {
            m_turnPersistence = Vector3.zero;
        }
        // Grab move input
        if (m_nextUpdateReady)
        {
            m_moveInput_Previous = m_moveInput;
            m_buttonInput_Previous = m_buttonInput;
        }
        m_moveInput = new Vector3(
            Input.GetAxis("MoveY"),
            0,
            -Input.GetAxis("MoveX"));
        if (m_moveInput.magnitude > 1.0f)
        {
            m_moveInput = m_moveInput.normalized;
        }
        m_moveInput.y = Input.GetAxis("Vertical");

        // Grab press input
        float t_nextValue = Input.GetAxis("Speed");
        if (t_nextValue > 0.5f && m_buttonInput.x < 0.5f)
        {
            if (m_buttonInput_Toggle.x < 0.5f)
            {
                m_buttonInput_Toggle.x = 1.0f;
            }
            else
            {
                m_buttonInput_Toggle.x = 0.0f;
            }
        }
        m_buttonInput.x = t_nextValue;
        // Reset speed toggle if no move input
        if (m_moveInput.magnitude < 0.1f || rigidbody.isKinematic || rigidbody.velocity.magnitude < 1.0f)
        {
            m_buttonInput_Toggle.x = 0.0f;
        }

        // Update worked, wait for next physics step
        m_nextUpdateReady = false;

        // Check if grounded
        m_grounded = OnGround(out m_groundDistance, out m_groundNormal);

        // Update transforms now
        SubUpdate();
    }
    // Update transforms
    void SubUpdate()
    {
        // Crouching
        if (m_plCrouching)
        {
            m_currentHeight = 2.0f;
        }
        else
        {
            m_currentHeight = 4.4f;
        }
        float t_dif;
        t_dif = m_currentHeight - m_head_offset.y;
        t_dif = Mathf.Min(Mathf.Abs(t_dif), 10.0f * Time.deltaTime) * Mathf.Sign(t_dif);
        m_head_offset.y += t_dif;
        
        // Work on view punches
        m_head_punch_angle += 180.0f * Time.deltaTime;
        Vector3 t_changeVector;
        float t_changeMagnitude;
        t_changeVector = m_head_punch - m_head_punch_actual;
        t_changeMagnitude = Mathf.Max(t_changeVector.magnitude / 2, Mathf.Min(t_changeVector.magnitude, 25 * Time.deltaTime));
        if (t_changeMagnitude > 0)
        {
            m_head_punch_actual += t_changeVector.normalized * t_changeMagnitude;
        }
        t_changeVector = m_head_punch;
        t_changeMagnitude = Mathf.Min(t_changeVector.magnitude, 25 * Time.deltaTime);
        if (t_changeMagnitude > 0)
        {
            m_head_punch -= t_changeVector.normalized * t_changeMagnitude;
        }
        // Work on field of view
        t_changeMagnitude = Mathf.Min(m_head_fov, m_head_fov_offset) - m_head_fov_actual;
        t_changeMagnitude = Mathf.Max(Mathf.Abs(t_changeMagnitude) / 5, Mathf.Min(Mathf.Abs(t_changeMagnitude), 30 * Time.deltaTime)) * Mathf.Sign(t_changeMagnitude);
        m_head_fov_actual += t_changeMagnitude;
        // Work on head bob
        t_changeMagnitude = m_head_bob - m_head_bob_actual;
        t_changeMagnitude = Mathf.Min(Mathf.Abs(t_changeMagnitude), 10 * Time.deltaTime) * Mathf.Sign(t_changeMagnitude);
        m_head_bob_actual += t_changeMagnitude;
        m_head_bob_counter += m_head_bob_speed * Time.deltaTime * 3.14f;
        Vector3 t_headBob = new Vector3(Mathf.Sin(m_head_bob_counter*0.5f) * 0.1f, Mathf.Cos(m_head_bob_counter) * 0.1f, 0);
        t_headBob *= m_head_bob_actual;

        // Move the camera and set body rots
        transform.rotation = Quaternion.Euler(m_body_angle);
        m_camera.rotation = transform.rotation * Quaternion.Euler(m_head_angle + Quaternion.Euler(0, 0, m_head_punch_angle) * m_head_punch_actual * 0.5f + m_head_punch_actual * 0.5f);
        m_camera.position = transform.position + transform.rotation * (m_head_offset + t_headBob);
        m_camera.camera.fieldOfView = 80 + m_head_fov_actual;
    }

    // Physics Step
	void FixedUpdate ()
    {
        // Perform step update
        StateDelegate nextState = null;
        this.m_state(out nextState);
        m_state = nextState;
        m_nextUpdateReady = true;
	}

    // Punch the view via external input
    public void PunchView(Vector3 n_punchVal)
    {
        m_head_punch += n_punchVal;
    }
    // Punch the view via external input
    public void KickView(Vector3 n_kickVal)
    {
        m_head_angle += n_kickVal;
    }
    // Set turn speed via external input
    public void SetTurnSpeed(float n_turnSpeed)
    {
        m_turnSpeed = n_turnSpeed;
    }
    // Set the fov zoom offset via external input
    public void SetZoomOffset(float n_fov_offset)
    {
        m_head_fov_offset = n_fov_offset;
    }
    // Set if the turning persists
    public void SetTurnPersist(bool n_persist)
    {
        m_turnPersist = n_persist;
    }

    // Check on ground
    bool OnGround(out float o_groundDistance, out Vector3 o_groundNormal)
    {
        // Raytrace downwards for the ground
        const float t_offset = 0.1f;
        const float t_traceDist = 10.0f;
        RaycastHit  t_hitInfo;
        if (Physics.Raycast(transform.position + new Vector3(0, t_offset, 0), Vector3.down, out t_hitInfo, t_traceDist + t_offset, (1 << 8)))
        {
            o_groundDistance = t_hitInfo.distance;
            o_groundNormal = t_hitInfo.normal;
            if (t_hitInfo.distance > t_offset * 1.2f)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
 
        o_groundDistance = t_traceDist;
        o_groundNormal = Vector3.up;

        return false;
    }
    // Check for ledge
    bool FindLedge(out Vector3 o_ledgePosition, out Vector3 o_wallNormal, out bool o_climbable, float n_grabMax, float n_grabMin)
    {
        o_ledgePosition = Vector3.zero;
        o_wallNormal = Vector3.up;
        o_climbable = false;

        // Raytrace forwards for a wall
        float t_grabMax = n_grabMax;
        float t_grabMin = n_grabMin;
        const float t_offset = 0.1f;
        const float t_traceDist = 10.0f;
        Vector3 t_traceStart = transform.position + new Vector3(0, m_currentHeight - t_offset, 0);
        RaycastHit t_hitInfo;
        if (Physics.Raycast(t_traceStart, transform.rotation * Vector3.forward, out t_hitInfo, t_traceDist)) // again, all colliders and layers for now
        {
            o_wallNormal = t_hitInfo.normal;
            // We hit a wall. Is it close enough
            if (t_hitInfo.distance < 2.0f && t_hitInfo.distance > 0.1f)
            {
                // Sure is, let's check for that ledge
                RaycastHit t_hitInfo_Ledge;
                if (Physics.Raycast(
                    t_traceStart + (transform.rotation * Vector3.forward * (t_hitInfo.distance + t_offset)) + new Vector3(0, t_grabMax + t_offset, 0),
                    Vector3.down,
                    out t_hitInfo_Ledge,
                    t_grabMax-t_grabMin+t_offset*2,
                    (1<<8)
                    ))
                {
                    //
                    if (t_hitInfo_Ledge.distance < t_grabMax - t_grabMin)
                    {
                        //o_ledgePosition = new Vector3(t_hitInfo.point.x, t_hitInfo_Ledge.point.y, t_hitInfo.point.z);
                        o_ledgePosition = new Vector3(t_hitInfo_Ledge.point.x, t_hitInfo_Ledge.point.y, t_hitInfo_Ledge.point.z);
                        o_climbable = true;
                        return true;
                    }
                }
            }
        }
        return false;
    }
    // Check for step
    bool FindStep(out Vector3 o_ledgePosition, out Vector3 o_wallNormal, out bool o_climbable, float n_grabMax, float n_grabMin)
    {
        o_ledgePosition = Vector3.zero;
        o_wallNormal = Vector3.up;
        o_climbable = false;

        // Raytrace forwards for a wall
        float t_grabMax = n_grabMax;
        float t_grabMin = n_grabMin;
        const float t_offset = 0.1f;
        const float t_traceDist = 10.0f;
        float t_verticalOffset = Mathf.Min(n_grabMin, (n_grabMax + n_grabMin) / 2);
        Vector3 t_traceStart = transform.position + new Vector3(0, m_currentHeight - t_offset + t_verticalOffset, 0);
        RaycastHit t_hitInfo;
        if (Physics.Raycast(t_traceStart, transform.rotation * Vector3.forward, out t_hitInfo, t_traceDist)) // again, all colliders and layers for now
        {
            o_wallNormal = t_hitInfo.normal;
            // We hit a wall. Is it close enough
            if (t_hitInfo.distance < 2.0f && t_hitInfo.distance > 0.1f)
            {
                // Sure is, let's check for that ledge
                RaycastHit t_hitInfo_Ledge;
                if (Physics.Raycast(
                    t_traceStart + (transform.rotation * Vector3.forward * (t_hitInfo.distance + t_offset)) + new Vector3(0, (t_grabMax - t_verticalOffset) + t_offset, 0),
                    Vector3.down,
                    out t_hitInfo_Ledge,
                    t_grabMax - t_grabMin + t_offset * 2,
                    (1 << 8)
                    ))
                {
                    //
                    if (t_hitInfo_Ledge.distance < t_grabMax - t_grabMin)
                    {
                        //o_ledgePosition = new Vector3(t_hitInfo.point.x, t_hitInfo_Ledge.point.y, t_hitInfo.point.z);
                        o_ledgePosition = new Vector3(t_hitInfo_Ledge.point.x, t_hitInfo_Ledge.point.y, t_hitInfo_Ledge.point.z);
                        o_climbable = true;
                        return true;
                    }
                }
            }
        }
        return false;
    }

    // Walking on ground
    void Movestate_Walk(out StateDelegate nextState)
    {
        // Turn the character
        float turnAmount;
        {
            // Horizontal turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.y), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.y);
            m_body_angle.y += turnAmount;
            m_turnInput.y -= turnAmount;
            // Zero head angle
            turnAmount = Mathf.Min(Mathf.Abs(m_head_angle.y), 90.0f * Time.deltaTime) * Mathf.Sign(m_head_angle.y);
            m_head_angle.y -= turnAmount;
            m_body_angle.y += turnAmount;
            // Vertical turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.x), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.x);
            m_head_angle.x += turnAmount;
            m_turnInput.x -= turnAmount;
            // Limit vertical turning
            m_head_angle.x = Mathf.Min(100, Mathf.Max(-100, m_head_angle.x));
        }

        // Set states
        m_plCrouching = false;
        m_plSprinting = false;
        if (m_buttonInput_Toggle.x > 0.5f)
        {
            m_plSprinting = true;
        }
        if (m_moveInput.y < -0.5f)
        {
            m_plCrouching = true;
            m_plSprinting = false;
        }
        // Reset fall state
        m_groundHitSpeed = 0;
        // Reset bob state
        m_head_bob_speed = 0.1f;
        m_head_bob = 0.0f;
        // Reset rifle state
        m_rifle.SetHoldState(PlayerSniper_Rifle.HoldState.RELAX);

        if (m_grounded)
        {
            // Set velocity
            Vector3 t_moveVector = rigidbody.velocity;
            Vector3 t_groundMoveVector = new Vector3(t_moveVector.x, 0, t_moveVector.z);
            Vector3 t_moveImpulse = new Vector3(m_moveInput.x, 0, m_moveInput.z);

            m_head_bob = t_moveImpulse.magnitude;
            m_head_bob_speed = 4.3f * t_moveImpulse.magnitude;

            float t_moveSpeed = 400;
            m_head_fov = 0;
            if (m_plCrouching)
            {
                t_moveSpeed = 200;
                m_head_fov = -5;
                m_head_bob_speed *= 0.5f;
            }
            if (m_plSprinting)
            {
                t_moveSpeed = 800;
                m_head_fov = 10;
                m_head_bob *= 2.0f;
                m_rifle.SetHoldState(PlayerSniper_Rifle.HoldState.BUSY);
            }

            t_groundMoveVector = transform.rotation * t_moveImpulse * Time.deltaTime * t_moveSpeed;

            t_moveVector.x = t_groundMoveVector.x;
            t_moveVector.z = t_groundMoveVector.z;

            // Jump
            if (m_moveInput.y > 0.5f && m_moveInput_Previous.y < 0.5f)
            {
                t_moveVector.y = 10;
            }

            // Apply changes
            rigidbody.velocity = t_moveVector;

            // Return state
            nextState = this.Movestate_Walk;
            return;
        }
        else
        {
            // Return fall state
            nextState = this.Movestate_Fall;
            return;
        }
    }
    // Falling in air
    void Movestate_Fall(out StateDelegate nextState)
    {
        // Turn the character
        float turnAmount;
        {
            // Horizontal turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.y), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.y);
            m_body_angle.y += turnAmount*0.1f;
            m_head_angle.y += turnAmount*0.4f;
            m_turnInput.y -= turnAmount;
            // Vertical turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.x), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.x);
            m_head_angle.x += turnAmount;
            m_turnInput.x -= turnAmount;
            // Limit vertical turning
            m_head_angle.x = Mathf.Min(100, Mathf.Max(-100, m_head_angle.x));
        }

        // Set states
        m_plCrouching = false;
        m_plSprinting = false;
        // Set fall state
        m_groundHitSpeed = Mathf.Max(-rigidbody.velocity.y, m_groundHitSpeed);
        // Reset bob state
        m_head_bob_speed = 0.1f;
        m_head_bob = 0.0f;
        // Reset rifle state
        m_rifle.SetHoldState(PlayerSniper_Rifle.HoldState.BUSY);

        // Check for ledges
        if (m_moveInput.y > 0.5f)
        {
            if (FindLedge(out m_ledgePosition, out m_ledgeNormal, out m_ledgeClimbable, 1.5f, -1.0f))
            {
                m_groundHitSpeed = 0;
                // Return fall state
                nextState = this.Movestate_Ledgehang;
                return;
            }
            else if (FindStep(out m_ledgePosition, out m_ledgeNormal, out m_ledgeClimbable, -1.0f, -3.5f))
            {
                // Reset climb timer
                m_ledgeClimbtime = 0;
                m_groundHitSpeed = 0;
                // Return climb state
                nextState = this.Movestate_Ledgeclimb;
                return;
            }
        }

        if (!m_grounded)
        {
            // Set velocity
            Vector3 t_moveVector = rigidbody.velocity;
            Vector3 t_groundMoveVector = new Vector3(t_moveVector.x, 0, t_moveVector.z);

            t_groundMoveVector = transform.rotation * new Vector3(m_moveInput.x, 0, m_moveInput.z) * Time.deltaTime * 10;

            t_moveVector.x += t_groundMoveVector.x;
            t_moveVector.z += t_groundMoveVector.z;

            // Apply changes
            rigidbody.velocity = t_moveVector;

            // View zoom
            m_head_fov = m_groundHitSpeed * 0.18f;

            // Return fall state
            nextState = this.Movestate_Fall;
            return;
        }
        else
        {
            // Punch view when hit ground
            Vector3 punchValue = Random.onUnitSphere * (m_groundHitSpeed * m_groundHitSpeed) * 0.02f;
            punchValue.x = Mathf.Abs(punchValue.x) + 0.5f;
            m_head_punch += punchValue;
            Debug.Log(m_groundHitSpeed);
            // Return ground control
            nextState = this.Movestate_Walk;
            return;
        }
    }
    // Ledge hanging
    void Movestate_Ledgehang(out StateDelegate nextState)
    {
        // Turn the head
        float turnAmount;
        {
            // Horizontal turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.y), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.y);
            m_head_angle.y += turnAmount * 0.5f;
            m_turnInput.y -= turnAmount;
            // Limit horizontal turning
            m_head_angle.y = Mathf.Min(60, Mathf.Max(-60, m_head_angle.y));
            // Vertical turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.x), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.x);
            m_head_angle.x += turnAmount * 0.5f;
            m_turnInput.x -= turnAmount;
            // Limit vertical turning
            m_head_angle.x = Mathf.Min(100, Mathf.Max(-100, m_head_angle.x));
        }

        // Set states
        m_plCrouching = false;
        m_plSprinting = false;
        m_head_fov = 0;
        // Reset bob state
        m_head_bob_speed = 0.1f;
        m_head_bob = 0.0f;
        // Reset rifle state
        m_rifle.SetHoldState(PlayerSniper_Rifle.HoldState.BUSY);

        // Zero velocity
        if (!rigidbody.isKinematic)
        {
            rigidbody.velocity = Vector3.zero;
            rigidbody.isKinematic = true;
        }

        transform.position = m_ledgePosition + (m_ledgeNormal * 1.2f) + new Vector3(0, -m_currentHeight, 0);

        // Hit crouch, let go
        if (m_moveInput.y < -0.5f)
        {
            // Return to motion mode
            rigidbody.isKinematic = false;
            // Return ground control
            nextState = this.Movestate_Fall;
            return;
        }
        else if (m_moveInput.y > 0.5f && m_moveInput_Previous.y < 0.5f && m_ledgeClimbable)
        {
            // Return to motion mode
            rigidbody.isKinematic = false;
            // Reset climb time
            m_ledgeClimbtime = 0;
            // Hit jump, climb up
            nextState = this.Movestate_Ledgeclimb;
            return;
        }

        // Return hang more
        nextState = this.Movestate_Ledgehang;
        return;
    }

    // Ledge climbing
    void Movestate_Ledgeclimb(out StateDelegate nextState)
    {
        // Turn the head
        float turnAmount;
        {
            // Horizontal turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.y), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.y);
            m_head_angle.y += turnAmount * 0.5f;
            m_turnInput.y -= turnAmount;
            // Limit horizontal turning
            m_head_angle.y = Mathf.Min(60, Mathf.Max(-60, m_head_angle.y));
            // Vertical turning
            turnAmount = Mathf.Min(Mathf.Abs(m_turnInput.x), 360.0f * Time.deltaTime) * Mathf.Sign(m_turnInput.x);
            m_head_angle.x += turnAmount * 0.5f;
            m_turnInput.x -= turnAmount;
            // Limit vertical turning
            m_head_angle.x = Mathf.Min(100, Mathf.Max(-100, m_head_angle.x));
        }

        // Set states
        m_plCrouching = false;
        m_plSprinting = false;
        m_head_fov = 0;
        // Reset bob state
        m_head_bob_speed = 0.1f;
        m_head_bob = 0.0f;
        // Reset rifle state
        m_rifle.SetHoldState(PlayerSniper_Rifle.HoldState.BUSY);

        // Set velocity to keep going forward and up when still on wall
        if (transform.position.y < m_ledgePosition.y)
        {
            rigidbody.velocity = (Vector3.up + transform.rotation * Vector3.forward) * 1200 * Time.deltaTime;
        }
        else
        {
            m_ledgeClimbtime += Time.deltaTime;
            rigidbody.velocity = (Vector3.down*0.05f + transform.rotation * Vector3.forward) * 400 * Time.deltaTime;
        }

        // Don't stop climbing until on ground
        if (m_grounded || m_ledgeClimbtime > 0.1f)
        {
            rigidbody.velocity = new Vector3(rigidbody.velocity.x * 0.2f, 0, rigidbody.velocity.z * 0.2f);
            // Reset climb time
            m_ledgeClimbtime = 0;
            // Return state
            nextState = this.Movestate_Walk;
            return;
        }

        // Return keep climbing
        nextState = this.Movestate_Ledgeclimb;
        return;
    }
}
