658 lines
21 KiB
C#
658 lines
21 KiB
C#
using Invector.vCamera;
|
|
using PixelCrushers.DialogueSystem;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using PixelCrushers.QuestMachine;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Playables;
|
|
using Sirenix.OdinInspector;
|
|
using QuestState = PixelCrushers.QuestMachine.QuestState;
|
|
using PixelCrushers;
|
|
|
|
namespace Beyond
|
|
{
|
|
[Serializable]
|
|
public class CutsceneSaveData
|
|
{
|
|
public bool wasPlayed;
|
|
}
|
|
|
|
[RequireComponent(typeof(PlayableDirector))]
|
|
public class CutScene : Saver
|
|
{
|
|
public static Action<bool> CutSceneEnable;
|
|
|
|
[Header("Conditions"), Tooltip("Leave it empty if you want this to play every time")]
|
|
public Condition m_condition;
|
|
|
|
[Header("Start Cutscene")] public GameObject[] toEnableOnStart;
|
|
public GameObject[] toDisableOnStart;
|
|
public UnityEvent m_onStartEvent;
|
|
|
|
[Header("End Cutscene")] public GameObject[] toEnableOnEnd;
|
|
public GameObject[] toDisableOnEnd;
|
|
public UnityEvent m_onEndEvent;
|
|
|
|
[Space]
|
|
[Tooltip("Depricated! don't use. Left to make sure some settings won't be lost (before copping)")]
|
|
public FadeSettings fadeSettings;
|
|
|
|
public bool m_completeCurrentQuest = false;
|
|
|
|
private float m_fadeTime = 1f;
|
|
public TeleportObject teleport;
|
|
public bool playOnStart = false;
|
|
|
|
//public bool playOnce = true;
|
|
public bool playMultipleTimes = false;
|
|
|
|
[TitleGroup("Skip Fade")]
|
|
public bool skipFadeOutIn = false;
|
|
|
|
[TitleGroup("Skip Fade")]
|
|
public bool skipFadeIn = false;
|
|
|
|
private bool timelineStarted;
|
|
private PlayableDirector m_playableDirector;
|
|
private Camera[] cameras;
|
|
private bool timeLineStoped;
|
|
private PlayState timeLineState = PlayState.Paused;
|
|
|
|
[Header("Debug"), SerializeField, Min(0.001f)]
|
|
private float m_speed = 1f;
|
|
|
|
private AudioListener[] audioListeners;
|
|
private CutSceneLerpCamera lerpCamera;
|
|
private StandardBarkUI m_barkUI;
|
|
private Camera playerCamera;
|
|
private bool cancelAlphaWait;
|
|
private Coroutine cancelAlpha;
|
|
private bool followTarget;
|
|
private Camera lastUseCamera;
|
|
private float cutSceneTimer;
|
|
private float nearestStopTime;
|
|
private CutSceneDialogueBreakpoint currentDialogueBreakpoint;
|
|
private int currentDialogueBreakpointIndex = 0;
|
|
private bool wasPlayed;
|
|
private bool wasLoaded;
|
|
|
|
public bool WasPlayed
|
|
{
|
|
set { wasPlayed = value; }
|
|
get { return wasPlayed; }
|
|
}
|
|
|
|
[SerializeField] private CutsceneLevelLoader m_cutsceneLevelLoader = new CutsceneLevelLoader();
|
|
|
|
[Space]
|
|
[Header("Breakpoints")]
|
|
[SerializeField]
|
|
private List<CutSceneBreakpoint> cutSceneBreakpoints = new List<CutSceneBreakpoint>();
|
|
|
|
[SerializeField]
|
|
private List<CutSceneDialogueBreakpoint> cutSceneDialogueBreakpoints = new List<CutSceneDialogueBreakpoint>();
|
|
|
|
private bool CanStart
|
|
{
|
|
get
|
|
{
|
|
if (wasPlayed && !playMultipleTimes)
|
|
return false;
|
|
return m_condition.IsTrue(Player.Instance.transform);
|
|
}
|
|
}
|
|
|
|
public bool TimelineStarted
|
|
{
|
|
get => timelineStarted;
|
|
set => timelineStarted = value;
|
|
}
|
|
|
|
public override void Awake()
|
|
{
|
|
base.Awake();
|
|
//fadeSettings.CreateInverseEndFadeCurve();
|
|
m_playableDirector = GetComponent<PlayableDirector>();
|
|
m_playableDirector.playOnAwake = false;
|
|
cameras = GetComponentsInChildren<Camera>(true);
|
|
audioListeners = GetComponentsInChildren<AudioListener>(true);
|
|
SetActiveCameras(false);
|
|
SetActiveAudioListener(false);
|
|
var tpCam = FindObjectOfType<vThirdPersonCamera>();
|
|
if (tpCam)
|
|
playerCamera = tpCam.GetComponent<Camera>();
|
|
wasPlayed = false;
|
|
}
|
|
|
|
private IEnumerator Start()
|
|
{
|
|
//lil hack to prevent starting cutscenes while loading, person to blame -> Seba
|
|
//yield return new WaitForSeconds(0.1f);
|
|
yield return null;
|
|
yield return null;
|
|
m_barkUI = GameObject.FindObjectOfType<StandardBarkUI>();
|
|
if (CanStart)
|
|
{
|
|
if (playOnStart)
|
|
PlayTimeline();
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
this.gameObject.SetActive(false);
|
|
}
|
|
*/
|
|
}
|
|
|
|
public override void OnEnable()
|
|
{
|
|
base.OnEnable();
|
|
m_playableDirector.played += OnPlayed;
|
|
m_playableDirector.stopped += OnStoped;
|
|
m_playableDirector.paused += OnPaused;
|
|
cutSceneDialogueBreakpoints = cutSceneDialogueBreakpoints.OrderBy(x => x.PauseTime).ToList();
|
|
currentDialogueBreakpoint = GetCutsceneDialogueBreakpoint(currentDialogueBreakpointIndex);
|
|
}
|
|
|
|
public override void OnDisable()
|
|
{
|
|
base.OnDisable();
|
|
m_playableDirector.played -= OnPlayed;
|
|
m_playableDirector.stopped -= OnStoped;
|
|
m_playableDirector.paused -= OnPaused;
|
|
}
|
|
|
|
public override void OnDestroy()
|
|
{
|
|
base.OnDestroy();
|
|
m_playableDirector.played -= OnPlayed;
|
|
m_playableDirector.stopped -= OnStoped;
|
|
m_playableDirector.paused -= OnPaused;
|
|
StopAllCoroutines();
|
|
}
|
|
|
|
private void OnPaused()
|
|
{
|
|
if (m_playableDirector.state == PlayState.Playing)
|
|
{
|
|
m_playableDirector.Pause();
|
|
}
|
|
else
|
|
{
|
|
m_playableDirector.Play();
|
|
}
|
|
}
|
|
|
|
private void OnSkip()
|
|
{
|
|
//StopCoroutine(cancelAlpha);
|
|
//StopAllCoroutines();
|
|
//StartCoroutine(OnExitDelay());
|
|
OnStoped(m_playableDirector);
|
|
}
|
|
|
|
private void OnPaused(PlayableDirector director)
|
|
{
|
|
if (timelineStarted == false)
|
|
{
|
|
PlayTimeline();
|
|
}
|
|
}
|
|
|
|
private void SetActive(GameObject[] list, bool isActive)
|
|
{
|
|
var length = list.Length;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (list[i] != null)
|
|
{
|
|
list[i].gameObject.SetActive(isActive);
|
|
}
|
|
}
|
|
}
|
|
|
|
private CutSceneDialogueBreakpoint GetCutsceneDialogueBreakpoint(int index)
|
|
{
|
|
return cutSceneDialogueBreakpoints.Count <= 0 || index >= cutSceneDialogueBreakpoints.Count
|
|
? null
|
|
: cutSceneDialogueBreakpoints[index];
|
|
}
|
|
|
|
private CutSceneBreakpoint GetCutsceneBreakpoint(int index)
|
|
{
|
|
return cutSceneBreakpoints.Count <= 0 || index >= cutSceneDialogueBreakpoints.Count
|
|
? null
|
|
: cutSceneBreakpoints[index];
|
|
}
|
|
|
|
private void OnPlayed(PlayableDirector director)
|
|
{
|
|
if (timelineStarted == false)
|
|
{
|
|
director.Pause();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (timelineStarted)
|
|
{
|
|
if (currentDialogueBreakpoint == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_playableDirector.time >= currentDialogueBreakpoint.PauseTime)
|
|
{
|
|
m_playableDirector.Pause();
|
|
DialogueManager.instance.StartConversation(currentDialogueBreakpoint.DialogueTitle);
|
|
currentDialogueBreakpointIndex++;
|
|
currentDialogueBreakpoint = GetCutsceneDialogueBreakpoint(currentDialogueBreakpointIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (lerpCamera != null || timelineStarted == false || timeLineStoped == true) return;
|
|
|
|
if (playerCamera && followTarget)
|
|
{
|
|
var length = cameras.Length;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (cameras[i].gameObject.activeInHierarchy)
|
|
{
|
|
lastUseCamera = cameras[i];
|
|
playerCamera.transform.position = cameras[i].transform.position;
|
|
playerCamera.transform.rotation = cameras[i].transform.rotation;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//No active cutscene camera! Keep old transform.
|
|
if (lastUseCamera)
|
|
{
|
|
playerCamera.transform.position = lastUseCamera.transform.position;
|
|
playerCamera.transform.rotation = lastUseCamera.transform.rotation;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnStoped(PlayableDirector director)
|
|
{
|
|
//FadeCanvasGroup.Instance.FadeIn(1f);
|
|
|
|
if (!timeLineStoped)
|
|
{
|
|
timeLineStoped = true;
|
|
timeLineState = PlayState.Paused;
|
|
timelineStarted = false;
|
|
|
|
director.Stop();
|
|
director.timeUpdateMode = DirectorUpdateMode.Manual;
|
|
director.time = director.duration;
|
|
director.Evaluate();
|
|
if (lerpCamera == null)
|
|
{
|
|
teleport.Teleport(vThirdPersonCamera.instance.transform);
|
|
vThirdPersonCamera.instance.ResetAngle();
|
|
vThirdPersonCamera.instance.ResetTarget();
|
|
}
|
|
|
|
try
|
|
{
|
|
m_onEndEvent?.Invoke();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError("CutScene: error on OnStopped, while executing event. Message: " + e.Message);
|
|
}
|
|
|
|
SetActive(toEnableOnEnd, true);
|
|
SetActive(toDisableOnEnd, false);
|
|
SkipCanvas.Instance.m_OnSkip -= OnSkip;
|
|
SkipCanvas.Instance.m_OnPause -= OnPaused;
|
|
SkipCanvas.Instance.gameObject.SetActive(false);
|
|
}
|
|
|
|
Player.Instance.ResetAnimator();
|
|
|
|
if (lerpCamera == null)
|
|
{
|
|
//after player is enabled on set active, so everything works just fine
|
|
EnableInputAndUI();
|
|
}
|
|
|
|
var dc = Player.Instance.GetComponent<bDrawHideMeleeWeapons>();
|
|
|
|
if (dc != null)
|
|
{
|
|
dc.HideWeapons(true);
|
|
}
|
|
if (m_cutsceneLevelLoader.Enabled)
|
|
{
|
|
m_cutsceneLevelLoader.LoadLevel();
|
|
}
|
|
|
|
StopAllCoroutines();
|
|
//FadeCanvasGroup.Instance.FadeIn(1f);
|
|
}
|
|
|
|
/*
|
|
private void OnStoped(PlayableDirector director)
|
|
{
|
|
StopAllCoroutines();
|
|
StartCoroutine(OnStopedCoroutine(director));
|
|
}
|
|
|
|
private IEnumerator OnStopedCoroutine(PlayableDirector director)
|
|
{
|
|
if (!timeLineStoped)
|
|
{
|
|
director.time = director.duration;
|
|
//give one frame to move director to the end
|
|
yield return null;
|
|
director.Stop();
|
|
|
|
if (lerpCamera == null)
|
|
{
|
|
EnableInputAndUI();
|
|
}
|
|
|
|
timeLineStoped = true;
|
|
timeLineState = PlayState.Paused;
|
|
timelineStarted = false;
|
|
if (lerpCamera == null)
|
|
{
|
|
teleport.Teleport(vThirdPersonCamera.instance.transform);
|
|
}
|
|
|
|
m_onEndEvent?.Invoke();
|
|
SetActive(toEnableOnEnd, true);
|
|
SetActive(toDisableOnEnd, false);
|
|
SkipCanvas.Instance.m_OnSkip -= OnSkip;
|
|
SkipCanvas.Instance.m_OnPause -= OnPaused;
|
|
SkipCanvas.Instance.gameObject.SetActive(false);
|
|
}
|
|
|
|
var dc = Player.Instance.GetComponent<bDrawHideMeleeWeapons>();
|
|
if (dc != null)
|
|
{
|
|
dc.HideWeapons(true);
|
|
}
|
|
yield return null;
|
|
}
|
|
*/
|
|
|
|
private IEnumerator OnPlayDelay()
|
|
{
|
|
wasPlayed = true;
|
|
Player.Instance.PlayerInput.SetLockAllInput(true);
|
|
|
|
if (lerpCamera == null && FadeCanvasGroup.Instance != null)
|
|
{
|
|
if (playOnStart || skipFadeIn)
|
|
{
|
|
FadeCanvasGroup.Instance.FadeIn(m_fadeTime);
|
|
//yield return new WaitForSeconds(m_fadeTime);
|
|
followTarget = true;
|
|
}
|
|
else
|
|
{
|
|
FadeCanvasGroup.Instance.FadeOutIn(m_fadeTime);
|
|
yield return new WaitForSeconds(m_fadeTime);
|
|
followTarget = true;
|
|
//yield return new WaitForSeconds(m_fadeTime * 0.5f);
|
|
}
|
|
|
|
///FadeCanvasGroup.InvokeFade(fadeSettings.Startfade, fadeSettings.speed * m_speed);
|
|
//
|
|
/*
|
|
FadeCanvasGroup.Instance.FadeOutIn(m_fadeTime);
|
|
cancelAlpha = StartCoroutine(CancelAlphaWait());
|
|
yield return new WaitUntil(() => Alpha1());
|
|
yield return new WaitForSeconds(m_fadeTime * 0.5f);
|
|
followTarget = true;
|
|
yield return new WaitForSeconds(m_fadeTime * 0.5f);
|
|
yield return new WaitUntil(() => Alpha0());
|
|
if (cancelAlpha != null)
|
|
{
|
|
StopCoroutine(cancelAlpha);
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
HideUI.InvokeSetActiveUI(false);
|
|
SkipCanvas.Instance.gameObject.SetActive(true);
|
|
SkipCanvas.Instance.m_OnSkip += OnSkip;
|
|
SkipCanvas.Instance.m_OnPause += OnPaused;
|
|
|
|
if (m_playableDirector && timeLineState != PlayState.Playing)
|
|
{
|
|
timeLineState = PlayState.Playing;
|
|
m_playableDirector.initialTime = 0f;
|
|
m_playableDirector.Play();
|
|
m_playableDirector.playableGraph.GetRootPlayable(0).SetSpeed(m_speed);
|
|
|
|
CutSceneEnable?.Invoke(true);
|
|
m_onStartEvent?.Invoke();
|
|
SetActive(toEnableOnStart, true);
|
|
SetActive(toDisableOnStart, false);
|
|
timeLineStoped = false;
|
|
StartCoroutine(OnExitDelay());
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
private IEnumerator OnExitDelay()
|
|
{
|
|
//var waitTime = (float)m_playableDirector.playableAsset.duration - (fadeSettings.GetInverseEndFadeCurveValue(1f) / fadeSettings.speed);
|
|
var waitTime =
|
|
(float)m_playableDirector.playableAsset.duration - m_fadeTime -
|
|
.2f; // * 0.5f; //0.5, b robimy fade in/out
|
|
|
|
while (m_playableDirector.time /*+ Time.deltaTime * 2f*/ <
|
|
waitTime) // hak, chcę być o jedną 2 klatkę do przodu.
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
if (lerpCamera == null)
|
|
{
|
|
if (!skipFadeOutIn)// && m_cutsceneLevelLoader.Enabled == false)
|
|
{
|
|
FadeCanvasGroup.Instance.FadeOutIn(m_fadeTime);
|
|
}
|
|
}
|
|
|
|
//cancelAlpha = StartCoroutine(CancelAlphaWait());
|
|
//yield return new WaitUntil(() => Alpha1());
|
|
//yield return new WaitUntil(() => Alpha0());
|
|
//yield return new WaitForSeconds(m_fadeTime * 0.5f);
|
|
// if (m_cutsceneLevelLoader.Enabled)
|
|
// {
|
|
// FadeCanvasGroup.Instance.FadeOut(m_fadeTime);
|
|
// yield return new WaitForSeconds(m_fadeTime);
|
|
// m_cutsceneLevelLoader.LoadLevel();
|
|
// yield break;
|
|
// }
|
|
|
|
yield return new WaitForSeconds(m_fadeTime);
|
|
followTarget = false;
|
|
//if (cancelAlpha != null)
|
|
//{
|
|
// StopCoroutine(cancelAlpha);
|
|
//}
|
|
|
|
OnStoped(m_playableDirector);
|
|
|
|
yield return null;
|
|
}
|
|
|
|
private IEnumerator CancelAlphaWait()
|
|
{
|
|
cancelAlphaWait = false;
|
|
float maxWaitTime = m_fadeTime;
|
|
//if (curve != null && curve.keys.Length > 0)
|
|
//{
|
|
//maxWaitTime = curve.keys[curve.length - 1].time / fadeSettings.speed;
|
|
//}
|
|
|
|
yield return new WaitForSeconds(maxWaitTime);
|
|
Debug.Log("Fade timeout, cancel wait");
|
|
cancelAlphaWait = true;
|
|
cancelAlpha = null;
|
|
}
|
|
|
|
private bool Alpha1()
|
|
{
|
|
return FadeCanvasGroup.Instance.canvasGroup.alpha >= 1f || cancelAlphaWait;
|
|
}
|
|
|
|
private bool Alpha0()
|
|
{
|
|
return FadeCanvasGroup.Instance.canvasGroup.alpha < 1f || cancelAlphaWait;
|
|
}
|
|
|
|
public void EnableInputAndUI()
|
|
{
|
|
HideUI.InvokeSetActiveUI(true);
|
|
CutSceneEnable?.Invoke(false);
|
|
Player.Instance.PlayerInput.SetLockAllInput(false);
|
|
Debug.Log("Disabled cutscene");
|
|
}
|
|
|
|
public void ResumeCutScene()
|
|
{
|
|
m_playableDirector.Resume();
|
|
}
|
|
|
|
[Button]
|
|
private void CompleteQuest()
|
|
{
|
|
var journal = QuestMachine.GetQuestJournal();
|
|
Quest currentQuest = null;
|
|
for (int i = 0; i < journal.questList.Count; i++)
|
|
{
|
|
var quest = journal.questList[i];
|
|
|
|
if (!quest.isTrackable || quest.GetState() == QuestState.Successful)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
currentQuest = quest;
|
|
break;
|
|
}
|
|
|
|
if (currentQuest)
|
|
{
|
|
for (int i = 0; i < currentQuest.nodeList.Count; i++)
|
|
{
|
|
if (currentQuest.nodeList[i].GetState() == QuestNodeState.True)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (currentQuest.nodeList[i].GetState() == QuestNodeState.Active)
|
|
{
|
|
currentQuest.nodeList[i].SetState(QuestNodeState.True);
|
|
journal.OnQuestNodeStateChanged(currentQuest.nodeList[i]);
|
|
}
|
|
}
|
|
//journal.();
|
|
}
|
|
}
|
|
|
|
[Button]
|
|
public void PlayTimeline()
|
|
{
|
|
if (CanStart)
|
|
{
|
|
timelineStarted = true;
|
|
lastUseCamera = null;
|
|
lerpCamera = GetComponent<CutSceneLerpCamera>();
|
|
if (lerpCamera != null && !lerpCamera.enabled)
|
|
{
|
|
lerpCamera = null;
|
|
}
|
|
if (m_completeCurrentQuest)
|
|
{
|
|
CompleteQuest();
|
|
}
|
|
StartCoroutine(OnPlayDelay());
|
|
}
|
|
}
|
|
|
|
private void SetActiveCameras(bool isActive)
|
|
{
|
|
foreach (var item in cameras)
|
|
{
|
|
item.enabled = isActive;
|
|
}
|
|
}
|
|
|
|
private void SetActiveAudioListener(bool isActive)
|
|
{
|
|
foreach (var item in audioListeners)
|
|
{
|
|
item.enabled = isActive;
|
|
}
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
m_playableDirector = GetComponent<PlayableDirector>();
|
|
m_playableDirector.playOnAwake = false;
|
|
}
|
|
|
|
public override string RecordData()
|
|
{
|
|
CutsceneSaveData data = new();
|
|
data.wasPlayed = WasPlayed;
|
|
return SaveSystem.Serialize(data);
|
|
}
|
|
|
|
public override void ApplyData(string s)
|
|
{
|
|
var sd = SaveSystem.Deserialize<CutsceneSaveData>(s);
|
|
if (sd != null)
|
|
{
|
|
WasPlayed = sd.wasPlayed;
|
|
}
|
|
if (wasPlayed)
|
|
{
|
|
gameObject.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class CutSceneBreakpoint
|
|
{
|
|
public float PauseTime;
|
|
public float Duration;
|
|
|
|
public UnityEvent OnPauseStart;
|
|
public UnityEvent OnPauseEnd;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class CutSceneDialogueBreakpoint
|
|
{
|
|
public float PauseTime;
|
|
public string DialogueTitle;
|
|
|
|
[Tooltip("if 0 pause will be stay until player pick choice")]
|
|
public float TimeForAutomaticChoice;
|
|
}
|
|
} |