/// <summary>
 /// adds recoil to the weapon springs in response to hitting
 /// something
 /// </summary>
 void ApplyRecoil()
 {
     FPWeapon.StopSprings();
     FPWeapon.AddForce(ImpactPositionSpringRecoil, ImpactRotationSpringRecoil);
     FPWeapon.AddForce2(ImpactPositionSpring2Recoil, ImpactRotationSpring2Recoil);
     Reset();
 }
 /// <summary>
 /// resets the weapon state to normal
 /// </summary>
 void Reset()
 {
     vp_Timer.In(0.05f, delegate()
     {
         if (FPWeapon != null)
         {
             FPWeapon.SetState(WeaponStatePull, false);
             FPWeapon.SetState(WeaponStateSwing, false);
             FPWeapon.Refresh();
             if (AttackPickRandomState)
             {
                 ResetState();
             }
         }
     }, ResetTimer);
 }
    /// <summary>
    /// applies some advanced recoil motions on the weapon when fired
    /// </summary>
    protected override void ApplyRecoil()
    {
        // return the weapon to its forward looking state by certain
        // position, rotation and velocity factors
        FPWeapon.ResetSprings(MotionPositionReset, MotionRotationReset,
                              MotionPositionPause, MotionRotationPause);

        // add a positional and angular force to the weapon for one frame
        if (MotionRotationRecoil.z == 0.0f)
        {
            FPWeapon.AddForce2(MotionPositionRecoil, MotionRotationRecoil);

            // if we have positional camera recoil factor, also shake the camera
            if (MotionPositionRecoilCameraFactor != 0.0f)
            {
                FPCamera.AddForce2(MotionPositionRecoil * MotionPositionRecoilCameraFactor);
            }
        }
        else
        {
            // if we have rotation recoil around the z vector, also do dead zone logic
            FPWeapon.AddForce2(MotionPositionRecoil,
                               Vector3.Scale(MotionRotationRecoil, (Vector3.one + Vector3.back)) + // recoil around x & y
                               (((Random.value < 0.5f) ? Vector3.forward : Vector3.back) *         // spin direction (left / right around z)
                                Random.Range(MotionRotationRecoil.z * MotionRotationRecoilDeadZone,
                                             MotionRotationRecoil.z)));                            // spin force

            // if we have positional camera recoil factor, also shake the camera
            if (MotionPositionRecoilCameraFactor != 0.0f)
            {
                FPCamera.AddForce2(MotionPositionRecoil * MotionPositionRecoilCameraFactor);
            }

            // if we have angular camera recoil factor, also twist the camera left / right
            if (MotionRotationRecoilCameraFactor != 0.0f)
            {
                FPCamera.AddRollForce((Random.Range(MotionRotationRecoil.z * MotionRotationRecoilDeadZone, MotionRotationRecoil.z)      // dead zone
                                       * MotionRotationRecoilCameraFactor) *                                                            // camera rotation factor
                                      ((Random.value < 0.5f) ? 1.0f : -1.0f));                                                          // direction
            }
        }
    }
    /// <summary>
    ///
    /// </summary>
    protected override void OnStart_Attack()
    {
        base.OnStart_Attack();

        // set spawn position for the projectile
        if (Player.IsFirstPerson.Get())
        {
            // in 1st person, don't necessarily fire the projectile from the
            // center of the camera, but perhaps a little bit to the right
            // where the arm would be
            Shooter.m_ProjectileSpawnPoint = FirePosition.gameObject;
            FirePosition.localPosition     = FirePositionOffset;
            FirePosition.localEulerAngles  = Vector3.zero;
        }
        else
        {
            // in 3rd person, always spawn the projectile exactly where the weapon is
            Shooter.m_ProjectileSpawnPoint = Weapon.Weapon3rdPersonModel;
        }

        // don't attempt lookdown adjustments while throwing things (it just gets crazy)
        FPWeapon.LookDownActive = false;                // NOTE: this is restored later

        // as soon as the fire animation has pulled the arm out of sight, perform
        // some tasks in preparation for the next throw
        vp_Timer.In(Shooter.ProjectileSpawnDelay, delegate()
        {
            // unwield or rewield the weapon depending on inventory state
            if (!HaveAmmoForCurrentWeapon)              // if there are no more units of this type to throw ...
            {
                // ... set the 'ReWield' state to avoid popping of the arm ...
                FPWeapon.SetState("ReWield");
                FPWeapon.Refresh();

                vp_Timer.In(1.0f, delegate()
                {
                    if (!Player.SetNextWeapon.Try())                            // ... then try to set the next weapon ...
                    {
                        // ... but if we have no other weapon: instead disarm!
                        vp_Timer.In(0.5f, delegate()
                        {
                            RewindAnimation();
                            Player.SetWeapon.Start(0);
                        }, m_Timer2);
                    }
                });
            }
            else                        // if we DO have additional units like this one	...
            {
                if (Player.IsFirstPerson.Get())
                {
                    // set the 'ReWield' state to avoid popping of the arm
                    FPWeapon.SetState("ReWield");
                    FPWeapon.Refresh();

                    // rewind animation and restore rewield state in 1 sec
                    vp_Timer.In(1.0f, delegate()
                    {
                        RewindAnimation();
                        FPWeapon.Rendering = true;
                        FPWeapon.SetState("ReWield", false);
                        FPWeapon.Refresh();
                    }, m_Timer3);
                }
                else
                {
                    // force-stop the attack activity half a second after the throw
                    vp_Timer.In(0.5f, delegate()
                    {
                        Player.Attack.Stop();
                    }, m_Timer4);
                }
            }
        }, m_Timer1);
    }
    /// <summary>
    /// simulates a melee swing by carrying out a sequence of
    /// timers, state changes and soft forces on the weapon springs
    /// </summary>
    protected void UpdateAttack()
    {
        if (!Player.Attack.Active)
        {
            return;
        }

        if (Player.SetWeapon.Active)
        {
            return;
        }

        if (FPWeapon == null)
        {
            return;
        }

        if (!FPWeapon.Wielded)
        {
            return;
        }

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

        m_NextAllowedSwingTime = Time.time + SwingRate;

        // enable random attack states on the melee and weapon components
        if (AttackPickRandomState)
        {
            PickAttack();
        }

        // set 'raise' state (of the chosen attack state) on the weapon component
        FPWeapon.SetState(WeaponStatePull);
        FPWeapon.Refresh();

        // after a short delay, swing the weapon
        vp_Timer.In(SwingDelay, delegate()
        {
            // play a random swing sound
            if (SoundSwing.Count > 0)
            {
                Audio.pitch = Random.Range(SoundSwingPitch.x, SoundSwingPitch.y) * Time.timeScale;
                Audio.clip  = (AudioClip)SoundSwing[(int)Random.Range(0, (SoundSwing.Count))];
                if (vp_Utility.IsActive(gameObject))
                {
                    Audio.Play();
                }
            }

            // switch to the swing state
            FPWeapon.SetState(WeaponStatePull, false);
            FPWeapon.SetState(WeaponStateSwing);
            FPWeapon.Refresh();

            // apply soft forces of the current attack
            FPWeapon.AddSoftForce(SwingPositionSoftForce, SwingRotationSoftForce, SwingSoftForceFrames);

            // check for target impact after a predetermined duration
            vp_Timer.In(ImpactTime, delegate()
            {
                // perform a sphere cast ray from center of controller, at height
                // of camera and along camera angle
                RaycastHit hit;
                Ray ray = new Ray(new Vector3(FPController.Transform.position.x, FPCamera.Transform.position.y,
                                              FPController.Transform.position.z), FPCamera.Transform.forward);

                Physics.Raycast(ray, out hit, (Bullet != null ? Bullet.Range : 2), vp_Layer.Mask.BulletBlockers);

                // hit something: perform impact functionality
                if (hit.collider != null)
                {
                    if (WeaponShooter != null)
                    {
                        WeaponShooter.FirePosition = Camera.main.transform.position;
                        WeaponShooter.TryFire();
                    }
                    ApplyRecoil();
                }
                else
                {
                    // didn't hit anything: carry on swinging until time is up
                    vp_Timer.In(SwingDuration - ImpactTime, delegate()
                    {
                        FPWeapon.StopSprings();
                        Reset();
                    }, SwingDurationTimer);
                }
            }, ImpactTimer);
        }, SwingDelayTimer);
    }