444 lines
14 KiB
C#
444 lines
14 KiB
C#
using System;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
using Random = UnityEngine.Random;
|
|
using UnityEngine.VFX;
|
|
using EZCameraShake;
|
|
using NaughtyAttributes;
|
|
using Util;
|
|
using Weapons;
|
|
|
|
//Thomas09
|
|
[RequireComponent(typeof(Animator))]
|
|
public class WeaponController : MonoBehaviour
|
|
{
|
|
private static readonly int Swing = Animator.StringToHash("Swing");
|
|
private static readonly int Aim = Animator.StringToHash("Aim");
|
|
|
|
#region Variables
|
|
|
|
private readonly RaycastHit[] _results = new RaycastHit[5];
|
|
|
|
private Animator anim;
|
|
|
|
|
|
private Weapon weapon;
|
|
private Camera playerCamera;
|
|
|
|
private Quaternion cameraRecoilRotation;
|
|
|
|
private GameObject sniperModel;
|
|
private GameObject leftArm;
|
|
private GameObject rightArm;
|
|
|
|
private VisualEffect muzzleFlash;
|
|
private ParticleSystem bulletEjection;
|
|
private float aimVelocity;
|
|
|
|
private int weaponID;
|
|
|
|
internal GameObject playTile;
|
|
//Recoil
|
|
[SerializeField] private Transform kickbackPivot;
|
|
private Vector3 positionVelocity;
|
|
private Vector3 rotationVelocity;
|
|
private readonly Color PURPLE = new Color(0.6f, 0.2f, 0.8f, 1f);
|
|
|
|
//crossbow variables
|
|
private CrossbowAnimation crossbow;
|
|
public bool hasAttackEffect = false;
|
|
public bool hasKikBack = true;
|
|
public ParticleSystem visualEffectObject;
|
|
|
|
//
|
|
|
|
private bool isScopped = false;
|
|
#endregion
|
|
|
|
|
|
private void Awake()
|
|
{
|
|
|
|
weapon = OnDemandLoader.Load<Weapon>("config/" + int.Parse(this.gameObject.name));
|
|
weaponID = int.Parse(this.gameObject.name);
|
|
weapon.cachedHorizontalSpread = weapon.horizontalSpread;
|
|
weapon.cachedVerticleSpread = weapon.verticleSpread;
|
|
|
|
if (weapon.isSniper)
|
|
{
|
|
sniperModel = transform.GetChild(0).gameObject;
|
|
leftArm = transform.Find("PlayerArms/left/LeftArmModel").gameObject;
|
|
rightArm = transform.Find("PlayerArms/right/RightArmModel").gameObject;
|
|
|
|
if (transform.Find("PlayTileStart"))
|
|
playTile = transform.Find("PlayTileStart").gameObject;
|
|
}
|
|
|
|
cameraRecoilRotation = new Quaternion(weapon.cameraRecoil[0], weapon.cameraRecoil[1], 0, 0);
|
|
|
|
playerCamera = Player.Instance.transform.Find("FirstPersonCamera_Holder").GetComponentInChildren<Camera>();
|
|
|
|
anim = GetComponent<Animator>();
|
|
Transform muzzleFlashTransform = transform.Find("MuzzleFlash/VFX_MuzzleFlash");
|
|
if (muzzleFlashTransform != null)
|
|
{
|
|
muzzleFlash = muzzleFlashTransform.GetComponent<VisualEffect>();
|
|
if (Player.Instance.PlayerEntity.IsFuturisticWeapon())
|
|
{
|
|
muzzleFlash.SetVector4("Colour", PURPLE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (weaponID != 26) //disregard the crossbow for the muzzleflash.
|
|
//Debug.Log("Muzzle Flash is missing! Did you forget to put it on " + gameObject.name);
|
|
}
|
|
|
|
|
|
Transform bulletEjectionTransform = transform.Find("BulletShell_PS");
|
|
if (bulletEjectionTransform != null)
|
|
{
|
|
bulletEjection = bulletEjectionTransform.GetComponent<ParticleSystem>();
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
crossbow =
|
|
GetComponentInChildren<CrossbowAnimation>(); //most of the time is null. so always check it before using!
|
|
CrosshairManager.Instance.SetSniperCrosshairAlpha(0.0f);
|
|
StartCoroutine(Player.Instance.EquipWeaponCoroutine(weapon, anim, this));
|
|
}
|
|
|
|
internal void PlayAttackLocalEffect()
|
|
{
|
|
visualEffectObject.gameObject.SetActive(true);
|
|
visualEffectObject.Play();
|
|
}
|
|
internal void UnPlayAttackLocalEffect()
|
|
{
|
|
visualEffectObject.Stop();
|
|
}
|
|
void ApplyKickback(GunRecoilConfig recoilParams)
|
|
{
|
|
kickbackPivot.localPosition -= new Vector3(0, 0, recoilParams.zKickback.Sample());
|
|
kickbackPivot.Rotate(recoilParams.xTwist.Sample(), recoilParams.yTwist.Sample(), 0);
|
|
positionVelocity = new Vector3(0, 0, -recoilParams.Push);
|
|
rotationVelocity = Vector3.zero;
|
|
}
|
|
|
|
public void Fire(bool isAimed)
|
|
{
|
|
EmitMuzzleFlash();
|
|
LerpCamera();
|
|
EjectBullet();
|
|
if (hasKikBack) ApplyKickback(isAimed ? weapon.aimedRecoil : weapon.hipFireRecoil);
|
|
ShakeCamera();
|
|
if (crossbow != null) crossbow.FireBow();
|
|
}
|
|
|
|
public void Mining()
|
|
{
|
|
anim.SetBool(Swing, true);
|
|
Debugger.Logger($"{weapon.name} mine swing", ContextDebug.Session, Process.Action);
|
|
}
|
|
|
|
private void EmitMuzzleFlash()
|
|
{
|
|
if (!(weapon.isSniper && Player.Instance.IsAiming) && muzzleFlash != null) muzzleFlash.Play();
|
|
}
|
|
|
|
private void LerpCamera()
|
|
{
|
|
if (weapon.isMeleeFlameAttack)
|
|
return;
|
|
StartCoroutine(LerpCameraRecoil());
|
|
}
|
|
|
|
private void EjectBullet()
|
|
{
|
|
if (bulletEjection != null && (!(weapon.isSniper && Player.Instance.IsAiming)))
|
|
{
|
|
bulletEjection.Play();
|
|
}
|
|
}
|
|
|
|
private void ShakeCamera()
|
|
{
|
|
if (weapon.Magnitude != 0 || weapon.Roughness != 0)
|
|
CameraShaker.Instance.ShakeOnce(weapon.Magnitude, weapon.Roughness, weapon.fadeInTime, weapon.fadeOutTime);
|
|
}
|
|
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
float recoveryTime = Player.Instance.IsAiming
|
|
? weapon.aimedRecoil.recoveryTime
|
|
: weapon.hipFireRecoil.recoveryTime;
|
|
kickbackPivot.localPosition =
|
|
Vector3.SmoothDamp(kickbackPivot.localPosition, Vector3.zero, ref positionVelocity, recoveryTime);
|
|
kickbackPivot.localEulerAngles = Vector3Utility.SmoothDampAngle(kickbackPivot.localEulerAngles, Vector3.zero,
|
|
ref rotationVelocity, recoveryTime);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (Player.Instance.updatePlayer)
|
|
{
|
|
if (playerCamera.gameObject.activeSelf)
|
|
{
|
|
CrosshairManager.Instance.SetDynamicCrossHair(65, 150, 10, 15, Player.Instance, weapon.reticletype,
|
|
weaponID);
|
|
|
|
if (Time.time - Player.Instance.lastReload < Player.Instance.reloadTime)
|
|
{
|
|
if (weapon.isSniper)
|
|
{
|
|
DisableSniperCrosshair();
|
|
}
|
|
|
|
anim.SetBool(Aim, false);
|
|
}
|
|
else
|
|
{
|
|
anim.SetBool(Aim, Player.Instance.IsAiming);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CrosshairManager.Instance.SetDynamicCrossHair(65, 150, 10, 15, Player.Instance,
|
|
WeaponCrosshairType.No_Reticle, weaponID);
|
|
}
|
|
|
|
|
|
if (Player.Instance.IsAiming)
|
|
{
|
|
AimWeapon();
|
|
}
|
|
else
|
|
{
|
|
UnAimTheWeapon();
|
|
}
|
|
}
|
|
|
|
RunState();
|
|
BulletSpreadStates();
|
|
}
|
|
|
|
|
|
private void BulletSpreadStates()
|
|
{
|
|
if (Player.Instance.IsMoving)
|
|
{
|
|
weapon.horizontalSpread = weapon.cachedHorizontalSpread * 2;
|
|
weapon.verticleSpread = weapon.cachedVerticleSpread * 2;
|
|
}
|
|
else if (!Player.Instance.IsAiming && Player.Instance.hasFiredWeapon && !weapon.isShotgun)
|
|
{
|
|
weapon.horizontalSpread = weapon.cachedHorizontalSpread / 2;
|
|
weapon.verticleSpread = weapon.cachedVerticleSpread / 2;
|
|
}
|
|
else if (Player.Instance.IsAiming && !weapon.isShotgun)
|
|
{
|
|
weapon.horizontalSpread = 0.0f;
|
|
weapon.verticleSpread = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
weapon.horizontalSpread = weapon.cachedHorizontalSpread;
|
|
weapon.verticleSpread = weapon.cachedVerticleSpread;
|
|
}
|
|
}
|
|
|
|
private void RunState()
|
|
{
|
|
anim.SetBool("Run", Player.Instance.CanPlayRunningEvents());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Call from miner weapon animation event
|
|
/// </summary>
|
|
public void OnMinerWeaponMineCall()
|
|
{
|
|
bool status = false;
|
|
var playerFirstPersonCamera = Player.Instance.GetPlayerFirstPersonCamera();
|
|
Vector3 screenCenter = new Vector3(Screen.width / 2f, Screen.height / 2f, 0f);
|
|
Ray ray = playerFirstPersonCamera.ScreenPointToRay(screenCenter);
|
|
|
|
float maxDistance = 2.1f;
|
|
var size = Physics.RaycastNonAlloc(ray, _results, maxDistance);
|
|
if (size > 0)
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
RaycastHit hit = _results[i];
|
|
if (hit.collider.CompareTag("Mining"))
|
|
{
|
|
Debugger.Logger("Mine successfully rock founded", ContextDebug.Session, Process.Update);
|
|
|
|
var effector = CallToTryPlayEffector(hit);
|
|
if (effector)
|
|
PacketManager.sendMineRock((int)effector.typeAxe);
|
|
else
|
|
PacketManager.sendMineRock((int)OreItemType.DEFULT);
|
|
var sound = CallToTryPlaySound(effector);
|
|
status = true;
|
|
}
|
|
if(status) break;
|
|
}
|
|
}
|
|
if (!status)
|
|
Debugger.Logger("Mine failed any rock not found", ContextDebug.Session, Process.Info);
|
|
|
|
anim.SetBool(Swing, false);
|
|
|
|
string CallToTryPlaySound(MineEffectorTypingObject type)
|
|
{
|
|
if (type == null) return null;
|
|
|
|
var effect = type.TryGetEffectByName(type.type);
|
|
var soundToPlay = Effect.ChooseRandom(effect.listOfSounds);
|
|
|
|
AudioManager.Instance.playSound(soundToPlay);
|
|
|
|
return soundToPlay;
|
|
}
|
|
MineEffectorTypingObject CallToTryPlayEffector(RaycastHit raycastHit)
|
|
{
|
|
var effectTyping = raycastHit.collider.gameObject.GetComponent<MineEffectorTypingObject>();
|
|
if (effectTyping)
|
|
{
|
|
effectTyping.CreateEffectByRayHit(raycastHit);
|
|
return effectTyping;
|
|
}
|
|
Debugger.Logger("EffectTyping is not on the object of collision", ContextDebug.Session, Process.Info);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void playAnimation(float speedMultiplier, string name)
|
|
{
|
|
//check if you're not currently in reload state.
|
|
if (!anim.GetCurrentAnimatorStateInfo(0).IsName("Reload"))
|
|
{
|
|
if (name.Contains("Reload"))
|
|
{
|
|
anim.speed *= speedMultiplier;
|
|
}
|
|
else
|
|
{
|
|
anim.speed = 1;
|
|
}
|
|
|
|
anim.Play(name);
|
|
}
|
|
}
|
|
|
|
public void SetAnimatorSpeedToDefault()
|
|
{
|
|
anim.speed = 1;
|
|
}
|
|
|
|
private Coroutine enableSniperCrosshairRoutine;
|
|
|
|
private void AimWeapon()
|
|
{
|
|
playerCamera.fieldOfView = Mathf.SmoothDamp(playerCamera.fieldOfView, weapon.scopedFOV, ref aimVelocity,
|
|
weapon.zoomSpeed * 0.025f);
|
|
|
|
if (weapon.isSniper)
|
|
{
|
|
if (Player.Instance.IsAiming && !isScopped)
|
|
{
|
|
isScopped = true;
|
|
|
|
if (enableSniperCrosshairRoutine != null)
|
|
{
|
|
StopCoroutine(enableSniperCrosshairRoutine);
|
|
enableSniperCrosshairRoutine = null;
|
|
}
|
|
|
|
enableSniperCrosshairRoutine = StartCoroutine(EnableSniperCrosshair());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UnAimTheWeapon()
|
|
{
|
|
playerCamera.fieldOfView = Mathf.SmoothDamp(playerCamera.fieldOfView, weapon.normalFOV, ref aimVelocity,
|
|
weapon.zoomSpeed * 0.025f);
|
|
if (weapon.isSniper)
|
|
{
|
|
isScopped = false;
|
|
DisableSniperCrosshair();
|
|
}
|
|
}
|
|
|
|
|
|
private IEnumerator EnableSniperCrosshair()
|
|
{
|
|
yield return new WaitForSeconds(weapon.crosshairChangeTime);
|
|
sniperModel.SetActive(false);
|
|
leftArm.SetActive(false);
|
|
rightArm.SetActive(false);
|
|
CrosshairManager.Instance.SetSniperCrosshair(weapon.reticletype);
|
|
CrosshairManager.Instance.SetSniperCrosshairAlpha(1.0f);
|
|
enableSniperCrosshairRoutine = null;
|
|
}
|
|
|
|
private void DisableSniperCrosshair()
|
|
{
|
|
if (weapon.isSniper)
|
|
{
|
|
CrosshairManager.Instance.SetSniperCrosshairAlpha(0.0f);
|
|
leftArm.SetActive(true);
|
|
rightArm.SetActive(true);
|
|
sniperModel.SetActive(true);
|
|
isScopped = false;
|
|
|
|
if (enableSniperCrosshairRoutine != null)
|
|
{
|
|
StopCoroutine(enableSniperCrosshairRoutine);
|
|
enableSniperCrosshairRoutine = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerator LerpCameraRecoil()
|
|
{
|
|
|
|
|
|
float startTime = Time.time;
|
|
float endTime = startTime + weapon.recoilDuration;
|
|
float yawRecoil = cameraRecoilRotation[0];
|
|
float randomPitch = Random.Range(cameraRecoilRotation[1], Mathf.Abs(cameraRecoilRotation[1]));
|
|
|
|
while (Time.time < endTime)
|
|
{
|
|
Player.Instance.ApplyRecoil(randomPitch,
|
|
yawRecoil * Time.deltaTime *
|
|
65); //const value of 65. To make it normal again. since Time.delaTime makes the values very small.
|
|
yield return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public struct Range
|
|
{
|
|
public float Min;
|
|
public float Max;
|
|
public float Sample() => Random.Range(Min, Max);
|
|
}
|
|
|
|
public static class Vector3Utility
|
|
{
|
|
public static Vector3 SmoothDampAngle(Vector3 from, Vector3 to, ref Vector3 velocity, float smoothTime)
|
|
{
|
|
return new Vector3(
|
|
Mathf.SmoothDampAngle(from.x, to.x, ref velocity.x, smoothTime),
|
|
Mathf.SmoothDampAngle(from.y, to.y, ref velocity.y, smoothTime),
|
|
Mathf.SmoothDampAngle(from.z, to.z, ref velocity.z, smoothTime)
|
|
);
|
|
}
|
|
} |