Upload from upload_mods.ps1
This commit is contained in:
531
Score/LockPicking/Scripts/Cipher.cs
Normal file
531
Score/LockPicking/Scripts/Cipher.cs
Normal file
@@ -0,0 +1,531 @@
|
||||
using UnityEngine.Events;
|
||||
|
||||
/*
|
||||
* Thank you for using my Lockpicking asset! I hope it works great in your game. You can extend it to suit your game by
|
||||
* manipulating some of the code below. For instance, if your player can have a various level of "lockpicking" skill,
|
||||
* you may consider multiplying the value of lockGive by their skill, so that a higher skilled player would find it
|
||||
* easier to open a lock.
|
||||
*
|
||||
* Enjoy!
|
||||
*/
|
||||
|
||||
namespace Lockpicking
|
||||
{
|
||||
//[ExecuteInEditMode]
|
||||
[RequireComponent(typeof(LockEmissive))]
|
||||
public class Cipher : MonoBehaviour
|
||||
{
|
||||
[Header("Speed Settings")]
|
||||
[Tooltip("Maximum shake distance per shake change.")]
|
||||
[SerializeField]
|
||||
private float maxShake = 0.5f;
|
||||
|
||||
[Tooltip("Amount of time between shake changes when shaking.")]
|
||||
[SerializeField]
|
||||
private float shakeTime = 0.1f;
|
||||
|
||||
[Tooltip("Speed of the wheel when turning.")]
|
||||
public float turnSpeed = 180f;
|
||||
|
||||
|
||||
[Header("Lock Setup")]
|
||||
[Tooltip("Number of symbols on the wheel. Should be spaced evenly.")]
|
||||
public int symbolCount = 18;
|
||||
|
||||
[Tooltip("How close do we have to be to perfectly aligned for the placement of a wheel to count?")]
|
||||
public float closeEnough = 3f;
|
||||
|
||||
[Tooltip("If true, wheels will \"snap\" into a new random spot on setup. If false, they will rotate to those spots.")]
|
||||
public bool quickReset;
|
||||
|
||||
[Tooltip("If true, the active wheel will be highlighted using the emissive map of the material.")]
|
||||
public bool highlightActiveWheel = true;
|
||||
|
||||
[Tooltip("If true, wheels will move to the closest spot when the player stops input movement.")]
|
||||
public bool moveToClosestSpot;
|
||||
|
||||
|
||||
[Header("Lock Details")]
|
||||
[Tooltip("When true, the lock has been opened.")]
|
||||
public bool isOpen;
|
||||
|
||||
[Tooltip("When true, the lock will reset itself on awake. Set this to false if you are choosing a specific combination.")]
|
||||
public bool resetOnAwake;
|
||||
|
||||
|
||||
[Header("Animation Trigger Strings")] public string openTrigger = "Open";
|
||||
|
||||
public string closeTrigger = "Close";
|
||||
|
||||
// Audio Settings
|
||||
[Range(0f, 1f)] public float clickVolumeMin = 0.1f;
|
||||
[Range(0f, 1f)] public float clickVolumeMax = 0.4f;
|
||||
[Range(0f, 1f)] public float squeekVolumeMin = 0.1f;
|
||||
[Range(0f, 1f)] public float squeekVolumeMax = 0.4f;
|
||||
[Range(0, 100)] public int squeekChance = 50;
|
||||
[Range(0f, 15f)] public float squeekRate = 3.5f;
|
||||
public float[] unlockAngle; // All the unlock angles for each wheel
|
||||
public float[] startAngle; // All the starting angles for each wheel
|
||||
public float[] turnedDistance; // amount each wheel has been turned
|
||||
public float[] turnedDistancePrev; // amount each wheel has been turned
|
||||
public bool[] isMoving; // Records whether the wheels are moving
|
||||
public bool playAudioOnSetup = true;
|
||||
|
||||
[Header("Plumbing")] public GameObject[] wheels;
|
||||
|
||||
public LocksetAudio audioClick;
|
||||
public LocksetAudio audioSqueek;
|
||||
public LocksetAudio audioJiggle;
|
||||
public LocksetAudio audioJiggle2;
|
||||
public LocksetAudio audioJiggle3;
|
||||
public LocksetAudio audioOpen;
|
||||
|
||||
// Events
|
||||
private readonly UnityEvent lockOpen = new UnityEvent();
|
||||
|
||||
// Private variables
|
||||
private int _activeWheel;
|
||||
private int _closeTrigger;
|
||||
private LocksetAudio _locksetAudio;
|
||||
|
||||
|
||||
// Private animation hashes
|
||||
private int _openTrigger;
|
||||
private Animator animator;
|
||||
private float getReadyPostReadyTimer = 0.3f;
|
||||
private bool isReady; // WHen true, player can interact
|
||||
private bool isShaking; // When true, the lock is shaking (trying to be opened but in the wrong combination)
|
||||
|
||||
private LockEmissive lockEmissive;
|
||||
private Vector3 preshake; // Saves the pre-shake angles
|
||||
|
||||
private float shakeTimer; // Counter for the shake Time
|
||||
|
||||
// private float _speed;
|
||||
private float squeekTimer;
|
||||
|
||||
public bool VisualizeSolution { get; set; }
|
||||
|
||||
public bool VisualizeStart { get; set; }
|
||||
|
||||
public float ActiveWheelStart
|
||||
{
|
||||
get => startAngle[ActiveWheel()];
|
||||
set => startAngle[ActiveWheel()] = value;
|
||||
}
|
||||
|
||||
public float ActiveWheelSolution
|
||||
{
|
||||
get => unlockAngle[ActiveWheel()];
|
||||
set => unlockAngle[ActiveWheel()] = value;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
squeekTimer = squeekRate;
|
||||
_locksetAudio = GetComponent<LocksetAudio>();
|
||||
animator = GetComponent<Animator>();
|
||||
lockEmissive = GetComponent<LockEmissive>();
|
||||
if (!highlightActiveWheel)
|
||||
lockEmissive.highlightRenderer = null;
|
||||
|
||||
_openTrigger = Animator.StringToHash(openTrigger);
|
||||
_closeTrigger = Animator.StringToHash(closeTrigger);
|
||||
|
||||
if (resetOnAwake) ResetLock();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Do actions to get ready, if we are not ready
|
||||
if (!isReady)
|
||||
{
|
||||
GetReady();
|
||||
if (playAudioOnSetup)
|
||||
DoAudio();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getReadyPostReadyTimer > 0)
|
||||
getReadyPostReadyTimer -= Time.deltaTime;
|
||||
|
||||
if (moveToClosestSpot)
|
||||
MoveToClosestSpot();
|
||||
ResetMovement();
|
||||
|
||||
if (highlightActiveWheel) lockEmissive.SetHighlightRenderer(wheels[_activeWheel].GetComponent<Renderer>());
|
||||
|
||||
DoAudio();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (unlockAngle.Length != wheels.Length )
|
||||
{
|
||||
Debug.Log("Updating Lengths");
|
||||
unlockAngle = new float[wheels.Length];
|
||||
startAngle = new float[wheels.Length];
|
||||
turnedDistance = new float[wheels.Length];
|
||||
isMoving = new bool[wheels.Length];
|
||||
}
|
||||
|
||||
if (_visualizeSolution)
|
||||
SetRotationToSolution();
|
||||
else if (_visualizeStart)
|
||||
SetRotationToStart();
|
||||
else
|
||||
SetRotationToZero();
|
||||
|
||||
for (int i = 0; i < wheels.Length; i++)
|
||||
{
|
||||
unlockAngle[i] = ClosestSpot(unlockAngle[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
public int ActiveWheel()
|
||||
{
|
||||
return _activeWheel;
|
||||
}
|
||||
|
||||
public void EditorOnValidate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
OnValidate();
|
||||
}
|
||||
|
||||
private void SetRotationToSolution()
|
||||
{
|
||||
for (var i = 0; i < wheels.Length; i++)
|
||||
{
|
||||
var eulerAngles = wheels[i].transform.localEulerAngles;
|
||||
eulerAngles.x = unlockAngle[i];
|
||||
wheels[i].transform.localEulerAngles = eulerAngles;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRotationToStart()
|
||||
{
|
||||
for (var i = 0; i < wheels.Length; i++)
|
||||
{
|
||||
var eulerAngles = wheels[i].transform.localEulerAngles;
|
||||
eulerAngles.x = startAngle[i];
|
||||
wheels[i].transform.localEulerAngles = eulerAngles;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRotationToZero()
|
||||
{
|
||||
for (var i = 0; i < wheels.Length; i++) wheels[i].transform.localEulerAngles = new Vector3();
|
||||
}
|
||||
|
||||
public float DistanceLeft(int i)
|
||||
{
|
||||
if (turnedDistance.Length >= i + 1)
|
||||
{
|
||||
var left = unlockAngle[i] - turnedDistance[i];
|
||||
if (left < -350)
|
||||
left += 360;
|
||||
if (left > 350)
|
||||
left -= 360;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
return 9999;
|
||||
}
|
||||
|
||||
private void DoAudio()
|
||||
{
|
||||
for (var i = 0; i < turnedDistance.Length; i++)
|
||||
{
|
||||
var turnSpeed = 0f;
|
||||
if (turnedDistance[i] != turnedDistancePrev[i])
|
||||
{
|
||||
if (getReadyPostReadyTimer <= 0 || playAudioOnSetup)
|
||||
{
|
||||
if (audioSqueek)
|
||||
// Squeek
|
||||
if (squeekRate > 0)
|
||||
{
|
||||
squeekTimer -= Time.deltaTime;
|
||||
if (squeekTimer <= 0)
|
||||
{
|
||||
if (UnityEngine.Random.Range(0, 100) < squeekChance)
|
||||
{
|
||||
//Log.Out("Cipher-DoAudio PLAY SOUND: audioSqueek");
|
||||
audioSqueek.PlayAudioClip(UnityEngine.Random.Range(squeekVolumeMin, squeekVolumeMax));
|
||||
}
|
||||
squeekTimer = squeekRate;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioClick)
|
||||
{
|
||||
// Clicks
|
||||
turnSpeed = turnedDistance[i] - turnedDistancePrev[i];
|
||||
|
||||
var turnedMod = turnedDistance[i] % (360 / symbolCount);
|
||||
var turnedModPrev = turnedDistancePrev[i] % (360 / symbolCount);
|
||||
|
||||
if ((turnSpeed > 0 || turnSpeed < -350) && (turnedMod < turnedModPrev || turnedMod > 0 && turnedModPrev < 0))
|
||||
{
|
||||
//Log.Out("Cipher-DoAudio PLAY SOUND: audioClick 1");
|
||||
audioClick.PlayAudioClip(UnityEngine.Random.Range(clickVolumeMin, clickVolumeMax));
|
||||
}
|
||||
else if ((turnSpeed < 0 || turnSpeed > 350) && (turnedMod > turnedModPrev || turnedMod < 0 && turnedModPrev > 0))
|
||||
{
|
||||
//Log.Out("Cipher-DoAudio PLAY SOUND: audioClick 2");
|
||||
audioClick.PlayAudioClip(UnityEngine.Random.Range(clickVolumeMin, clickVolumeMax));
|
||||
}
|
||||
else if (turnedMod == 0)
|
||||
{
|
||||
//Log.Out("Cipher-DoAudio PLAY SOUND: audioClick 3");
|
||||
audioClick.PlayAudioClip(UnityEngine.Random.Range(clickVolumeMin, clickVolumeMax));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
turnedDistancePrev[i] = turnedDistance[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int NextWheelIndex()
|
||||
{
|
||||
return _activeWheel + 1 < wheels.Length ? _activeWheel + 1 : 0;
|
||||
}
|
||||
|
||||
public int PrevWheelIndex()
|
||||
{
|
||||
return _activeWheel - 1 < 0 ? wheels.Length - 1 : _activeWheel - 1;
|
||||
}
|
||||
|
||||
public void SelectWheel(int value)
|
||||
{
|
||||
_activeWheel = value < wheels.Length && value >= 0 ? value : 0;
|
||||
}
|
||||
|
||||
public void ResetMovement()
|
||||
{
|
||||
for (var i = 0; i < wheels.Length; i++) isMoving[i] = false;
|
||||
}
|
||||
|
||||
public void MoveToClosestSpot()
|
||||
{
|
||||
for (var i = 0; i < wheels.Length; i++)
|
||||
// Only run this if the wheel is not moving (i.e. being moved by the player)
|
||||
if (!isMoving[i])
|
||||
{
|
||||
if (turnedDistance[i] < 0) turnedDistance[i] += 360;
|
||||
|
||||
/*
|
||||
float smallestDistance = 360f;
|
||||
float closestRotation = 0f;
|
||||
|
||||
for (int d = 0; d < 360 / symbolCount; d++)
|
||||
{
|
||||
float diff = d * (360 / symbolCount);
|
||||
if (Mathf.Abs(Mathf.Abs(turnedDistance[i]) - diff) < smallestDistance)
|
||||
{
|
||||
smallestDistance = Mathf.Abs(Mathf.Abs(turnedDistance[i]) - diff);
|
||||
closestRotation = diff;
|
||||
}
|
||||
}
|
||||
MoveTowards(i, closestRotation);
|
||||
*/
|
||||
MoveTowards(i, ClosestSpot(Mathf.Abs(turnedDistance[i])));
|
||||
}
|
||||
}
|
||||
|
||||
private float ClosestSpot(float value)
|
||||
{
|
||||
var smallestDistance = 360f;
|
||||
var closestRotation = 0f;
|
||||
|
||||
for (var d = -360; d < 360 / symbolCount; d++)
|
||||
{
|
||||
float diff = d * (360 / symbolCount);
|
||||
if (Mathf.Abs(value - diff) < smallestDistance)
|
||||
{
|
||||
smallestDistance = Mathf.Abs(value - diff);
|
||||
closestRotation = diff;
|
||||
}
|
||||
}
|
||||
|
||||
return closestRotation;
|
||||
}
|
||||
|
||||
public void TryOpen()
|
||||
{
|
||||
if (!isShaking)
|
||||
preshake = transform.localEulerAngles;
|
||||
|
||||
if (!isOpen)
|
||||
{
|
||||
for (var i = 0; i < wheels.Length; i++)
|
||||
if (Mathf.Abs(DistanceLeft(i)) > closeEnough)
|
||||
{
|
||||
Shake();
|
||||
return;
|
||||
}
|
||||
|
||||
isOpen = true;
|
||||
animator.SetTrigger(_openTrigger);
|
||||
|
||||
//Log.Out("Lockpicking-TryOpen PLAY SOUND: audioPadlockOpen");
|
||||
audioOpen.PlayOnce();
|
||||
|
||||
// Invoke the event for any other scripts that are listening
|
||||
lockOpen.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopShaking()
|
||||
{
|
||||
transform.localEulerAngles = preshake;
|
||||
isShaking = false;
|
||||
|
||||
if (audioJiggle)
|
||||
{
|
||||
audioJiggle.StopLoop();
|
||||
if (audioJiggle2 != null)
|
||||
audioJiggle2.StopLoop();
|
||||
if (audioJiggle3 != null)
|
||||
audioJiggle3.StopLoop();
|
||||
}
|
||||
}
|
||||
|
||||
private void Shake()
|
||||
{
|
||||
if (!isShaking)
|
||||
isShaking = true;
|
||||
|
||||
shakeTimer -= Time.deltaTime;
|
||||
if (shakeTimer <= 0)
|
||||
{
|
||||
// Start with the current values
|
||||
var newShake = preshake;
|
||||
|
||||
// Add some modification
|
||||
//newShake.z += UnityEngine.Random.Range(-maxShake, maxShake);
|
||||
newShake.x += UnityEngine.Random.Range(-maxShake, maxShake);
|
||||
newShake.y += UnityEngine.Random.Range(-maxShake, maxShake);
|
||||
|
||||
// Set the value + modification
|
||||
transform.localEulerAngles = newShake;
|
||||
|
||||
// Reset the timer
|
||||
shakeTimer = shakeTime;
|
||||
}
|
||||
|
||||
if (audioJiggle)
|
||||
{
|
||||
audioJiggle.PlayLoop();
|
||||
if (audioJiggle2 != null)
|
||||
audioJiggle2.PlayLoop();
|
||||
if (audioJiggle3 != null)
|
||||
audioJiggle3.PlayLoop();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetReady()
|
||||
{
|
||||
var readyCount = 0;
|
||||
for (var i = 0; i < wheels.Length; i++)
|
||||
{
|
||||
var speed = 1;
|
||||
var distanceLeft = startAngle[i] - turnedDistance[i];
|
||||
|
||||
if (VisualizeSolution) distanceLeft = unlockAngle[i] - turnedDistance[i];
|
||||
|
||||
if (distanceLeft < 0) speed = -1;
|
||||
|
||||
var turnAmount = speed * turnSpeed * Time.deltaTime;
|
||||
if (Mathf.Abs(distanceLeft) < Mathf.Abs(turnAmount))
|
||||
{
|
||||
turnAmount = distanceLeft;
|
||||
readyCount++;
|
||||
}
|
||||
|
||||
if (quickReset || VisualizeSolution)
|
||||
{
|
||||
turnAmount = distanceLeft;
|
||||
readyCount++;
|
||||
}
|
||||
|
||||
SetTurnedDistance(i, turnAmount);
|
||||
RotateWheel(wheels[i].transform, turnAmount);
|
||||
}
|
||||
|
||||
if (readyCount == wheels.Length)
|
||||
isReady = true;
|
||||
}
|
||||
|
||||
public void MoveActiveWheel(int speed)
|
||||
{
|
||||
MoveWheel(_activeWheel, speed);
|
||||
}
|
||||
|
||||
public void MoveWheel(int i, int speed, float destination = 999f)
|
||||
{
|
||||
if (isReady)
|
||||
{
|
||||
isMoving[i] = true; // Mark this wheel as currently moving
|
||||
var turnAmount = speed * turnSpeed * Time.deltaTime;
|
||||
if (destination != 999)
|
||||
if (Mathf.Abs(destination - turnedDistance[i]) < Mathf.Abs(turnAmount))
|
||||
turnAmount = destination - turnedDistance[i];
|
||||
|
||||
SetTurnedDistance(i, turnAmount);
|
||||
RotateWheel(wheels[i].transform, turnAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private void RotateWheel(Transform transform, float value)
|
||||
{
|
||||
transform.Rotate(value, 0.0f, 0.0f, Space.Self);
|
||||
}
|
||||
|
||||
public void MoveTowards(int i, float closestRotation)
|
||||
{
|
||||
if (turnedDistance[i] > closestRotation)
|
||||
MoveWheel(i, -1, closestRotation);
|
||||
else
|
||||
MoveWheel(i, 1, closestRotation);
|
||||
}
|
||||
|
||||
public void SetTurnedDistance(int i, float distance)
|
||||
{
|
||||
turnedDistance[i] += distance;
|
||||
if (turnedDistance[i] > 360)
|
||||
turnedDistance[i] -= 360;
|
||||
if (turnedDistance[i] < -360)
|
||||
turnedDistance[i] += 360;
|
||||
}
|
||||
|
||||
public void ResetLock()
|
||||
{
|
||||
Debug.Log("ResetLock");
|
||||
isOpen = false;
|
||||
isReady = false;
|
||||
animator.SetTrigger(_closeTrigger);
|
||||
|
||||
// Shuffle each wheel
|
||||
for (var i = 0; i < wheels.Length; i++)
|
||||
{
|
||||
unlockAngle[i] = RandomAngle();
|
||||
startAngle[i] = RandomAngle();
|
||||
}
|
||||
}
|
||||
|
||||
private float RandomAngle()
|
||||
{
|
||||
return UnityEngine.Random.Range(0, symbolCount) * (360 / symbolCount) - 180;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Score/LockPicking/Scripts/CipherControls.cs
Normal file
73
Score/LockPicking/Scripts/CipherControls.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Lockpicking;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
public class CipherControls : MonoBehaviour
|
||||
{
|
||||
[FormerlySerializedAs("cypher")] public Cipher cipher;
|
||||
|
||||
// Update is called once per frame
|
||||
private void Update()
|
||||
{
|
||||
if (cipher.gameObject.activeSelf)
|
||||
InputControls();
|
||||
}
|
||||
|
||||
private void InputControls()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Tab))
|
||||
{
|
||||
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
|
||||
cipher.SelectWheel(cipher.PrevWheelIndex());
|
||||
else
|
||||
cipher.SelectWheel(cipher.NextWheelIndex());
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.LeftArrow))
|
||||
cipher.SelectWheel(cipher.PrevWheelIndex());
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.RightArrow))
|
||||
cipher.SelectWheel(cipher.NextWheelIndex());
|
||||
|
||||
if (Input.GetKey(KeyCode.UpArrow))
|
||||
cipher.MoveActiveWheel(-1);
|
||||
|
||||
if (Input.GetKey(KeyCode.DownArrow))
|
||||
cipher.MoveActiveWheel(1);
|
||||
|
||||
if (Input.GetKey(KeyCode.Q))
|
||||
cipher.MoveWheel(0, -1);
|
||||
|
||||
if (Input.GetKey(KeyCode.A))
|
||||
cipher.MoveWheel(0, 1);
|
||||
|
||||
if (Input.GetKey(KeyCode.W))
|
||||
cipher.MoveWheel(1, -1);
|
||||
|
||||
if (Input.GetKey(KeyCode.S))
|
||||
cipher.MoveWheel(1, 1);
|
||||
|
||||
if (Input.GetKey(KeyCode.E))
|
||||
cipher.MoveWheel(2, -1);
|
||||
|
||||
if (Input.GetKey(KeyCode.D))
|
||||
cipher.MoveWheel(2, 1);
|
||||
|
||||
if (Input.GetKey(KeyCode.R))
|
||||
cipher.MoveWheel(3, -1);
|
||||
|
||||
if (Input.GetKey(KeyCode.F))
|
||||
cipher.MoveWheel(3, 1);
|
||||
|
||||
if (Input.GetKey(KeyCode.T))
|
||||
cipher.MoveWheel(4, -1);
|
||||
|
||||
if (Input.GetKey(KeyCode.G))
|
||||
cipher.MoveWheel(4, 1);
|
||||
|
||||
if (Input.GetKey(KeyCode.Y))
|
||||
cipher.MoveWheel(5, -1);
|
||||
|
||||
if (Input.GetKey(KeyCode.H))
|
||||
cipher.MoveWheel(5, 1);
|
||||
}
|
||||
}
|
||||
79
Score/LockPicking/Scripts/CipherDemoUI.cs
Normal file
79
Score/LockPicking/Scripts/CipherDemoUI.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
//using UnityEngine;
|
||||
//using UnityEngine.UI;
|
||||
//using Lockpicking;
|
||||
//using UnityEngine.Serialization;
|
||||
|
||||
//public class CipherDemoUI : MonoBehaviour
|
||||
//{
|
||||
|
||||
// // Set up references to the Text objects
|
||||
// public Text wheel1;
|
||||
// public Text wheel2;
|
||||
// public Text wheel3;
|
||||
// public Text wheel4;
|
||||
// public Text wheel5;
|
||||
// public Text wheel6;
|
||||
|
||||
// public Cipher cipher;
|
||||
|
||||
// public Color highlightColor = new Color(255f,0f,171f,1f);
|
||||
|
||||
// void Start()
|
||||
// {
|
||||
//// ResetLock();
|
||||
// }
|
||||
|
||||
// void Update()
|
||||
// {
|
||||
// DrawText();
|
||||
// }
|
||||
|
||||
// private void DrawText()
|
||||
// {
|
||||
// if (Input.GetKey(KeyCode.O))
|
||||
// {
|
||||
// cipher.TryOpen();
|
||||
// }
|
||||
// if (Input.GetKeyUp(KeyCode.O))
|
||||
// {
|
||||
// cipher.StopShaking();
|
||||
// }
|
||||
|
||||
// if (Mathf.Abs(cipher.DistanceLeft(0)) < cipher.closeEnough)
|
||||
// wheel1.color = highlightColor;
|
||||
// else
|
||||
// wheel1.color = Color.white;
|
||||
// if (Mathf.Abs(cipher.DistanceLeft(1)) < cipher.closeEnough)
|
||||
// wheel2.color = highlightColor;
|
||||
// else
|
||||
// wheel2.color = Color.white;
|
||||
// if (Mathf.Abs(cipher.DistanceLeft(2)) < cipher.closeEnough)
|
||||
// wheel3.color = highlightColor;
|
||||
// else
|
||||
// wheel3.color = Color.white;
|
||||
// if (Mathf.Abs(cipher.DistanceLeft(3)) < cipher.closeEnough)
|
||||
// wheel4.color = highlightColor;
|
||||
// else
|
||||
// wheel4.color = Color.white;
|
||||
// if (Mathf.Abs(cipher.DistanceLeft(4)) < cipher.closeEnough)
|
||||
// wheel5.color = highlightColor;
|
||||
// else
|
||||
// wheel5.color = Color.white;
|
||||
// if (Mathf.Abs(cipher.DistanceLeft(5)) < cipher.closeEnough)
|
||||
// wheel6.color = highlightColor;
|
||||
// else
|
||||
// wheel6.color = Color.white;
|
||||
// wheel1.text = "" + cipher.DistanceLeft(0);
|
||||
// wheel2.text = "" + cipher.DistanceLeft(1);
|
||||
// wheel3.text = "" + cipher.DistanceLeft(2);
|
||||
// wheel4.text = "" + cipher.DistanceLeft(3);
|
||||
// wheel5.text = "" + cipher.DistanceLeft(4);
|
||||
// wheel6.text = "" + cipher.DistanceLeft(5);
|
||||
// }
|
||||
|
||||
// public void ResetLock()
|
||||
// {
|
||||
// cipher.ResetLock();
|
||||
// }
|
||||
//}
|
||||
|
||||
773
Score/LockPicking/Scripts/Keyhole.cs
Normal file
773
Score/LockPicking/Scripts/Keyhole.cs
Normal file
@@ -0,0 +1,773 @@
|
||||
using UnityEngine.Events;
|
||||
|
||||
/*
|
||||
* Thank you for using my Lockpicking asset! I hope it works great in your game. You can extend it to suit your game by
|
||||
* manipulating some of the code below. For instance, if your player can have a various level of "lockpicking" skill,
|
||||
* you may consider multiplying the value of lockGive by their skill, so that a higher skilled player would find it
|
||||
* easier to open a lock.
|
||||
*
|
||||
* Enjoy!
|
||||
*/
|
||||
|
||||
namespace Lockpicking
|
||||
{
|
||||
[RequireComponent(typeof(LockEmissive))]
|
||||
public class Keyhole : MonoBehaviour
|
||||
{
|
||||
// 7 Days To Die stuff
|
||||
public int NumLockPicks;
|
||||
public EntityPlayer player;
|
||||
public BlockValue blockValue;
|
||||
|
||||
[Header("Plumbing")] public GameObject keyhole; // The keyhole with lockpick A that turns the entire keyhole object to open it
|
||||
|
||||
public GameObject lockpickObject; // The lockpick that turns to match the secret lockAngle
|
||||
public Animator lockpickAnimator; // Animator on the lockpick in the lockpickObject
|
||||
public Animator _padlockAnimator;
|
||||
public GameObject padlock1; // Link to the padlock 1 game object
|
||||
public GameObject button;
|
||||
public LocksetAudio audioTurnClick;
|
||||
public LocksetAudio audioSqueek;
|
||||
public LocksetAudio audioOpen;
|
||||
public LocksetAudio audioJiggle;
|
||||
public LocksetAudio audioJiggle2;
|
||||
public LocksetAudio audioJiggle3;
|
||||
public LocksetAudio audioPadlockOpen;
|
||||
public LocksetAudio audioPadlockJiggle;
|
||||
public LocksetAudio audioLockpickBreak;
|
||||
public LocksetAudio audioLockpickEnter;
|
||||
public LocksetAudio audioLockpickClick;
|
||||
|
||||
// Audio Settings
|
||||
[Range(0f, 1f)] public float clickVolumeMin = 0.1f;
|
||||
[Range(0f, 1f)] public float clickVolumeMax = 0.4f;
|
||||
[Range(0, 100)] public int clickChance = 100;
|
||||
[Range(0f, 15f)] public float clickRate = 10f;
|
||||
[Range(0f, 1f)] public float squeekVolumeMin = 0.1f;
|
||||
[Range(0f, 1f)] public float squeekVolumeMax = 0.4f;
|
||||
[Range(0, 100)] public int squeekChance = 50;
|
||||
[Range(0f, 360f)] public float squeekRate = 20f;
|
||||
public bool buttonDown;
|
||||
private LockEmissive _lockEmissive; // Link to the lockEmissive script on this object
|
||||
private float _lockpickAnglePrev;
|
||||
|
||||
// Private variables
|
||||
private float breakCounter; // Counter for taking a break after a broken lockpick
|
||||
public float breakTimeCounter;
|
||||
private bool isShaking; // Whether we are currently shaking or not
|
||||
private Vector3 preshakeKeyhole; // Saves the pre-shake angles
|
||||
private Vector3 preshakeLockpick; // Saves the pre-shake angles
|
||||
private float shakeTimer; // Counter for the shake Time
|
||||
private float squeekTimer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
squeekTimer = squeekRate;
|
||||
|
||||
_pickAnglesDefault = LockpickAngles();
|
||||
|
||||
_lockEmissive = gameObject.GetComponent<LockEmissive>();
|
||||
if (_lockEmissive == null)
|
||||
gameObject.AddComponent<LockEmissive>();
|
||||
|
||||
if (padlock1 != null)
|
||||
{
|
||||
_padlockAnimator = padlock1.gameObject.GetComponent<Animator>();
|
||||
if (_padlockAnimator == null)
|
||||
_padlockAnimator = padlock1.gameObject.AddComponent<Animator>();
|
||||
}
|
||||
|
||||
_closeTrigger = Animator.StringToHash(closeTrigger);
|
||||
_openTrigger = Animator.StringToHash(openTrigger);
|
||||
_lockpickBreakTrigger = Animator.StringToHash(lockPickBreakTrigger);
|
||||
_lockpickInsertTrigger = Animator.StringToHash(lockPickInsertTrigger);
|
||||
|
||||
if (resetOnAwake)
|
||||
ResetLock();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (NumLockPicks > 0)
|
||||
{
|
||||
PassValuesToEmissiveScript();
|
||||
|
||||
if (BreakingForAnimation())
|
||||
return;
|
||||
HandlePlayerInput();
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshLockPicks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RefreshLockPicks();
|
||||
ResetLock();
|
||||
if (NumLockPicks > 0)
|
||||
UpdateLockPicks(true);
|
||||
else
|
||||
UpdateLockPicks(false);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
NumLockPicks = 0;
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
LockAngle = LockAngle;
|
||||
LockGive = LockGive;
|
||||
CloseDistance = CloseDistance;
|
||||
|
||||
_pickAngleMin = Mathf.Clamp(_pickAngleMin, minLockAngle, maxLockAngle);
|
||||
_pickAngleMax = Mathf.Clamp(_pickAngleMax, minLockAngle, maxLockAngle);
|
||||
|
||||
minGiveAmount = Mathf.Clamp(minGiveAmount, 1f, 360f);
|
||||
maxGiveAmount = Mathf.Clamp(maxGiveAmount, 1f, 360f);
|
||||
minCloseDistance = Mathf.Clamp(minCloseDistance, 5f, 360f);
|
||||
maxCloseDistance = Mathf.Clamp(maxCloseDistance, 5f, 360f);
|
||||
}
|
||||
|
||||
public float BreakTimeCounter()
|
||||
{
|
||||
return breakTimeCounter;
|
||||
}
|
||||
|
||||
public float LockPickAngle()
|
||||
{
|
||||
return GetAngle(LockpickAngles().z);
|
||||
}
|
||||
|
||||
public float KeyholeAngle()
|
||||
{
|
||||
return GetAngle(KeyholeAngles().z);
|
||||
}
|
||||
|
||||
public void EditorOnValidate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
OnValidate();
|
||||
}
|
||||
|
||||
private void UpdateLockPicks(bool enable)
|
||||
{
|
||||
// Hide the lock picks or show them.
|
||||
keyhole.transform.FindInChilds("LockpickB (Turnable)").gameObject.SetActive(enable);
|
||||
keyhole.transform.FindInChilds("LockpickA").gameObject.SetActive(enable);
|
||||
}
|
||||
|
||||
|
||||
private void RefreshLockPicks()
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
var uiforPlayer = LocalPlayerUI.GetUIForPlayer(player as EntityPlayerLocal);
|
||||
var playerInventory = uiforPlayer.xui.PlayerInventory;
|
||||
var item = ItemClass.GetItem("resourceLockPick");
|
||||
if (item != null)
|
||||
NumLockPicks = playerInventory.GetItemCount(item);
|
||||
|
||||
if (NumLockPicks > 0)
|
||||
UpdateLockPicks(true);
|
||||
else
|
||||
UpdateLockPicks(false);
|
||||
}
|
||||
|
||||
private void HandlePlayerInput()
|
||||
{
|
||||
if (_lockIsOpen) return;
|
||||
if (openPressure > 0)
|
||||
{
|
||||
TryToTurnKeyhole();
|
||||
}
|
||||
else
|
||||
{
|
||||
StopShaking();
|
||||
ReturnKeyholeToDefaultPosition();
|
||||
TurnLockpick(turnSpeedLockpick * lockpickPressure);
|
||||
}
|
||||
}
|
||||
|
||||
private bool BreakingForAnimation()
|
||||
{
|
||||
if (breakCounter > 0f)
|
||||
{
|
||||
breakCounter -= Time.deltaTime;
|
||||
ReturnKeyholeToDefaultPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ReturnKeyholeToDefaultPosition()
|
||||
{
|
||||
TurnKeyhole(-returnSpeedKeyhole);
|
||||
}
|
||||
|
||||
private void TryToTurnKeyhole()
|
||||
{
|
||||
if (LockCanTurn())
|
||||
{
|
||||
TurnKeyhole(turnSpeedKeyhole * openPressure);
|
||||
|
||||
if (KeyholeTurnValue() <= 0 && LockpickIsInPosition())
|
||||
OpenLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
Shake();
|
||||
}
|
||||
}
|
||||
|
||||
private void PassValuesToEmissiveScript()
|
||||
{
|
||||
_lockEmissive.breakpointValue = Mathf.Clamp(breakTimeCounter / breakTime, 0, 1);
|
||||
_lockEmissive.successValue = Mathf.Clamp(KeyholeTurnValue(), 0, 1);
|
||||
}
|
||||
|
||||
private bool LockpickIsInPosition()
|
||||
{
|
||||
return LockPickAngle() < _lockAngle + _lockGive && LockPickAngle() > _lockAngle - _lockGive;
|
||||
}
|
||||
|
||||
private void Shake()
|
||||
{
|
||||
// If we are not already shaking, save the original rotations.
|
||||
if (!isShaking)
|
||||
{
|
||||
if (audioPadlockJiggle && padlock1 != null && padlock1.activeSelf)
|
||||
{
|
||||
audioPadlockJiggle.PlayLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (audioJiggle)
|
||||
audioJiggle.PlayLoop();
|
||||
if (audioJiggle2 != null)
|
||||
audioJiggle2.PlayLoop();
|
||||
if (audioJiggle3 != null)
|
||||
audioJiggle3.PlayLoop();
|
||||
}
|
||||
|
||||
preshakeKeyhole = KeyholeAngles();
|
||||
preshakeLockpick = LockpickAngles();
|
||||
isShaking = true;
|
||||
}
|
||||
|
||||
// Check breakTimeCounter to stop shaking at the right time
|
||||
breakTimeCounter += Time.deltaTime;
|
||||
//Log.Out($"Break Time Counter: {breakTimeCounter} Total BreakTime: {breakTime}");
|
||||
if (breakTimeCounter > breakTime)
|
||||
{
|
||||
StopShaking();
|
||||
BreakLockpick();
|
||||
return;
|
||||
}
|
||||
|
||||
shakeTimer -= Time.deltaTime;
|
||||
if (shakeTimer <= 0)
|
||||
{
|
||||
// Start with the current values
|
||||
var newShakeKeyhole = preshakeKeyhole;
|
||||
var newShakeLockpick = preshakeLockpick;
|
||||
|
||||
// Add some modification
|
||||
newShakeKeyhole.z += UnityEngine.Random.Range(-maxShake, maxShake);
|
||||
newShakeLockpick.z += UnityEngine.Random.Range(-maxShake, maxShake);
|
||||
|
||||
// Set the value + modification
|
||||
SetKeyholeAngles(newShakeKeyhole);
|
||||
SetLockpickAngles(newShakeLockpick);
|
||||
|
||||
// Reset the timer
|
||||
shakeTimer = shakeTime;
|
||||
}
|
||||
}
|
||||
|
||||
private void StopShaking()
|
||||
{
|
||||
if (isShaking)
|
||||
{
|
||||
if (audioPadlockJiggle && padlock1 != null && padlock1.activeSelf)
|
||||
{
|
||||
audioPadlockJiggle.StopLoop();
|
||||
}
|
||||
else if (audioJiggle)
|
||||
{
|
||||
audioJiggle.StopLoop();
|
||||
if (audioJiggle2 != null)
|
||||
audioJiggle2.StopLoop();
|
||||
if (audioJiggle3 != null)
|
||||
audioJiggle3.StopLoop();
|
||||
}
|
||||
|
||||
SetKeyholeAngles(preshakeKeyhole);
|
||||
SetLockpickAngles(preshakeLockpick);
|
||||
isShaking = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetKeyholeAngles(Vector3 value)
|
||||
{
|
||||
keyhole.transform.localEulerAngles = value;
|
||||
}
|
||||
|
||||
private void SetLockpickAngles(Vector3 value)
|
||||
{
|
||||
lockpickObject.transform.localEulerAngles = value;
|
||||
}
|
||||
|
||||
public void BreakLockpick()
|
||||
{
|
||||
//Log.Out("Lockpicking-BreakLockpick START");
|
||||
if (audioLockpickBreak)
|
||||
{
|
||||
//Log.Out("Lockpicking-BreakLockpick PLAY SOUND: audioLockpickBreak");
|
||||
//Log.Out("Lockpicking-BreakLockpick audioLockpickBreak.name: " + audioLockpickBreak.name);
|
||||
//audioLockpickBreak.DelayPlay(1f);
|
||||
audioLockpickBreak.PlayOnce();
|
||||
}
|
||||
breakCounter = breakPause; // Set so we can't do any actions for a short time
|
||||
breakTimeCounter = 0f; // Reset the breakCounter
|
||||
ResetLockpickPosition(); // Reset the lockpick position
|
||||
lockpickAnimator.SetTrigger(_lockpickBreakTrigger); // Play the break animation
|
||||
lockpickBroke.Invoke(); // Invoke this event in case other scripts are listening
|
||||
|
||||
/*if (audioLockpickEnter && audioLockpickEnter.isActiveAndEnabled)
|
||||
{
|
||||
Log.Out("Lockpicking-BreakLockpick PLAY SOUND: audioLockpickEnter");
|
||||
audioLockpickEnter.DelayPlay(1f);
|
||||
}*/
|
||||
|
||||
// Remove the broke pick lock.
|
||||
if (player != null)
|
||||
{
|
||||
//Log.Out("Lockpicking-BreakLockpick REMOVE LOCK PICK");
|
||||
var playerUI = (player as EntityPlayerLocal).PlayerUI;
|
||||
var playerInventory = playerUI.xui.PlayerInventory;
|
||||
|
||||
var item = ItemClass.GetItem("resourceLockPick");
|
||||
var itemStack = new ItemStack(item, 1);
|
||||
playerInventory.RemoveItem(itemStack);
|
||||
RefreshLockPicks();
|
||||
}
|
||||
|
||||
if (NumLockPicks > 0)
|
||||
{
|
||||
//Log.Out("Lockpicking-BreakLockpick 1");
|
||||
UpdateLockPicks(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Log.Out("Lockpicking-BreakLockpick 2");
|
||||
UpdateLockPicks(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Call this when the lock is open successfully.
|
||||
/// </summary>
|
||||
public void OpenLock()
|
||||
{
|
||||
if (!_lockIsOpen)
|
||||
{
|
||||
if (audioPadlockOpen && padlock1 != null && padlock1.activeInHierarchy)
|
||||
{
|
||||
//Log.Out("Lockpicking-OpenLock PLAY SOUND: audioPadlockOpen");
|
||||
audioPadlockOpen.PlayOnce();
|
||||
if (_padlockAnimator != null)
|
||||
_padlockAnimator.SetTrigger(_openTrigger);
|
||||
}
|
||||
else if (audioOpen)
|
||||
{
|
||||
//Log.Out("Lockpicking-OpenLock PLAY SOUND: audioOpen");
|
||||
audioOpen.PlayOnce();
|
||||
}
|
||||
|
||||
// Invoke the event for any other scripts that are listening
|
||||
lockOpen.Invoke();
|
||||
_lockIsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DoSqueekAudio(float speed)
|
||||
{
|
||||
if (audioSqueek)
|
||||
if (squeekRate > 0)
|
||||
{
|
||||
squeekTimer -= Mathf.Abs(speed) * Time.deltaTime;
|
||||
if (squeekTimer <= 0)
|
||||
{
|
||||
if (UnityEngine.Random.Range(0, 100) < squeekChance)
|
||||
{
|
||||
//Log.Out("Keyhole-DoSqueekAudio PLAY SOUND: audioSqueek");
|
||||
audioSqueek.PlayAudioClip(UnityEngine.Random.Range(squeekVolumeMin, squeekVolumeMax));
|
||||
}
|
||||
squeekTimer = squeekRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetAngle(float eulerAngle)
|
||||
{
|
||||
var angle = eulerAngle;
|
||||
angle %= 360;
|
||||
if (angle > 180)
|
||||
angle -= 360;
|
||||
return angle;
|
||||
}
|
||||
|
||||
private void TurnLockpick(float speed)
|
||||
{
|
||||
// If we are at or outside of our max range, return
|
||||
if (LockPickAngle() >= _pickAngleMax && speed > 0 || LockPickAngle() <= _pickAngleMin && speed < 0)
|
||||
return;
|
||||
|
||||
|
||||
// Set the new angle
|
||||
var newAngle = new Vector3(LockpickAngles().x, LockpickAngles().y,
|
||||
LockpickAngles().z + speed * Time.deltaTime);
|
||||
|
||||
SetLockpickAngles(newAngle);
|
||||
|
||||
DoClickAudio(speed, newAngle);
|
||||
}
|
||||
|
||||
private void DoClickAudio(float speed, Vector3 newAngle)
|
||||
{
|
||||
var angleMod = newAngle.z % clickRate;
|
||||
var prevMod = _lockpickAnglePrev % clickRate;
|
||||
|
||||
if (speed > 0 && angleMod < prevMod || speed < 0 && angleMod > prevMod)
|
||||
if (audioTurnClick != null)
|
||||
{
|
||||
//Log.Out("Keyhole-DoClickAudio PLAY SOUND: audioTurnClick");
|
||||
audioTurnClick.PlayAudioClip(UnityEngine.Random.Range(clickVolumeMin, clickVolumeMax));
|
||||
}
|
||||
|
||||
_lockpickAnglePrev = newAngle.z;
|
||||
}
|
||||
|
||||
private Vector3 LockpickAngles()
|
||||
{
|
||||
return lockpickObject.transform.localEulerAngles;
|
||||
}
|
||||
|
||||
private void TurnKeyhole(float speed)
|
||||
{
|
||||
// If we are at or outside of our max range, return
|
||||
if (KeyholeAngle() >= _keyholeAngleMax && speed > 0 || KeyholeAngle() <= _keyholeAngleDefault && speed < 0)
|
||||
return;
|
||||
|
||||
// Set the new angle
|
||||
SetKeyholeAngles(new Vector3(KeyholeAngles().x, KeyholeAngles().y, KeyholeAngles().z + speed * Time.deltaTime));
|
||||
|
||||
DoSqueekAudio(speed);
|
||||
}
|
||||
|
||||
private Vector3 KeyholeAngles()
|
||||
{
|
||||
return keyhole.transform.localEulerAngles;
|
||||
}
|
||||
|
||||
public float KeyholeTurnValue()
|
||||
{
|
||||
return (_keyholeAngleMax - KeyholeAngle()) / (_keyholeAngleMax - _keyholeAngleDefault);
|
||||
}
|
||||
|
||||
public void SetLock(float newLockAngle, float newLockGive, float newCloseDistance)
|
||||
{
|
||||
_lockAngle = newLockAngle;
|
||||
_lockGive = newLockGive;
|
||||
_closeDistance = newCloseDistance;
|
||||
if (audioLockpickEnter && audioLockpickEnter.isActiveAndEnabled)
|
||||
{
|
||||
//Log.Out("Lockpicking-BreakLockpick PLAY SOUND: audioLockpickEnter");
|
||||
audioLockpickEnter.DelayPlay(0.7f);
|
||||
}
|
||||
|
||||
ResetLockpickPosition();
|
||||
lockpickAnimator.SetTrigger(_lockpickInsertTrigger); // Play the animation
|
||||
}
|
||||
|
||||
public void SetLock(float lockAngleMin, float lockAngleMax, float lockGiveMin,
|
||||
float lockGiveMax, float closeDistanceMin, float closeDistanceMax)
|
||||
{
|
||||
SetLock(UnityEngine.Random.Range(lockAngleMin, lockAngleMax),
|
||||
UnityEngine.Random.Range(lockGiveMin, lockGiveMax),
|
||||
UnityEngine.Random.Range(closeDistanceMin, closeDistanceMax));
|
||||
}
|
||||
|
||||
public void ResetLock()
|
||||
{
|
||||
LockIsOpen = false;
|
||||
ProgressionValue progressionValue = null;
|
||||
var difficulty = 0;
|
||||
|
||||
var prevBreakTime = breakTime;
|
||||
var prevMaxGive = maxGiveAmount;
|
||||
|
||||
var healthLeft = blockValue.Block.MaxDamage - blockValue.damage;
|
||||
// Adjust the difficulty based on the lock damage
|
||||
if (healthLeft <= 10000)
|
||||
difficulty = 3;
|
||||
if (healthLeft <= 2500)
|
||||
difficulty = 2;
|
||||
if (healthLeft <= 400)
|
||||
difficulty = 1;
|
||||
if (healthLeft <= 200)
|
||||
difficulty = 0;
|
||||
|
||||
// give more time to avoid breaking pick locks.
|
||||
if (player != null)
|
||||
{
|
||||
var secureBlock = Block.list[blockValue.type];
|
||||
if (secureBlock != null)
|
||||
{
|
||||
|
||||
if (secureBlock.Properties.Values.ContainsKey("LockPickDifficulty"))
|
||||
difficulty = int.Parse(secureBlock.Properties.Values["LockPickDifficulty"]);
|
||||
}
|
||||
var maxGiveAmounts = "10,8,6,4".Split(','); //Configuration.GetPropertyValue("AdvancedLockpicking", "MaxGiveAmount").Split(',');
|
||||
var breakTimes = "1.2,1.0,.8,.6".Split(','); //Configuration.GetPropertyValue("AdvancedLockpicking", "BreakTime").Split(',');
|
||||
|
||||
// Default values.
|
||||
maxGiveAmount = 10f;
|
||||
breakTime = 2f;
|
||||
if (maxGiveAmounts.Length >= difficulty)
|
||||
{
|
||||
maxGiveAmount = StringParsers.ParseFloat(maxGiveAmounts[difficulty]);
|
||||
breakTime = StringParsers.ParseFloat(breakTimes[difficulty]);
|
||||
}
|
||||
|
||||
progressionValue = player.Progression.GetProgressionValue("perkLockPicking");
|
||||
if (progressionValue is { Level: > 0 })
|
||||
{
|
||||
prevBreakTime = breakTime;
|
||||
prevMaxGive = maxGiveAmount;
|
||||
breakTime += (float)progressionValue.Level / 5;
|
||||
maxGiveAmount += (float)progressionValue.Level * 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SetLock(minLockAngle, maxLockAngle,
|
||||
minGiveAmount, maxGiveAmount,
|
||||
minCloseDistance, maxCloseDistance);
|
||||
|
||||
if (GamePrefs.GetBool(EnumGamePrefs.DebugMenuEnabled))
|
||||
{
|
||||
var progression = " Progression: ";
|
||||
progression = progressionValue != null ? $"{progression} Level {progressionValue.Level} BreakTime Before: {prevBreakTime} MaxGiveAmount Before: {prevMaxGive}" : $"{progression} N/A";
|
||||
|
||||
/*Log.Out("");
|
||||
Log.Out("-------------------------------------------");
|
||||
Log.Out($"Configured Lock Pick: Break Time: {breakTime} MaxGiveAmount: {maxGiveAmount} Lock Difficulty: {difficulty} Block Damage: {healthLeft} {progression} ");
|
||||
Log.Out("Lock Angle: " + _lockAngle + " Give: " + _lockGive + " Close distance: " + _closeDistance);
|
||||
Log.Out($"MinLockAngle: {minLockAngle} MaxLockAngle: {maxLockAngle} Min Give Amount: {minGiveAmount} Max Give Amount: {maxGiveAmount} Min Close distance: {minCloseDistance} Max Close Distance: {maxCloseDistance}");
|
||||
Log.Out(" To Adjust, run console command lock 2 34");
|
||||
Log.Out(" For breaktime of 2 and maxgive of 34");
|
||||
Log.Out("-------------------------------------------");*/
|
||||
|
||||
}
|
||||
|
||||
RefreshLockPicks();
|
||||
}
|
||||
|
||||
public void ResetLockpickPosition()
|
||||
{
|
||||
SetLockpickAngles(_pickAnglesDefault);
|
||||
if (_padlockAnimator != null)
|
||||
_padlockAnimator.SetTrigger(_closeTrigger);
|
||||
}
|
||||
|
||||
public bool LockCanTurn()
|
||||
{
|
||||
return !(LockPickAngle() < GetAngle(_lockAngle) - _lockGive - _closeDistance * KeyholeTurnValue()) &&
|
||||
!(LockPickAngle() > GetAngle(_lockAngle) + _lockGive + _closeDistance * KeyholeTurnValue());
|
||||
}
|
||||
|
||||
|
||||
public bool LockComplete()
|
||||
{
|
||||
if (!LockIsOpen)
|
||||
return false;
|
||||
|
||||
|
||||
if (padlock1 != null && padlock1.activeInHierarchy)
|
||||
{
|
||||
if (_padlockAnimator != null)
|
||||
// If the padlock is fully animated
|
||||
if (_padlockAnimator.GetCurrentAnimatorStateInfo(0).IsName("Padlock1Opened"))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return !audioOpen.isAudioPlaying();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region ThirdParty
|
||||
|
||||
// Events
|
||||
private readonly UnityEvent lockpickBroke = new UnityEvent();
|
||||
private readonly UnityEvent lockOpen = new UnityEvent();
|
||||
|
||||
|
||||
[Header("Player Input")] public float openPressure;
|
||||
|
||||
public float lockpickPressure;
|
||||
|
||||
|
||||
[Header("Speed Settings")]
|
||||
[Tooltip("Speed of the lockpick when input value is full.")]
|
||||
[Range(1f, 720f)]
|
||||
public float turnSpeedLockpick = 50f;
|
||||
|
||||
[Tooltip("Speed of the entire keyhole when input value is full.")]
|
||||
[Range(1f, 720f)]
|
||||
public float turnSpeedKeyhole = 50f;
|
||||
|
||||
[Tooltip("Speed at which the lock will return to normal when the input value is 0.")]
|
||||
[Range(1f, 720f)]
|
||||
public float returnSpeedKeyhole = 150f;
|
||||
|
||||
[Tooltip("Maximum shake distance per shake change.")]
|
||||
[SerializeField]
|
||||
private float maxShake = 0.5f;
|
||||
|
||||
[Tooltip("Amount of time between shake changes when shaking.")]
|
||||
[SerializeField]
|
||||
private float shakeTime = 0.1f;
|
||||
|
||||
|
||||
[Header("Pick Settings")]
|
||||
[Tooltip("Starting angle of the lock pick.")]
|
||||
[SerializeField]
|
||||
private Vector3 _pickAnglesDefault;
|
||||
|
||||
[Tooltip("Minimum angle the lock pick can travel to.")]
|
||||
[SerializeField]
|
||||
private float _pickAngleMin = -90f;
|
||||
|
||||
[Tooltip("Maximum angle the lock pick can travel to.")]
|
||||
[SerializeField]
|
||||
private float _pickAngleMax = 90f;
|
||||
|
||||
|
||||
[Header("Keyhole Settings")]
|
||||
[Tooltip("Starting angle of the keyhole.")]
|
||||
[SerializeField]
|
||||
private float _keyholeAngleDefault = 0f;
|
||||
|
||||
[Tooltip("Maximum angle of the keyhole. At this angle, the lock will open.")]
|
||||
[SerializeField]
|
||||
private float _keyholeAngleMax = 90f;
|
||||
|
||||
|
||||
[Header("Lock Settings")]
|
||||
[Tooltip("If true, lock details will be randomized on awake")]
|
||||
public bool resetOnAwake = true;
|
||||
|
||||
[Tooltip("Minimum angle the lock can be set to.")]
|
||||
[Range(0f, 180f)]
|
||||
public float minLockAngle = -90f;
|
||||
|
||||
[Tooltip("Maximum angle the lock can be set to.")]
|
||||
[Range(0f, 180f)]
|
||||
public float maxLockAngle = 90f;
|
||||
|
||||
[Tooltip("Minimum distance (plus and minus) from the lock angle that the lock will open.")]
|
||||
[Range(1f, 180f)]
|
||||
public float minGiveAmount = 1f;
|
||||
|
||||
[Tooltip("Maximum distance (plus and minus) from the lock angle that the lock will open.")]
|
||||
[Range(1f, 180f)]
|
||||
public float maxGiveAmount = 30f;
|
||||
|
||||
[Tooltip("Minimum distance for the pick to be in for the lock will turn partially.")]
|
||||
[Range(5f, 180f)]
|
||||
public float minCloseDistance = 5f;
|
||||
|
||||
[Tooltip("Maximum distance for the pick to be in for the lock will turn partially.")]
|
||||
[Range(5f, 180f)]
|
||||
public float maxCloseDistance = 10f;
|
||||
|
||||
[Tooltip("Amount of time to ignore player input after a lock pick breaks.")]
|
||||
[Range(0f, 5f)]
|
||||
public float breakPause = 2f;
|
||||
|
||||
|
||||
[Header("Lock Details")]
|
||||
[Tooltip("True if the lock is already open (unlocked).")]
|
||||
[SerializeField]
|
||||
private bool _lockIsOpen;
|
||||
|
||||
public bool LockIsOpen
|
||||
{
|
||||
get => _lockIsOpen;
|
||||
set => _lockIsOpen = value;
|
||||
}
|
||||
|
||||
|
||||
[Tooltip("The exact angle the lock is set to.")]
|
||||
private float _lockAngle;
|
||||
|
||||
public float LockAngle
|
||||
{
|
||||
get => _lockAngle;
|
||||
set => _lockAngle = Mathf.Clamp(value, minLockAngle, maxLockAngle);
|
||||
}
|
||||
|
||||
[Tooltip("The distance to/from the LockAngle the lock pick needs to be in for the lock to open successfully.")]
|
||||
[SerializeField]
|
||||
private float _lockGive;
|
||||
|
||||
public float LockGive
|
||||
{
|
||||
get => _lockGive;
|
||||
set => _lockGive = Mathf.Clamp(value, 1, maxGiveAmount);
|
||||
}
|
||||
|
||||
[Tooltip("If the lock pick is within this distance to the angle range which the lock will open, the lock will turn partially when an open attempt is made.")]
|
||||
[SerializeField]
|
||||
private float _closeDistance;
|
||||
|
||||
public float CloseDistance
|
||||
{
|
||||
get => _closeDistance;
|
||||
set => _closeDistance = Mathf.Clamp(value, 5, maxCloseDistance);
|
||||
}
|
||||
|
||||
[Tooltip("The amount of time before a lock pick breaks when the lock is unable to be opened, but the player is attempting to open it.")]
|
||||
[Range(0f, 5f)]
|
||||
public float breakTime = 1f;
|
||||
|
||||
|
||||
[Header("Animation Trigger Strings")] public string openTrigger = "OpenPadlock";
|
||||
|
||||
public string closeTrigger = "ClosePadlock";
|
||||
public string lockPickBreakTrigger = "BreakLockpick1";
|
||||
public string lockPickInsertTrigger = "InsertLockpick";
|
||||
|
||||
// Private animation hashes
|
||||
private int _openTrigger;
|
||||
private int _closeTrigger;
|
||||
private int _lockpickBreakTrigger;
|
||||
private int _lockpickInsertTrigger;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
43
Score/LockPicking/Scripts/KeyholeDemoUI.cs
Normal file
43
Score/LockPicking/Scripts/KeyholeDemoUI.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
//using UnityEngine;
|
||||
//using UnityEngine.UI;
|
||||
//using Lockpicking;
|
||||
|
||||
//public class KeyholeDemoUI : MonoBehaviour
|
||||
//{
|
||||
|
||||
// // Set up references to the Text objects
|
||||
// public Text lockAngleText;
|
||||
// public Text lockRangeText;
|
||||
// public Text breakTimeText;
|
||||
// public Text lockpickAngleText;
|
||||
// public Text keyholeAngleText;
|
||||
// public Text closeDistanceText;
|
||||
|
||||
// public Keyhole lockpick;
|
||||
|
||||
// void Start()
|
||||
// {
|
||||
// ResetLock();
|
||||
// }
|
||||
|
||||
// void Update()
|
||||
// {
|
||||
// DrawText();
|
||||
// }
|
||||
|
||||
// private void DrawText()
|
||||
// {
|
||||
// lockAngleText.text = "" + lockpick.LockAngle;
|
||||
// lockRangeText.text = "" + Mathf.Round(lockpick.LockAngle - lockpick.LockGive) + " to " + Mathf.Round(lockpick.LockAngle + lockpick.LockGive);
|
||||
// breakTimeText.text = "" + lockpick.BreakTimeCounter;
|
||||
// lockpickAngleText.text = "" + lockpick.LockPickAngle;
|
||||
// keyholeAngleText.text = "" + lockpick.KeyholeTurnValue;
|
||||
// closeDistanceText.text = "" + lockpick.CloseDistance;
|
||||
// }
|
||||
|
||||
// public void ResetLock()
|
||||
// {
|
||||
// lockpick.ResetLock();
|
||||
// }
|
||||
//}
|
||||
|
||||
64
Score/LockPicking/Scripts/LockButton.cs
Normal file
64
Score/LockPicking/Scripts/LockButton.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using UnityEngine.Events;
|
||||
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class LockButton : MonoBehaviour
|
||||
{
|
||||
[Header("Animation Trigger Strings")] public string pressDownTrigger = "ButtonPressDown";
|
||||
|
||||
public string pressUpTrigger = "ButtonPressUp";
|
||||
|
||||
[Header("Plumbing")][SerializeField] private Animator animator;
|
||||
|
||||
public LocksetAudio audioButtonPressed;
|
||||
public LocksetAudio audioButtonReset;
|
||||
|
||||
private readonly UnityEvent buttonPressed = new UnityEvent();
|
||||
private readonly UnityEvent buttonReset = new UnityEvent();
|
||||
|
||||
private bool _isUp = true;
|
||||
private int _pressDownTrigger;
|
||||
private int _pressUpTrigger;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_pressDownTrigger = Animator.StringToHash(pressDownTrigger);
|
||||
_pressUpTrigger = Animator.StringToHash(pressUpTrigger);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.P))
|
||||
ToggleButton();
|
||||
}
|
||||
|
||||
public void ToggleButton()
|
||||
{
|
||||
if (_isUp)
|
||||
{
|
||||
animator.SetTrigger(_pressDownTrigger);
|
||||
buttonPressed.Invoke();
|
||||
//Log.Out("LockButton-ToggleButton PLAY SOUND: audioButtonPressed");
|
||||
audioButtonPressed.PlayOnce();
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.SetTrigger(_pressUpTrigger);
|
||||
buttonReset.Invoke();
|
||||
//Log.Out("LockButton-ToggleButton PLAY SOUND: audioButtonReset");
|
||||
audioButtonReset.PlayOnce();
|
||||
}
|
||||
|
||||
_isUp = !_isUp;
|
||||
}
|
||||
|
||||
public void ToggleButton(bool up)
|
||||
{
|
||||
if (up && !_isUp || !up && _isUp)
|
||||
ToggleButton();
|
||||
}
|
||||
}
|
||||
71
Score/LockPicking/Scripts/LockControls.cs
Normal file
71
Score/LockPicking/Scripts/LockControls.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using Lockpicking;
|
||||
|
||||
public class LockControls : MonoBehaviour
|
||||
{
|
||||
public Keyhole lockpick;
|
||||
PlayerActionsLocal playerActions;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!lockpick)
|
||||
return;
|
||||
|
||||
if (playerActions == null)
|
||||
{
|
||||
var player = GameManager.Instance.World.GetPrimaryPlayer();
|
||||
if (player != null)
|
||||
playerActions = player.PlayerUI.playerInput;
|
||||
|
||||
}
|
||||
if (lockpick.gameObject.activeSelf) InputControls();
|
||||
}
|
||||
|
||||
private bool Left()
|
||||
{
|
||||
if (Input.GetKey(KeyCode.JoystickButton4)) return true;
|
||||
if (Input.GetKey(KeyCode.A)) return true;
|
||||
if (Input.GetKey(KeyCode.LeftArrow)) return true;
|
||||
if (Input.mouseScrollDelta.y < 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Right()
|
||||
{
|
||||
if (Input.GetKey(KeyCode.JoystickButton5)) return true;
|
||||
if (Input.GetKey(KeyCode.D)) return true;
|
||||
if (Input.GetKey(KeyCode.RightArrow)) return true;
|
||||
if (Input.mouseScrollDelta.y > 0) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
private void InputControls()
|
||||
{
|
||||
ResetValues();
|
||||
|
||||
|
||||
if (Input.GetKey(KeyCode.Space))
|
||||
{
|
||||
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
|
||||
lockpick.openPressure = 0.4f;
|
||||
else
|
||||
lockpick.openPressure = 1f;
|
||||
}
|
||||
|
||||
if (playerActions == null) return;
|
||||
|
||||
if (Left())
|
||||
lockpick.lockpickPressure = -1f;
|
||||
|
||||
if (Right())
|
||||
lockpick.lockpickPressure = 1f;
|
||||
|
||||
//if (Input.GetKey(KeyCode.LeftArrow))
|
||||
//else if (Input.GetKey(KeyCode.RightArrow)) lockpick.lockpickPressure = 1f;
|
||||
}
|
||||
|
||||
private void ResetValues()
|
||||
{
|
||||
lockpick.openPressure = 0f;
|
||||
lockpick.lockpickPressure = 0f;
|
||||
}
|
||||
}
|
||||
36
Score/LockPicking/Scripts/LockDemoCommonControls.cs
Normal file
36
Score/LockPicking/Scripts/LockDemoCommonControls.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
//using UnityEngine;
|
||||
//using UnityEngine.UI;
|
||||
|
||||
//public class LockDemoCommonControls : MonoBehaviour
|
||||
//{
|
||||
// public GameObject canvasUI;
|
||||
// public Button[] allTextureButtons;
|
||||
|
||||
// void Update()
|
||||
// {
|
||||
// if (Input.GetKeyDown(KeyCode.C))
|
||||
// canvasUI.SetActive(!canvasUI.activeSelf);
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha1))
|
||||
// allTextureButtons[0].onClick.Invoke();
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha2))
|
||||
// allTextureButtons[1].onClick.Invoke();
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha3))
|
||||
// allTextureButtons[2].onClick.Invoke();
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha4))
|
||||
// allTextureButtons[3].onClick.Invoke();
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha5))
|
||||
// allTextureButtons[4].onClick.Invoke();
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha6))
|
||||
// allTextureButtons[5].onClick.Invoke();
|
||||
|
||||
// if (Input.GetKeyDown(KeyCode.Alpha7))
|
||||
// allTextureButtons[6].onClick.Invoke();
|
||||
// }
|
||||
//}
|
||||
|
||||
146
Score/LockPicking/Scripts/LockEmissive.cs
Normal file
146
Score/LockPicking/Scripts/LockEmissive.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
public class LockEmissive : MonoBehaviour
|
||||
{
|
||||
[Header("Behavior")] public bool pulse = true;
|
||||
|
||||
public bool breakpoint;
|
||||
public bool success;
|
||||
public bool off;
|
||||
|
||||
[Header("Settings")][Range(0f, 5f)] public float pulseSpeedMod = 0.5f;
|
||||
|
||||
[Header("Colors")] public Color hightlightColor = Color.yellow;
|
||||
|
||||
public Color[] colors = { Color.cyan, Color.red, Color.yellow, Color.green, Color.blue, Color.magenta, Color.white, Color.grey, Color.yellow, Color.blue };
|
||||
|
||||
[Header("Renderers")][SerializeField] private Renderer[] _renderers;
|
||||
|
||||
public Renderer highlightRenderer;
|
||||
|
||||
// Hidden from Inspector
|
||||
[HideInInspector] public float breakpointValue;
|
||||
[HideInInspector] public float successValue;
|
||||
private int _colorIndex;
|
||||
|
||||
// Private variables
|
||||
private float _pulseValue;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (off)
|
||||
{
|
||||
SetAllMaterials(0f);
|
||||
}
|
||||
else if (pulse)
|
||||
{
|
||||
_pulseValue = Mathf.PingPong(Time.time * pulseSpeedMod, 1); // Pulse the value over time
|
||||
SetAllMaterials(_pulseValue); // Set the values
|
||||
}
|
||||
else if (breakpoint)
|
||||
{
|
||||
SetAllMaterials(breakpointValue); // Set the values
|
||||
}
|
||||
else if (success)
|
||||
{
|
||||
SetAllMaterials(Mathf.Clamp(Mathf.Abs(successValue - 1), 0, 1)); // Set the values
|
||||
}
|
||||
|
||||
if (highlightRenderer)
|
||||
SetHighlightMaterial();
|
||||
}
|
||||
|
||||
private Color _activeColor()
|
||||
{
|
||||
return colors[_colorIndex];
|
||||
}
|
||||
|
||||
public void SetRenders(Renderer[] newRenders)
|
||||
{
|
||||
_renderers = newRenders;
|
||||
}
|
||||
|
||||
public void SetHighlightRenderer(Renderer value)
|
||||
{
|
||||
highlightRenderer = value;
|
||||
}
|
||||
|
||||
private void SetHighlightMaterial()
|
||||
{
|
||||
// sphereii: disable the high light color
|
||||
//highlightRenderer.material.SetColor("_EmissionColor", hightlightColor);
|
||||
highlightRenderer.material.SetColor("_EmissionColor", Color.clear);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all materials attached to the renderers array
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
private void SetAllMaterials(float value)
|
||||
{
|
||||
if (_renderers == null) return;
|
||||
for (var i = 0; i < _renderers.Length; i++)
|
||||
if (_renderers[i] != null && _renderers[i].gameObject != null)
|
||||
if (_renderers[i].gameObject.activeSelf)
|
||||
SetMaterial(_renderers[i].material, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a single material
|
||||
/// </summary>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="value"></param>
|
||||
private void SetMaterial(Material material, float value)
|
||||
{
|
||||
var finalColor = _activeColor() * Mathf.LinearToGammaSpace(value);
|
||||
|
||||
//material.SetColor("_EmissionColor", finalColor);
|
||||
|
||||
// sphereii: give it a nice bronze color
|
||||
material.SetColor("_EmissionColor", new Color(0.666f, 0.588f, 0.275f, 1f));
|
||||
}
|
||||
|
||||
public void NextColor()
|
||||
{
|
||||
_colorIndex = _colorIndex + 1 >= colors.Length ? 0 : _colorIndex + 1;
|
||||
}
|
||||
|
||||
public void PrevColor()
|
||||
{
|
||||
_colorIndex = _colorIndex - 1 < 0 ? colors.Length - 1 : _colorIndex - 1;
|
||||
}
|
||||
|
||||
public void SetPulse()
|
||||
{
|
||||
pulse = true;
|
||||
breakpoint = false;
|
||||
success = false;
|
||||
off = false;
|
||||
}
|
||||
|
||||
public void SetBreakpoint()
|
||||
{
|
||||
pulse = false;
|
||||
breakpoint = true;
|
||||
success = false;
|
||||
off = false;
|
||||
}
|
||||
|
||||
public void SetSuccess()
|
||||
{
|
||||
pulse = false;
|
||||
breakpoint = false;
|
||||
success = true;
|
||||
off = false;
|
||||
}
|
||||
|
||||
public void SetOff()
|
||||
{
|
||||
pulse = false;
|
||||
breakpoint = false;
|
||||
success = false;
|
||||
off = true;
|
||||
}
|
||||
}
|
||||
51
Score/LockPicking/Scripts/LockEmissiveControls.cs
Normal file
51
Score/LockPicking/Scripts/LockEmissiveControls.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
public class LockEmissiveControls : MonoBehaviour
|
||||
{
|
||||
public Renderer[] baseplate1;
|
||||
public Renderer[] baseplate2;
|
||||
public Renderer[] lock1;
|
||||
public Renderer[] lock2;
|
||||
public Renderer[] lock3;
|
||||
public Renderer[] button;
|
||||
public Renderer[] padlock1;
|
||||
public Renderer[] padlock2;
|
||||
|
||||
public void SetBaseplate1(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < baseplate1.Length; i++) baseplate1[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetBaseplate2(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < baseplate2.Length; i++) baseplate2[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetLock1(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < lock1.Length; i++) lock1[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetLock2(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < lock2.Length; i++) lock2[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetLock3(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < lock3.Length; i++) lock3[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetButton(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < button.Length; i++) button[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetPadlock1(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < padlock1.Length; i++) padlock1[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
|
||||
public void SetPadlock2(Texture newTexture)
|
||||
{
|
||||
for (var i = 0; i < padlock2.Length; i++) padlock2[i].material.SetTexture("_EmissionMap", newTexture);
|
||||
}
|
||||
}
|
||||
61
Score/LockPicking/Scripts/LockObjectRotation.cs
Normal file
61
Score/LockPicking/Scripts/LockObjectRotation.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
public class LockObjectRotation : MonoBehaviour
|
||||
{
|
||||
public bool mouseMovementOn;
|
||||
[SerializeField] private float maxX = 30f; // Max rotation
|
||||
[SerializeField] private float maxY = 30f; // Max rotation
|
||||
|
||||
[SerializeField] private Vector3 mousePosition; // last position of mouse
|
||||
[SerializeField] private float speed = 2160f; // speed of rotation
|
||||
[SerializeField] private float startX; // Starting rotation
|
||||
[SerializeField] private float startY; // Starting rotation
|
||||
public Camera uiCam;
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
startX = GetAngle(transform.localEulerAngles.x);
|
||||
startY = GetAngle(transform.localEulerAngles.y);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
MouseMovement();
|
||||
mousePosition = uiCam.ScreenToViewportPoint(Input.mousePosition); // Save mouse position every frame.
|
||||
//mousePosition = Camera.main.ScreenToViewportPoint(Input.mousePosition); // Save mouse position every frame.
|
||||
}
|
||||
|
||||
private void MouseMovement()
|
||||
{
|
||||
// If we are holding down the left mouse button...
|
||||
if (Input.GetMouseButton(0) || mouseMovementOn)
|
||||
{
|
||||
// Grab the new position of the mouse, 0,0 - 1,1
|
||||
var newPosition = uiCam.ScreenToViewportPoint(Input.mousePosition);
|
||||
//Vector3 newPosition = Camera.main.ScreenToViewportPoint(Input.mousePosition);
|
||||
|
||||
// Compute the delta in the x and y positions. Do inversion for the yDelta. Note X/Y are flipped.
|
||||
var horDelta = -(newPosition.x - mousePosition.x) * speed * Time.deltaTime;
|
||||
var verDelta = (newPosition.y - mousePosition.y) * speed * Time.deltaTime;
|
||||
|
||||
// Make sure we don't go over our max range
|
||||
if (GetAngle(transform.localEulerAngles.x) + verDelta > startX + maxX || GetAngle(transform.localEulerAngles.x) + verDelta < startX - maxX)
|
||||
verDelta = 0;
|
||||
if (GetAngle(transform.localEulerAngles.y) + horDelta > startY + maxY || GetAngle(transform.localEulerAngles.y) + horDelta < startY - maxY)
|
||||
horDelta = 0;
|
||||
|
||||
// Compute & assign the new angle
|
||||
var newAngles = new Vector3(transform.localEulerAngles.x + verDelta,
|
||||
transform.localEulerAngles.y + horDelta, transform.localEulerAngles.z);
|
||||
transform.localEulerAngles = newAngles;
|
||||
}
|
||||
}
|
||||
|
||||
private float GetAngle(float eulerAngle)
|
||||
{
|
||||
var angle = eulerAngle;
|
||||
angle %= 360;
|
||||
if (angle > 180)
|
||||
angle -= 360;
|
||||
return angle;
|
||||
}
|
||||
}
|
||||
75
Score/LockPicking/Scripts/LocksetAudio.cs
Normal file
75
Score/LockPicking/Scripts/LocksetAudio.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System.Collections;
|
||||
|
||||
[RequireComponent(typeof(AudioSource))]
|
||||
public class LocksetAudio : MonoBehaviour
|
||||
{
|
||||
public AudioClip[] clips;
|
||||
private float _delay;
|
||||
private AudioSource audioSource;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
audioSource = GetComponent<AudioSource>();
|
||||
}
|
||||
|
||||
public void PlayAudioClip(float volume = 0.5f)
|
||||
{
|
||||
if (clips == null)
|
||||
return;
|
||||
|
||||
if (clips.Length > 0)
|
||||
{
|
||||
SelectRandomClip();
|
||||
audioSource.volume = volume;
|
||||
audioSource.Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayOnce()
|
||||
{
|
||||
SelectRandomClip();
|
||||
if (audioSource.clip == null)
|
||||
return;
|
||||
|
||||
audioSource.PlayOneShot(audioSource.clip);
|
||||
}
|
||||
|
||||
public bool isAudioPlaying()
|
||||
{
|
||||
return audioSource.isPlaying;
|
||||
}
|
||||
|
||||
public void DelayPlay(float delay)
|
||||
{
|
||||
_delay = delay;
|
||||
StartCoroutine("Delay");
|
||||
}
|
||||
|
||||
public IEnumerator Delay()
|
||||
{
|
||||
yield return new WaitForSeconds(_delay);
|
||||
PlayOnce();
|
||||
}
|
||||
|
||||
public void PlayLoop()
|
||||
{
|
||||
if (!audioSource.isPlaying)
|
||||
{
|
||||
SelectRandomClip();
|
||||
audioSource.Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopLoop()
|
||||
{
|
||||
audioSource.Pause();
|
||||
}
|
||||
|
||||
public void SelectRandomClip()
|
||||
{
|
||||
if (clips == null)
|
||||
return;
|
||||
|
||||
if (clips.Length > 0) audioSource.clip = clips[UnityEngine.Random.Range(0, clips.Length)];
|
||||
}
|
||||
}
|
||||
175
Score/LockPicking/Scripts/SphereII_Locks.cs
Normal file
175
Score/LockPicking/Scripts/SphereII_Locks.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using Lockpicking;
|
||||
using System.Collections.Generic;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
|
||||
// This class sites between the thirdparty Keyhole script + prefabs and support scripts.
|
||||
public class SphereLocks
|
||||
{
|
||||
private GameObject _lockPick;
|
||||
|
||||
private GameObject _lockPickAsset;
|
||||
|
||||
// transforms
|
||||
private List<string> _transforms = new List<string>();
|
||||
|
||||
public void Init(BlockValue blockValue, Vector3i blockPos)
|
||||
{
|
||||
// Check if the current block has a pre-defined lockpick prefab
|
||||
var lockPrefab = "";
|
||||
if (blockValue.type != 0)
|
||||
if (blockValue.Block.Properties.Contains("LockPrefab"))
|
||||
lockPrefab = blockValue.Block.Properties.GetStringValue("LockPrefab");
|
||||
|
||||
|
||||
// Load up the default.
|
||||
if (string.IsNullOrEmpty(lockPrefab))
|
||||
{
|
||||
// If the globally configured lock pick cotnains Lockset01, assume its the default.
|
||||
lockPrefab = "#@modfolder(Locks):Resources/Locks.unity3d?Lockset01"; // Configuration.GetPropertyValue("AdvancedLockpicking", "LockPrefab");
|
||||
if (lockPrefab.EndsWith("Lockset01"))
|
||||
{
|
||||
var locks = new List<string> { "Lockset01", "Lockset02", "Lockset03", "Lockset04", "padlock01" };
|
||||
var randomKey = Math.Abs(blockPos.x % 9);
|
||||
var randomLock = randomKey switch
|
||||
{
|
||||
< 1 => "Lockset01",
|
||||
< 3 => "Lockset02",
|
||||
< 5 => "Lockset03",
|
||||
< 7 => "Lockset04",
|
||||
_ => "padlock01"
|
||||
};
|
||||
|
||||
lockPrefab = lockPrefab.Replace("Lockset01", randomLock);
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(lockPrefab))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_lockPickAsset = DataLoader.LoadAsset<GameObject>(lockPrefab);
|
||||
_lockPick = Object.Instantiate(_lockPickAsset);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Out($"LockPrefab not valid. Falling back to vanilla.");
|
||||
return;
|
||||
}
|
||||
Disable();
|
||||
|
||||
|
||||
// Marked transforms
|
||||
_transforms = new List<string> { "Baseplate1", "Baseplate2", "ButtonInner", "ButtonInner", "ButtonOuter", "Padlock1_low" };
|
||||
_transforms.AddRange(new List<string> { "Padlock1_Latch_low", "Lock1Outer", "Lock2Outer", "Lock3Outer", "Lock1Inner", "Lock2Inner", "Lock3Inner" });
|
||||
|
||||
if (_lockPick.GetComponent<Keyhole>() == null)
|
||||
{
|
||||
// Populate the Keyhole
|
||||
var keyhole = _lockPick.AddComponent<Keyhole>();
|
||||
keyhole.keyhole = FindTransform("Keyhole (Turnable)").gameObject;
|
||||
|
||||
// attach the lock control the to top level
|
||||
LockControls lockControl;
|
||||
if (_lockPick.transform.parent != null)
|
||||
lockControl = _lockPick.transform.parent.gameObject.AddComponent<LockControls>();
|
||||
else
|
||||
lockControl = _lockPick.transform.gameObject.AddComponent<LockControls>();
|
||||
|
||||
lockControl.lockpick = keyhole;
|
||||
|
||||
// Lock Pick configuration
|
||||
keyhole.lockpickObject = _lockPick.transform.FindInChilds("LockpickB (Turnable)").gameObject;
|
||||
keyhole.lockpickAnimator = FindTransform("LockpickB").GetComponent<Animator>();
|
||||
keyhole.lockpickAnimator.gameObject.SetActive(true);
|
||||
|
||||
keyhole.blockValue = blockValue;
|
||||
var cam = FindTransform("Cam2").GetComponentInChildren<Camera>();
|
||||
if (cam != null)
|
||||
{
|
||||
cam.rect = new Rect(0.25f, 0.25f, 0.5f, 0.5f);
|
||||
var lockObjectRotation = keyhole.lockpickObject.transform.gameObject.AddComponent<LockObjectRotation>();
|
||||
lockObjectRotation.uiCam = cam;
|
||||
}
|
||||
|
||||
var padlock = FindTransform("Padlock1");
|
||||
if (padlock != null)
|
||||
{
|
||||
keyhole.padlock1 = padlock.gameObject;
|
||||
keyhole.audioPadlockJiggle = FindTransform("Audio Padlock Jiggle").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioPadlockOpen = FindTransform("Audio Padlock Open").gameObject.AddComponent<LocksetAudio>();
|
||||
}
|
||||
|
||||
// audio configuration
|
||||
keyhole.audioTurnClick = FindTransform("Audio Turn Click").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioSqueek = FindTransform("Audio Squeek").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioOpen = FindTransform("Audio Open").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioJiggle = FindTransform("Audio Jiggle A").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioJiggle2 = FindTransform("Audio Jiggle B").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioJiggle3 = FindTransform("Audio Jiggle C").gameObject.AddComponent<LocksetAudio>();
|
||||
|
||||
keyhole.audioLockpickBreak = FindTransform("Audio Lockpick Break").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioLockpickEnter = FindTransform("Audio Lockpick Enter").gameObject.AddComponent<LocksetAudio>();
|
||||
keyhole.audioLockpickClick = FindTransform("Audio Lockpick Click").gameObject.AddComponent<LocksetAudio>();
|
||||
|
||||
var lockEmissive = _lockPick.AddComponent<LockEmissive>();
|
||||
// lockEmissive.off = true;
|
||||
var lstRenders = new List<Renderer>();
|
||||
var tempRender = new Renderer[12];
|
||||
|
||||
foreach (var transform in _transforms)
|
||||
{
|
||||
var temp = FindTransform(transform);
|
||||
if (temp)
|
||||
lstRenders.Add(FindTransform(transform).GetComponent<MeshRenderer>());
|
||||
}
|
||||
|
||||
lockEmissive.SetRenders(lstRenders.ToArray());
|
||||
}
|
||||
|
||||
Enable();
|
||||
}
|
||||
|
||||
|
||||
public Keyhole GetScript()
|
||||
{
|
||||
return _lockPick != null ? _lockPick.GetComponent<Keyhole>() : null;
|
||||
}
|
||||
|
||||
public bool IsLockOpened()
|
||||
{
|
||||
return _lockPick != null && _lockPick.GetComponent<Keyhole>().LockComplete();
|
||||
}
|
||||
|
||||
public void SetPlayer(EntityPlayer player)
|
||||
{
|
||||
if (_lockPick != null) _lockPick.GetComponent<Keyhole>().player = player;
|
||||
}
|
||||
|
||||
private Transform FindTransform(string target)
|
||||
{
|
||||
return _lockPick.transform.FindInChilds(target);
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
if (_lockPick == null) return;
|
||||
_lockPick.SetActive(true);
|
||||
_lockPick.GetComponent<Keyhole>().ResetLock();
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
if (_lockPick != null)
|
||||
{
|
||||
Keyhole keyhole = _lockPick.GetComponent<Keyhole>();
|
||||
if (keyhole != null && keyhole.breakTimeCounter > 0)
|
||||
{
|
||||
//Log.Out("Sphereii_Locks Disabled START, breakTimeCounter: " + keyhole.breakTimeCounter);
|
||||
keyhole.BreakLockpick();
|
||||
}
|
||||
_lockPick.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Score/LockPicking/XUiC/XUiC_PickLocking.cs
Normal file
88
Score/LockPicking/XUiC/XUiC_PickLocking.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
// Simple XUI screen to enable the lock picking to have a window-style pop up.
|
||||
|
||||
public class XUiC_PickLocking : XUiController
|
||||
{
|
||||
public static string ID = "";
|
||||
private Vector3i blockPos;
|
||||
private BlockValue currentBlock;
|
||||
private SphereLocks Lock;
|
||||
|
||||
// Reference to our current locked container
|
||||
private ILockable LockedItem;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Lock = new SphereLocks();
|
||||
ID = windowGroup.ID;
|
||||
base.Init();
|
||||
}
|
||||
|
||||
public override void Update(float _dt)
|
||||
{
|
||||
base.Update(_dt);
|
||||
if (LockedItem == null)
|
||||
return;
|
||||
|
||||
// Check if the lock is open
|
||||
if (Lock.IsLockOpened())
|
||||
{
|
||||
LockedItem.SetLocked(false);
|
||||
OnClose();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the container reference so we can unlock it.
|
||||
public static void Open(LocalPlayerUI playerUi, ILockable lockedItem, BlockValue blockValue, Vector3i blockPos)
|
||||
{
|
||||
// Configure the lock pick
|
||||
playerUi.xui.FindWindowGroupByName(ID).GetChildByType<XUiC_PickLocking>().LockedItem = lockedItem;
|
||||
playerUi.xui.FindWindowGroupByName(ID).GetChildByType<XUiC_PickLocking>().currentBlock = blockValue;
|
||||
playerUi.xui.FindWindowGroupByName(ID).GetChildByType<XUiC_PickLocking>().blockPos = blockPos;
|
||||
playerUi.windowManager.Open(ID, true);
|
||||
}
|
||||
|
||||
// Set the player reference and display the lock.
|
||||
public override void OnOpen()
|
||||
{
|
||||
EntityPlayer player = xui.playerUI.entityPlayer;
|
||||
base.OnOpen();
|
||||
Lock = new SphereLocks();
|
||||
|
||||
// Pass the Player reference to the lock before we enable.
|
||||
Lock.Init(currentBlock, blockPos);
|
||||
Lock.SetPlayer(player);
|
||||
Lock.Enable();
|
||||
if (!ThreadManager.IsMainThread()) return;
|
||||
xui.playerUI.entityPlayer.PlayOneShot("open_sign");
|
||||
}
|
||||
|
||||
public override void OnClose()
|
||||
{
|
||||
if (Lock.IsLockOpened())
|
||||
{
|
||||
var blockValue = BlockValue.Air;
|
||||
if (!currentBlock.Block.LockpickDowngradeBlock.isair)
|
||||
{
|
||||
blockValue = currentBlock.Block.LockpickDowngradeBlock;
|
||||
}
|
||||
else if (!currentBlock.Block.DowngradeBlock.isair)
|
||||
{
|
||||
blockValue = currentBlock.Block.DowngradeBlock;
|
||||
}
|
||||
|
||||
if (!blockValue.isair)
|
||||
{
|
||||
blockValue = BlockPlaceholderMap.Instance.Replace(blockValue, GameManager.Instance.World.GetGameRandom(), blockPos.x, blockPos.z, false);
|
||||
blockValue.rotation = currentBlock.rotation;
|
||||
blockValue.meta = currentBlock.meta;
|
||||
GameManager.Instance.World.SetBlockRPC(0, blockPos, blockValue, blockValue.Block.Density);
|
||||
}
|
||||
}
|
||||
Lock.Disable();
|
||||
LockedItem = null;
|
||||
base.OnClose();
|
||||
xui.playerUI.windowManager.Close(ID);
|
||||
if (!ThreadManager.IsMainThread()) return;
|
||||
xui.playerUI.entityPlayer.PlayOneShot("close_sign");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user