using System; using System.Collections; using HurricaneVR.Framework.ControllerInput; using HurricaneVR.Framework.Core; using HurricaneVR.Framework.Core.Bags; using HurricaneVR.Framework.Core.Grabbers; using HurricaneVR.Framework.Core.Utils; using HurricaneVR.Framework.Shared; using HurricaneVR.Framework.Weapons; using HurricaneVR.Framework.Weapons.Guns; using UnityEngine; using Zero; public class ShotgunReload : MonoBehaviour { [SerializeField] private HVRGrabbable masterGrabbable; [SerializeField] private Rigidbody rig; [SerializeField] private ConfigurableJoint joint; [SerializeField] private StateReloadShotgun prevState; [SerializeField] private StateReloadShotgun state; [SerializeField] private StateLogicShotgun logicState; [SerializeField] private float maxAngle; [SerializeField] private GameObject stab; [SerializeField] private HVRGunSounds sounds; [SerializeField] private float actualAngle; [SerializeField] private float timeToActionFromAngle = 0.2f; [SerializeField] private HVRGrabbable magazineGrabbable; [SerializeField] private HVRMagazineSocket magazineSocket; [SerializeField] private HVRGrabbableBag magazineBag; [SerializeField] private Transform ejectTransform; [SerializeField] private float impulseEject = 50; [SerializeField] private float delayToActivateGrab; [SerializeField] private HVRGrabbable reloadGrabbable; private bool isPrepareToShoot; public bool IsPrepareToShoot => isPrepareToShoot; private float currentTime; private void Start() { joint = GetComponent(); Closed(); } public void Grab() { isPrepareToShoot = false; prevState = state; state = StateReloadShotgun.InHand; joint.SetAngularXHighLimit(maxAngle); joint.SetAngularXLowLimit(0); if(prevState == StateReloadShotgun.Closed) { sounds.PlaySlideBack(); logicState = StateLogicShotgun.ToOpen; } if(prevState == StateReloadShotgun.Opened) { logicState = StateLogicShotgun.ToClose; } stab.SetActive(false); currentTime = Time.time; } public void Release() { prevState = state; state = StateReloadShotgun.Free; if(prevState is not (StateReloadShotgun.Closed or StateReloadShotgun.Opened)) { joint.SetAngularXHighLimit(maxAngle); joint.SetAngularXLowLimit(0); stab.SetActive(false); } else { if(prevState == StateReloadShotgun.Closed) { Closed(); } if(prevState == StateReloadShotgun.Opened) { Opened(); } } currentTime = Time.time; } public void Closed() { prevState = state; state = StateReloadShotgun.Closed; joint.SetAngularXLowLimit(0); joint.SetAngularXHighLimit(0); stab.SetActive(true); isPrepareToShoot = true; SetEnableMagazineSlot(false); StartCoroutine(Enabled()); IEnumerator Enabled() { reloadGrabbable.enabled = false; yield return new WaitForSeconds(delayToActivateGrab); reloadGrabbable.enabled = true; } logicState = StateLogicShotgun.None; } public void Opened(bool forceEject = false) { isPrepareToShoot = false; prevState = state; state = StateReloadShotgun.Opened; joint.SetAngularXHighLimit(maxAngle); joint.SetAngularXLowLimit(maxAngle - 0.1f); stab.SetActive(false); SetEnableMagazineSlot(true); if(magazineSocket.GrabbedTarget) { var magazine = magazineSocket.GrabbedTarget.GetComponent(); if(magazine) { if(magazine.IsEmpty || forceEject) { magazineSocket.ForceRelease(); var magRig = magazine.GetComponent(); if(magRig) { magRig.AddForce(ejectTransform.forward * impulseEject); } } } } logicState = StateLogicShotgun.None; } public void ChangeAngle(float angle, float b) { if (currentTime + timeToActionFromAngle > Time.time) return; angle = 360 - angle; if(angle >= 360) angle -= 360; actualAngle = angle; if(angle < 10 && logicState == StateLogicShotgun.ToClose) { if(state is StateReloadShotgun.InHand or StateReloadShotgun.Free) { sounds.PlaySlideForward(); Closed(); } } else if(angle > 80 && logicState == StateLogicShotgun.ToOpen) { if(state is StateReloadShotgun.InHand or StateReloadShotgun.Free) { sounds.PlaySlideBack(); Opened(); } } } public void SetEnableMagazineSlot(bool isEnable, HVRGrabbable unload = default) { magazineSocket.enabled = isEnable; magazineBag.enabled = isEnable; magazineGrabbable.enabled = isEnable; if(unload) { unload.enabled = isEnable; } } public void LoadMagazine() { SetEnableMagazineSlot(false); if (state == StateReloadShotgun.Closed) return; prevState = state; state = StateReloadShotgun.Free; logicState = StateLogicShotgun.ToClose; joint.SetAngularXHighLimit(maxAngle); joint.SetAngularXLowLimit(0); stab.SetActive(false); sounds.PlayLoadMagazine(); } public void UnloadMagazine(HVRGrabberBase grabbableBase, HVRGrabbable unload) { SetEnableMagazineSlot(true, unload); sounds.PlayUnloadMagazine(); } private void Update() { foreach(var hand in masterGrabbable.HandGrabbers) { var controller = HVRInputManager.Instance.GetController(hand.HandSide); var release = false; if (controller.ControllerType == HVRControllerType.WMR) { release = controller.Side == HVRHandSide.Right ? controller.TrackPadLeft.JustActivated : controller.TrackPadRight.JustActivated; } else if (controller.ControllerType == HVRControllerType.Vive) { release = HVRInputManager.Instance.RightController.TrackPadDown.JustActivated; } else { release = controller.PrimaryButtonState.JustActivated; } if(release) { if(state == StateReloadShotgun.Closed) { sounds.PlaySlideBack(); Opened(); } else if(state is StateReloadShotgun.Free or StateReloadShotgun.Opened) { sounds.PlaySlideForward(); Closed(); } } } } } public enum StateReloadShotgun { Closed = 0, Opened = 1, InHand = 2, Free = 3 } public enum StateLogicShotgun { None, ToOpen, ToClose }