using System.Collections; using System.Collections.Generic; using UnityEngine; using RPGCreationKit.Player; using RPGCreationKit.CellsSystem; using TMPro; namespace RPGCreationKit { public class LockpickingManager : MonoBehaviour { public static LockpickingManager instance; private void Awake() { if (instance == null) instance = this; else Debug.LogError("Anomaly detected with the singleton pattern of 'LockpickingManager', are you using multiple LockpickingManager?"); } private Door curDoor; private LootingPoint curLootingPoint; [Space(8)] [Header("\tLockpicking References")] [SerializeField] private GameObject lockpickingUI; [SerializeField] private Transform LockPickUI; [SerializeField] private GameObject LockPickBack; [SerializeField] public Item LockPick; [SerializeField] private GameObject PadLock; [SerializeField] private GameObject DoorLock; [SerializeField] private TextMeshProUGUI PicksLeft; [SerializeField] private SpinVert PadlockSV; [SerializeField] private SpinVert DoorSV; [SerializeField] private List ThingsToHide; [Space(8)] [Header("\tAudio")] [SerializeField] private AudioSource audioSource; [Space(8)] [SerializeField] private AudioClip pickAttempt; [SerializeField] private AudioClip pickBroke; [SerializeField] private AudioClip pickSuccess; [SerializeField] private AudioClip LockUnlocking; [Header("\tStarting Positions")] [SerializeField] private Vector3 PickAngle; [SerializeField] private Vector3 OrigPos; [SerializeField] private float MinAngle = -70f; [SerializeField] private float MaxAngle = 70f; private bool isShaking = false; private bool isBroken = false; private float shakeTime = 0f; private float angle = 0f; private float angleX = 0f; private float target = 0f; private float acceptableRange = 0f; private float direction = 0f; private bool isDoor = false; private SpinVert RealSV; // Durability is Static, and Held between lockpicking sessions, so that they cant exit then return to lockpicking to reset durability private static int durability = 0; void Start() { PickAngle = LockPickUI.transform.rotation.eulerAngles; } public void StartPicking(Door _door) { if (_door.lockLevel == DoorLockLevel.Impossible) return; curDoor = _door; isDoor = true; RealSV = DoorSV; switch (_door.lockLevel) { case DoorLockLevel.VeryEasy: acceptableRange = 50f; //25 break; case DoorLockLevel.Easy: acceptableRange = 38f; //20 break; case DoorLockLevel.Medium: acceptableRange = 26f; //13 break; case DoorLockLevel.Hard: acceptableRange = 15f; //8 break; case DoorLockLevel.VeryHard: acceptableRange = 3f; //3 break; } Begin(); } public void StartPicking(LootingPoint _LootingPoint) { if (_LootingPoint.lockLevel == ContainerLockLevel.Impossible) return; curLootingPoint = _LootingPoint; isDoor = false; RealSV = PadlockSV; switch (_LootingPoint.lockLevel) { case ContainerLockLevel.VeryEasy: acceptableRange = 50f; //25 break; case ContainerLockLevel.Easy: acceptableRange = 38f; //20 break; case ContainerLockLevel.Medium: acceptableRange = 26f; //13 break; case ContainerLockLevel.Hard: acceptableRange = 15f; //8 break; case ContainerLockLevel.VeryHard: acceptableRange = 3f; //3 break; } Begin(); } private void Begin() { acceptableRange = (acceptableRange + EntityAttributes.PlayerAttributes.attributes.Dexterity); Debug.Log("acceptableRange: "+acceptableRange); PickAngle = LockPickUI.transform.rotation.eulerAngles; OrigPos = PickAngle; MinAngle = PickAngle.y - 70; MaxAngle = PickAngle.y + 70; RealSV.ResetRotation(); PicksLeft.text = Inventory.PlayerInventory.GetItemCount(LockPick).ToString(); if (!Inventory.PlayerInventory.HasItem(LockPick.ItemID)) return; angle = PickAngle.y; target = Random.Range(MinAngle, MaxAngle); if (durability <= 0) durability = 5; // 5 attempts per Lockpick RckPlayer.instance.input.SwitchCurrentActionMap("LockpickingUI"); DoorLock.SetActive(isDoor); PadLock.SetActive(!isDoor); lockpickingUI.SetActive(true); RckPlayer.instance.isPickingLock = true; for (int i = 0; i < ThingsToHide.Count; i++) ThingsToHide[i].SetActive(false); } void FixedUpdate() { if (isShaking) { float distance = Mathf.Abs(angle - target); PickAngle = LockPickUI.transform.rotation.eulerAngles; PickAngle.x = Mathf.Clamp((Random.Range(-distance, distance) / 90f) * 10f, -10, 10); PickAngle.y = angle; LockPickUI.rotation = Quaternion.Euler(PickAngle); shakeTime -= Time.fixedDeltaTime; if (shakeTime <= 0) { isShaking = false; PickAngle = LockPickUI.transform.rotation.eulerAngles; PickAngle.x = angleX; LockPickUI.rotation = Quaternion.Euler(PickAngle); } } if (isBroken) { //this is where I build an animation making it look like it is broke shakeTime -= Time.fixedDeltaTime; // May as well use this as the breaking animation time if (shakeTime <= 0) { // show it broken, then vanish for 1 second, and come back new. need to figure out how to reset rotation... if (LockPickUI.gameObject.activeSelf) { LockPickUI.gameObject.SetActive(false); shakeTime = 1f; Vector3 TempV = LockPickUI.transform.rotation.eulerAngles; // Reset Angle //TempV.x = TempV.x - 90f; LockPickBack.transform.rotation = Quaternion.Euler(TempV); } else { isBroken = false; //LockPickBack.SetActive(true); LockPickUI.gameObject.SetActive(true); LockPickUI.rotation = Quaternion.Euler(OrigPos); angle = OrigPos.y; durability = 5; // Resets the picks health } } } } void Update() { if (!RckPlayer.instance.isPickingLock) return; if (isShaking) return; if (isBroken) return; direction = -RckPlayer.instance.input.currentActionMap.FindAction("Move").ReadValue().x; angle += direction * Time.deltaTime * 16.0f; angle = Mathf.Clamp(angle, MinAngle, MaxAngle); LockPickUI.rotation = Quaternion.Euler(PickAngle.x, angle, PickAngle.z); if (RckPlayer.instance.input.currentActionMap.FindAction("Attempt").triggered) { Attempt(); } else if (RckPlayer.instance.input.currentActionMap.FindAction("Close").triggered) { StopPicking(); } } void Attempt() { if (!RckPlayer.instance.isPickingLock) return; if (durability <= 0) return; durability--; // Check if successfull attempt Debug.Log("Angle: "+angle+"; Min: "+(target - acceptableRange)+"; Max: "+(target + acceptableRange)); if(angle > target - acceptableRange && angle < target + acceptableRange) { // Success! StartCoroutine(UnlockLock()); return; } if (durability <= 0) // Breaks Pick. Lets make the pick in 2 pieces and animate a break { Inventory.PlayerInventory.RemoveItem(LockPick.ItemID, 1); PicksLeft.text = Inventory.PlayerInventory.GetItemCount(LockPick).ToString(); if (audioSource != null) audioSource.PlayOneShot(pickBroke); if (Inventory.PlayerInventory.GetItemCount(LockPick) < 1) StopPicking(); isBroken = true; // this makes Lateupdate fire, which fires off Attempt(); shakeTime = 2f; // Making this 0 so it just skips the shaking. We need an animation here instead (New Function) angleX = PickAngle.x; Vector3 TempV = LockPickBack.transform.rotation.eulerAngles; // Reset Angle TempV.x = TempV.x + 45f; LockPickBack.transform.rotation = Quaternion.Euler(TempV); // LockPickBack.SetActive(false); } else { isShaking = true; shakeTime = 1f; if(audioSource != null) audioSource.PlayOneShot(pickAttempt); } } public void CheatUnlock() { StartCoroutine(UnlockLock()); } IEnumerator UnlockLock() { EntityAttributes.PlayerAttributes.attributes.DexterityPoints += 1; int A = EntityAttributes.PlayerAttributes.attributes.DexterityPoints; int B = EntityAttributes.PlayerAttributes.attributes.Dexterity; while (A >= (B*3)) { EntityAttributes.PlayerAttributes.attributes.Dexterity += 1; EntityAttributes.PlayerAttributes.attributes.DexterityPoints = (A-(B*3)); A = EntityAttributes.PlayerAttributes.attributes.DexterityPoints; B = EntityAttributes.PlayerAttributes.attributes.Dexterity; } if (isDoor) { curDoor.UnlockDoor(); } else { curLootingPoint.UnlockContainer(); } RealSV.StartSpinning(); if (audioSource != null) audioSource.PlayOneShot(LockUnlocking); yield return new WaitForSecondsRealtime(1.5f); StopPicking(); } public void StopPicking() { for (int i = 0; i < ThingsToHide.Count; i++) ThingsToHide[i].SetActive(true); lockpickingUI.SetActive(false); isShaking = false; RckPlayer.instance.isPickingLock = false; curDoor = null; curLootingPoint = null; RckPlayer.instance.input.SwitchCurrentActionMap("Player"); LockPickUI.rotation = Quaternion.Euler(OrigPos); } } }