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("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(); anim = GetComponent(); Transform muzzleFlashTransform = transform.Find("MuzzleFlash/VFX_MuzzleFlash"); if (muzzleFlashTransform != null) { muzzleFlash = muzzleFlashTransform.GetComponent(); 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(); } } private void OnEnable() { crossbow = GetComponentInChildren(); //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()); } /// /// Call from miner weapon animation event /// 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(); 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) ); } }