Testing Phase

Basics are implemented. Needs playtesting before potential rewrite and implementation of avatar parameters & manual control.
This commit is contained in:
NotAKidoS 2022-10-12 22:46:17 -05:00
parent c049d93d55
commit d033d3750e
8 changed files with 541 additions and 82 deletions

View file

@ -1,12 +1,7 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using HarmonyLib;
using ABI_RC.Core.Player;
using ABI_RC.Core.UI;
using MelonLoader;
using RootMotion.FinalIK;
using UnityEngine;
using UnityEngine.Events;
namespace Blackout;
@ -20,11 +15,21 @@ namespace Blackout;
1 - Drowsy (partial effect)
2 - Sleep (full effect)
After staying still for DrowsyModeTimer (minutes), you enter DrowsyMode.
This mode dims the screen to your selected dimming strength.
After continuing to stay still for SleepModeTimer (seconds), you enter SleepMode.
This mode overrenders mostly everything with black.
Slight movement while in SleepMode will place you in DrowsyMode until SleepModeTimer is reached again.
Hard movement once entering DrowsyMode will fully wake you and return complete vision.
*/
public class BlackoutController : MonoBehaviour
{
public int BlackoutState = 0;
public static BlackoutController Instance;
public BlackoutState CurrentState = BlackoutState.Awake;
//degrees of movement to give partial vision
public float drowsyThreshold = 1f;
@ -32,81 +37,190 @@ public class BlackoutController : MonoBehaviour
public float wakeThreshold = 12f;
//how long without movement until the screen dims
public float enterSleepTime = 3f; // MINUTES
public float DrowsyModeTimer = 3f; // MINUTES
//how long should the wake state last before return
public float returnSleepTime = 10f; // SECONDS
public float SleepModeTimer = 10f; // SECONDS
//how much does DrowsyMode affect the screen
public float DrowsyDimStrength = 0.5f;
//this is uh, not work well- might rewrite now that i know how this should work
public bool HudMessages = false;
public enum BlackoutState
{
Awake = 0,
Drowsy,
Sleeping,
}
//private BlackoutController instance;
private Quaternion oldHeadRotation = Quaternion.identity;
private float angularMovement = 0f;
private float curTime = 0f;
private float lastAwakeTime = 0f;
private int nextUpdate = 1;
private Animator blackoutAnimator;
public void ChangeBlackoutState(BlackoutState newState)
{
if (!blackoutAnimator) return;
if (newState == CurrentState) return;
lastAwakeTime = curTime;
switch (newState)
{
case BlackoutState.Awake:
blackoutAnimator.SetBool("BlackoutState.Drowsy", false);
blackoutAnimator.SetBool("BlackoutState.Sleeping", false);
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyPartial", DrowsyDimStrength);
break;
case BlackoutState.Drowsy:
blackoutAnimator.SetBool("BlackoutState.Drowsy", true);
blackoutAnimator.SetBool("BlackoutState.Sleeping", false);
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyPartial", DrowsyDimStrength);
break;
case BlackoutState.Sleeping:
blackoutAnimator.SetBool("BlackoutState.Drowsy", false);
blackoutAnimator.SetBool("BlackoutState.Sleeping", true);
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyPartial", DrowsyDimStrength);
break;
default:
break;
}
BlackoutState prevState = CurrentState;
CurrentState = newState;
SendHUDMessage($"Exiting {prevState} and entering {newState} state.");
}
void Update()
{
//only run once a second, angularMovement is "smoothed out" at high FPS otherwise
float curTime = Time.time;
//for the sake of responsivness while user is in a sleepy state, this might be removed to prevent confusion...
curTime = Time.time;
if (!(curTime >= nextUpdate)) return;
nextUpdate = Mathf.FloorToInt(curTime) + 1;
//get difference between last frame rotation and current rotation
Quaternion currentHeadRotation = PlayerSetup.Instance.GetActiveCamera().transform.rotation;
float angularMovement = Quaternion.Angle(oldHeadRotation, currentHeadRotation);
angularMovement = Quaternion.Angle(oldHeadRotation, currentHeadRotation);
oldHeadRotation = currentHeadRotation;
// These are SOFT movements
//handle current state
switch (CurrentState)
{
case BlackoutState.Awake:
HandleAwakeState();
break;
case BlackoutState.Drowsy:
HandleDrowsyState();
break;
case BlackoutState.Sleeping:
HandleSleepingState();
break;
default:
break;
}
//debug
//MelonLogger.Msg("curTime " + curTime);
//MelonLogger.Msg("lastAwakeTime " + lastAwakeTime);
//MelonLogger.Msg("timeleft " + GetNextStateTimer());
//MelonLogger.Msg("current state " + CurrentState);
}
//initialize BlackoutInstance object
void Start()
{
Instance = this;
GameObject blackoutAsset = AssetsHandler.GetAsset("Assets/BundledAssets/Blackout/Blackout.prefab");
GameObject blackoutGO = Instantiate(blackoutAsset, new Vector3(0, 0, 0), Quaternion.identity);
if (blackoutGO != null)
{
blackoutGO.name = "BlackoutInstance";
blackoutAnimator = blackoutGO.GetComponent<Animator>();
SetupBlackoutInstance();
}
}
void OnEnabled()
{
if (!blackoutAnimator) return;
blackoutAnimator.gameObject.SetActive(true);
}
void OnDisabled()
{
ChangeBlackoutState(BlackoutState.Awake);
if (!blackoutAnimator) return;
blackoutAnimator.gameObject.SetActive(false);
}
public void SetupBlackoutInstance()
{
blackoutAnimator.transform.parent = PlayerSetup.Instance.GetActiveCamera().transform;
blackoutAnimator.transform.localPosition = Vector3.zero;
blackoutAnimator.transform.localRotation = Quaternion.identity;
blackoutAnimator.transform.localScale = Vector3.one;
}
private float GetNextStateTimer()
{
switch (CurrentState)
{
case BlackoutState.Awake:
return (lastAwakeTime + DrowsyModeTimer * 60 - curTime);
case BlackoutState.Drowsy:
return (lastAwakeTime + SleepModeTimer - curTime);
case BlackoutState.Sleeping:
return 0f;
default:
return 0f;
}
}
//broken, needs to run next frame
private void SendHUDMessage(string message)
{
MelonLogger.Msg(message);
if (!CohtmlHud.Instance || !HudMessages) return;
CohtmlHud.Instance.ViewDropTextImmediate("Blackout", message, GetNextStateTimer().ToString() + " seconds till next state change.");
}
private void HandleAwakeState()
{
//small movement should reset sleep timer
if (angularMovement > drowsyThreshold)
{
lastAwakeTime = curTime;
if (BlackoutState == 2)
{
BlackoutState = 1;
MelonLogger.Msg("Exited Sleep state and entered Drowsy state.");
}
}
// These are HARD movements
//enter drowsy mode after few minutes
if (curTime > lastAwakeTime + DrowsyModeTimer * 60)
{
ChangeBlackoutState(BlackoutState.Drowsy);
}
}
private void HandleDrowsyState()
{
//hard movement should exit drowsy state
if (angularMovement > wakeThreshold)
{
lastAwakeTime = curTime;
if (BlackoutState == 0) return;
BlackoutState = 0;
MelonLogger.Msg("Exited anystate and entered Awake state.");
ChangeBlackoutState(BlackoutState.Awake);
}
MelonLogger.Msg($"BlackoutState " + BlackoutState);
MelonLogger.Msg($"curTime " + curTime);
MelonLogger.Msg($"lastAwakeTime " + lastAwakeTime);
if (BlackoutState == 2) return;
//check if we should enter/return to sleep mode
if (curTime > lastAwakeTime + (BlackoutState == 0 ? enterSleepTime * 60 : returnSleepTime))
//enter full sleep mode
if (curTime > lastAwakeTime + SleepModeTimer)
{
BlackoutState = 2;
MelonLogger.Msg("Entered sleep state.");
ChangeBlackoutState(BlackoutState.Sleeping);
}
}
void Start()
private void HandleSleepingState()
{
MelonLogger.Msg(Application.streamingAssetsPath);
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "blackoutfader"));
if (myLoadedAssetBundle == null)
//small movement should enter drowsy state
if (angularMovement > drowsyThreshold)
{
Debug.Log("Failed to load AssetBundle!");
return;
ChangeBlackoutState(BlackoutState.Drowsy);
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
Instantiate(prefab);
myLoadedAssetBundle.Unload(false);
prefab.transform.parent = PlayerSetup.Instance.GetActiveCamera().transform;
prefab.transform.localPosition = Vector3.zero;
prefab.transform.localRotation = Quaternion.identity;
prefab.transform.localScale = Vector3.zero;
}
}