///////////////////////////////////////////////////////////
    // this method handles firing rate, recoil forces and fire
    // sounds for an FPSWeapon. you should call it from the
    // gameplay class handling player input when the player
    // presses the fire button.
    ///////////////////////////////////////////////////////////
    public void Fire()
    {
        if (m_Weapon == null)
        {
            return;
        }

        if (Time.time < m_NextAllowedFireTime)
        {
            return;
        }

        if (AmmoCount < 1)
        {
            DryFire();
            return;
        }

        m_NextAllowedFireTime   = Time.time + ProjectileFiringRate;
        m_NextAllowedReloadTime = Time.time;

        m_AmmoCount--;

        // return the weapon to its forward looking state by certain
        // position, rotation and velocity factors
        m_Weapon.ResetSprings(MotionPositionReset, MotionRotationReset,
                              MotionPositionPause, MotionRotationPause);

        // add a positional and angular force to the weapon for one frame
        m_Weapon.AddForce2(MotionPositionRecoil, MotionRotationRecoil);

        // play shoot sound
        if (audio != null)
        {
            audio.pitch = Random.Range(SoundFirePitch.x, SoundFirePitch.y);
            audio.clip  = SoundFire;
            audio.Play();
            // LORE: we must use 'Play' rather than 'PlayOneShot' for the
            // AudioSource to be regarded as 'isPlaying' which is needed
            // for 'vp_FPSCamera:DeactivateWeaponWhenSilent'
        }

        // spawn projectiles
        for (int v = 0; v < ProjectileCount; v++)
        {
            if (ProjectilePrefab != null)
            {
                GameObject p = null;
                p = (GameObject)Object.Instantiate(ProjectilePrefab, m_Camera.transform.position, m_Camera.transform.rotation);
                p.transform.localScale = new Vector3(ProjectileScale, ProjectileScale, ProjectileScale);                        // preset defined scale

                // apply conical spread as defined in preset
                p.transform.Rotate(0, 0, Random.Range(0, 360));                                                         // first, rotate up to 360 degrees around z for circular spread
                p.transform.Rotate(0, Random.Range(-ProjectileSpread, ProjectileSpread), 0);                            // then rotate around y with user defined deviation
            }
        }

        // spawn shell casing
        if (ShellPrefab != null)
        {
            if (ShellEjectDelay > 0.0f)
            {
                vp_Timer.In(ShellEjectDelay, EjectShell);
            }
            else
            {
                EjectShell();
            }
        }

        // show muzzle flash
        if (m_MuzzleFlashComponent != null)
        {
            m_MuzzleFlashComponent.Shoot();
        }
    }