public virtual void PlayDeathEffects()
 {
     if (deathSound.Length > 0)
     {
         GetComponent <AudioSource>().PlayOneShot(UtilRandom.RandomFromArray(deathSound) as AudioClip);
     }
 }
    public virtual void PlayGroundLandEffects()
    {
        float time = GameTime.time;

        if (time < nextGroundHitEffect)
        {
            return;
        }
        nextGroundHitEffect = time + 0.333f;

        if (footLandHardSound.Length > 0)
        {
            GetComponent <AudioSource>().PlayOneShot(UtilRandom.RandomFromArray(footLandHardSound) as AudioClip);
        }
        if (landGroundHardParticles)
        {
            landGroundHardParticles.Play();
        }

        // Send the camera info about the footstep for rolling effect.
        PlayerCamera pc = Camera.main.GetComponent <PlayerCamera>();

        if (pc)
        {
            pc.HitGround();
        }
    }
    void HitGround(Collision collision)
    {
        // Don't play this effect too often or while dead.
        if (Time.time < nextGroundHitEffect || isDead)
        {
            return;
        }

        nextGroundHitEffect = Time.time + 0.25f;

        // Only play this effect if we hit the ground hard enough on the local Y axis.
        if ((warp * collision.relativeVelocity).y >= 5.0f)
        {
            // Play a different impact sound depending on hard / soft ground.
            AudioClip[] audioclips = isOnSoftGround ? footLandSoftSound : footLandHardSound;
            if (audioclips.Length > 0)
            {
                GetComponent <AudioSource>().PlayOneShot(UtilRandom.RandomFromArray(audioclips) as AudioClip);
            }

            ParticleSystem system = isOnSoftGround ? landGroundSoftParticles : landGroundHardParticles;
            system.Play();

            // Send camera message we hit the ground so it can play a view punch effect.
            if (playerCamera)
            {
                playerCamera.HitGround();
            }
        }
    }
    public virtual void PlayJumpEffects()
    {
        float time = GameTime.time;

        if (time < nextJumpEffect)
        {
            return;
        }
        nextJumpEffect = time + 0.333f;

        if (jumpSound.Length > 0)
        {
            GetComponent <AudioSource>().PlayOneShot(UtilRandom.RandomFromArray(jumpSound) as AudioClip);
        }
    }
    void DoPlayerDeath(DeathType deathtype)
    {
        if (isDead)
        {
            return;
        }

        if (deathtype == DeathType.Pierce)
        {
            SetState(PlayerState.DeadImpaled);
        }
        else
        {
            SetState(PlayerState.Dead);
        }

        // Send HUD info so it can dim and red the screen.
        if (gameHUD)
        {
            gameHUD.DoPlayerDeath(deathtype);
        }

        // Used for allowing the camera to free rotate if we're falling forever.
        m_diedFromFall = deathtype == DeathType.Fall;

        /*if (deathtype != DeathType.Fall)
         *      resetGravity(true);*/

        // All sorts of different sounds depending on how we died!
        AudioClip[] sounds;
        if (deathtype == DeathType.Pierce)
        {
            sounds = deathSoundImpaled;
        }
        else if (deathtype == DeathType.Fall)
        {
            sounds = deathSoundFall;
        }
        else
        {
            sounds = deathSound;
        }

        if (sounds.Length > 0)
        {
            GetComponent <AudioSource>().PlayOneShot(UtilRandom.RandomFromArray(sounds) as AudioClip, 1.0f);
        }
    }
    private void DoFootsteps()
    {
        // Play footstep effects based on how fast we're moving in our ground normalized plane.
        float speed = GetComponent <Rigidbody>().velocity.magnitude;

        if (speed < footStepMinSpeed)
        {
            return;
        }

        // Next time we play is based on our speed.
        float speedPerMaxSpeed = Mathf.Min(1.0f, speed / maxGroundSpeed);
        float nextFootStep     = lastFootStep + Mathf.Max(footStepMinTime, footStepMaxTime * (1 - speedPerMaxSpeed));

        if (Time.time >= nextFootStep)
        {
            lastFootStep = Time.time;
            swapfoot     = !swapfoot;

            AudioClip[] audioclips = isOnSoftGround ? footStepSoftSound : footStepHardSound;             // Hard or soft material sounds?
            AudioClip   clip       = UtilRandom.RandomFromArray(audioclips) as AudioClip;

            // Play softer/louder depending on current speed.
            float magnitude = 0.5f + speedPerMaxSpeed * 0.5f;

            if (clip != null)
            {
                GetComponent <AudioSource>().PlayOneShot(clip, magnitude);
            }

            ParticleSystem system = isOnSoftGround ? swapfoot ? hitGroundSoftRightParticles : hitGroundSoftLeftParticles : swapfoot ? hitGroundHardRightParticles : hitGroundHardLeftParticles;
            system.Play();

            // Send the camera info about the footstep for rolling effect.
            if (playerCamera)
            {
                playerCamera.DoFootstep(magnitude, swapfoot);
            }
        }
    }
    void DoJump()
    {
        if (Time.time < nextJump)
        {
            return;
        }

        // Allow regular jumping if we're on the ground or we WERE on the ground 0.15 seconds earlier.
        // If we don't then players complained that they seemed to activate the double jump instead of regular jump when near edges.
        if (onGround || Time.time <= lastGroundTime + 0.15f)
        {
            nextJump    = noGroundTime = Time.time + 0.1f;
            nextAirDash = nextJump + 0.1f;

            onGround = false;

            Vector3 vel = GetComponent <Rigidbody>().velocity;

            vel = warp * vel;

            vel.y = Mathf.Max(0.0f, vel.y) + jumpPower;

            vel = Quaternion.Inverse(warp) * vel;

            GetComponent <Rigidbody>().velocity = vel;

            if (jumpSound.Length > 0)
            {
                GetComponent <AudioSource>().PlayOneShot(UtilRandom.RandomFromArray(jumpSound) as AudioClip);
            }

            return;
        }

        // See if we should wall jump.
        if (Time.time >= nextWallJump)
        {
            Vector3 pos     = eyePosition.position;
            Vector3 forward = transform.forward;
            Vector3 down    = -transform.up;

            // Twice, once for each direction (back and forwards).
            for (int i = 0; i < 2; i++)
            {
                // First try at the camera.
                if (TryWallJump(pos, forward))
                {
                    return;
                }

                // Try wall jumping multiple times at different local y levels.
                for (int j = 1; j <= 4; j++)
                {
                    if (TryWallJump(pos + j * 0.2f * down, forward))
                    {
                        return;
                    }
                }

                // Try other direction.
                pos     = eyePosition.position;
                forward = -forward;
            }
        }

        // OK, see if we can double jump?
        if (canUseMidairAbility || cheatInfiniteDoubleJump)
        {
            canUseMidairAbility = false;

            float fwdspeed = Input.GetAxis("Vertical");

            // If not pressing anything just set the y velocity to jump power.
            if (fwdspeed == 0)
            {
                Vector3 vel = GetComponent <Rigidbody>().velocity;

                vel   = warp * vel;
                vel.y = jumpPower;
                vel   = Quaternion.Inverse(warp) * vel;

                GetComponent <Rigidbody>().velocity = vel;
            }
            else
            {
                // If we're holding a direction then it's a bit trickier.
                // We want to give some degree of enhanced control when double jumping without the ability to instantly change directions.
                // So we scale by the dot product between the current movement direction and the desired movement direction.
                // But the scale can never be below 0.5 otherwise we would go no where.
                Quaternion dewarp = Quaternion.Inverse(warp);

                // Always move relative to the camera.
                Vector3 forward = transform.forward;

                // Find out the current movement direction
                Vector3 current_velocity = GetComponent <Rigidbody>().velocity;

                current_velocity = warp * current_velocity;

                // Ignore the warped Y axis.
                current_velocity.y = 0.0f;

                current_velocity = dewarp * current_velocity;

                Vector3 current_dir   = current_velocity.normalized;
                float   current_speed = current_velocity.magnitude;

                Vector3 new_velocity = forward * fwdspeed;
                new_velocity *= Mathf.Max(doubleJumpDirectionChangeAllowance, Vector3.Dot(current_dir, new_velocity));
                new_velocity *= current_speed;

                new_velocity = warp * new_velocity;

                new_velocity.y = jumpPower;

                new_velocity = dewarp * new_velocity;

                GetComponent <Rigidbody>().velocity = new_velocity;
            }

            if (doubleJumpSound)
            {
                GetComponent <AudioSource>().PlayOneShot(doubleJumpSound);
            }
        }
    }