using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.Events; [Serializable] [CreateAssetMenu(fileName = "New Dialogue", menuName = "Dialogue/New Dialogue")] public class Dialogue : ScriptableObject, IDialogue { [SerializeField] public string SpeakerName; [SerializeField] public int CurrentStep = 0; [SerializeField] public List DialogueSteps; public void SetSpeakerName(string speakerName) { SpeakerName = speakerName; DialogueSteps.ForEach(step => step.Header = speakerName); } #region finish action api public void SetActionAfterEachDialogueStep(UnityEvent _endOfDialogueStepAction) { foreach(var dialogueStep in DialogueSteps) { dialogueStep.SetActionAfterDialogueStep(_endOfDialogueStepAction); } } public void SetActionAfterEachDialogueStep(Action _finishDialogueAction) { foreach (var dialogueStep in DialogueSteps) { dialogueStep.SetActionAfterDialogueStep(_finishDialogueAction); } } public void SetActionAfterDialogueStep(int dialogueStepNo, UnityEvent _endOfDialogueStepAction) { if(DialogueSteps.Count >= dialogueStepNo) DialogueSteps[dialogueStepNo].SetActionAfterDialogueStep(_endOfDialogueStepAction); } public void SetActionAfterDialogueStep(int dialogueStepNo, Action _finishDialogueAction) { /* Debug.Log(dialogueStepNo); */ if (DialogueSteps.Count >= dialogueStepNo) DialogueSteps[dialogueStepNo].SetActionAfterDialogueStep(_finishDialogueAction); } #endregion #region dialogue displaying api public void StartDialogue() { // 1. Build BuildDialogue(DialogueSteps); // 2. Show first step ShowDialogueStepPanel(); } public void BreakDialogueStep() { foreach (var DialogueStep in DialogueSteps) { if (!DialogueStep.WasDisplayed && DialogueStep.DialogueController.CurrentPanel != null) { DialogueStep.DialogueController.CloseCurrentPanel(); // close panel break; } } } /// /// Function to /// - close panel /// - INVOKE FINAL DIALOGUE ACTION /// - mark as dispalyed /// - increasing step number /// /// Dont invoke final action!!! /// public void FinishDialogue() { foreach (var DialogueStep in DialogueSteps) { if (!DialogueStep.WasDisplayed) { // status must be changes before invoked final action - example - updating state DialogueStep.WasDisplayed = true; CurrentStep++; DialogueStep.DialogueController.FinishCurrentDialogue(DialogueStep.DialogueController); break; } } } /// /// Function to /// - close panel /// - mark as dispalyed /// - increasing step number /// /// Dont invoke final action!!! /// public void CloseDialogue() { foreach (var DialogueStep in DialogueSteps) { if (!DialogueStep.WasDisplayed) { DialogueStep.WasDisplayed = true; CurrentStep++; DialogueStep.DialogueController.CloseCurrentPanel(DialogueStep.DialogueController); break; } } } /// /// Dialogue API /// /// MAIN bunction to begin dialogue /// Create new panel instance on scene by force with sentence from queue /// /// The best way is to invoked its after player reaction from other script (by event - collision) :) /// public void ShowDialogueStepPanel() { foreach (var DialogueStep in DialogueSteps) { if (!DialogueStep.WasDisplayed && DialogueStep.DialogueController.listOfDialogue.Count != 0) { DialogueStep.DialogueController.Show(DialogueStep.DialogueController.listOfDialogue.Dequeue()); // create panel break; } } } /// /// Show next sentence ONLY in the same step /// /// Return next panel status ponly for first faounded not displayed dialogue step /// /// TODO change name this function and one below - but this break buttons with this action assigned /// /// It would be much safer if function were return int not void bu unity event dont allow to bind methods in that scenario /// /// public void ShowNextPanel() { // we dont use foreach and "was displayed" condition because ther is DATA LEAK // MISLEADING - last sentence mark step ad "wasDisplayed" but not increase "CurrentPanel" index var currentStep = GetCurrentStep(); var nextSentenceIndex = currentStep.DialogueController.ShowNextPanel(currentStep.DialogueController); if (!nextSentenceIndex) { CurrentStep++; Debug.Log($"Increase - {CurrentStep}"); } //return nextSentenceIndex; } /// /// Dialogue API /// /// Function to automaticly go to next dialgue sentence (in this or next step eg after pressing button on panel /// It provide that dialogue not braking after finishing current step /// /// The dialogue follows the order of the lists ! ! /// /// It's default function to get next sentence if dialogue is currently started /// It is responsible for detecting /// 1) if there is any dialogue panel already created before displaying next sentence /// 2) if its last panel sentence and invoiking 'end dialogue' action /// /// Whats more, if there was no more sentences in 'step', althroughr closing panel go to next step automatiiccally /// public void GoToNextSentence() { // wskazujemy na inny krok kolejno niz nieoznaczony // MISLEADING - last sentence mark step ad "wasDisplayed" but not increase "CurrentPanel" index foreach (var DialogueStep in DialogueSteps) { if (!DialogueStep.WasDisplayed) { var nextSentence = DialogueStep.DialogueController.ShowNextPanel(DialogueStep.DialogueController); if (!nextSentence) { DialogueStep.WasDisplayed = true; CurrentStep++; ShowDialogueStepPanel(); } break; } } } #endregion public void InvokeFinalAction() { foreach (var DialogueStep in DialogueSteps) { if (!DialogueStep.WasDisplayed) { DialogueStep.DialogueController.FinishDialoguStep(); break; } } } public void BuildDialogue() { BuildDialogue(DialogueSteps); } /// /// Function to build each step of dialogue /// public void BuildDialogue(List Dialogue) { foreach (var dialogueStep in Dialogue) { dialogueStep.Header = SpeakerName; dialogueStep.Build(); // synchronize current step counter // cause ERROR - multi counting .... } } #region Dialogue Status API /// /// Function to reset rememebered dialogue status /// /// (Scriptable objects clones are overwritten during clone modification) /// public void ResetDialogue() { CurrentStep = 0; DialogueSteps.ForEach(step => step.WasDisplayed = false); } public virtual void UpdateDialogueState(DialogueData dialogueData) { // 1 Rule - speaker name shouldnt change !!! its our 'key' CurrentStep = dialogueData.CurrentStep; for(int i=0; i < dialogueData.DialogueStepModelDataList.Count; i++) { DialogueSteps[i].WasDisplayed = dialogueData.DialogueStepModelDataList[i].WasDisplayed; } } #endregion public DialogueStepModel? GetCurrentStep() {// TODO - argument out of colection :/ var currentStep = DialogueSteps.ElementAtOrDefault(CurrentStep); if (currentStep != null && currentStep.WasDisplayed && CurrentStep < DialogueSteps.Count) CurrentStep++; return DialogueSteps.Count > CurrentStep ? DialogueSteps[CurrentStep] : null; } /* public DialogueStepModel GetCurrentStep() { foreach (var DialogueStep in DialogueSteps) { Debug.Log("-" + DialogueStep.DialogueController.listOfDialogue.Count); if (!DialogueStep.WasDisplayed && DialogueStep.DialogueController.listOfDialogue.Count != 0) { return DialogueStep; } } return null; }*/ }