b8ab71969a
Finished lockpicking. tied it to the Attributes system. when you pick a lock you gain dexterity, the higher your dexterity, the easier it is to pick locks.
333 lines
9.1 KiB
C#
333 lines
9.1 KiB
C#
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<GameObject> 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<Vector2>().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);
|
|
|
|
}
|
|
|
|
}
|
|
}
|