using EasyTalk.Nodes.Common; using System.Collections; using System.Collections.Generic; using UnityEngine; using EasyTalk.Controller; using EasyTalk.Nodes.Core; using static EasyTalk.Controller.DialogueController; using EasyTalk.Nodes.Utility; using UnityEngine.UI; namespace EasyTalk.Display { /// /// This is an implementation of a Dialogue Display which supports a conversation display (for displaying dialogue and character information), an option display (for /// displaying options to the player), and a continue display (for showing the player when they continue or skip ahead in the conversation). /// public class DialogueDisplay : AbstractDialogueDisplay { /// /// The conversation display to use when displaying dialogue. /// [Tooltip("The Conversation Display used to show text from conversation lines and character names.")] [SerializeField] protected ConversationDisplay convoDisplay; /// /// The option display to use when displaying options. /// [Tooltip("The Option Display used to present options to the player.")] [SerializeField] protected OptionDisplay optionDisplay; /// /// The continue display to use when indicating to the player that they can continue on in a conversation. /// [Tooltip("The Continue Display which can be shown to the player to let them know that they can continue.")] [SerializeField] protected ContinueDisplay continueDisplay; /// /// The text input display used to retrieve text input from the player. /// [SerializeField] protected TextInputDisplay textInputDisplay; /// /// The character display used to show character portrayals during dialogue playback. /// [SerializeField] protected CharacterDisplay characterDisplay; /// /// The icon display used to show character icons during dialogue playback. /// [SerializeField] protected IconDisplay iconDisplay; /// /// The default Conversation Display ID to use when a Dialogue Controller doesn't specify a Conversation Display or ID. /// [Tooltip("This value specifies the Display ID of the Conversation Display which the Dialogue Display should fallback to whenever the actively running Dialogue Controller doesn't " + "specifiy a specific Conversation Display or Display ID to use.")] [SerializeField] protected string defaultConvoDisplayID = "main"; /// /// Whether the dialogue display should be hidden when a dialogue is exited. /// [Tooltip("If set to true, whenever a dialogue is exited, the dialogue display will be hidden.")] [SerializeField] protected bool hideDisplayOnExit = false; /// /// Whether the conversation display should be hidden when a pause node is reached. /// [Tooltip("If true, the conversation display will be hidden whenever a pause node is encountered.")] [SerializeField] protected bool hideOnPause = false; /// /// Whether the conversation display should be hidden when options are being presented to the player. /// [Tooltip("When set to 'true', the conversation display will be hidden whenever options are presented to the player.")] [SerializeField] protected bool hideConvoWhenShowingOptions = false; /// /// Whether the conversation display should be reset when options are being presented. /// [Tooltip("When set to true, the conversation display text and character name will be cleared whenever options are being presented to the player.")] [SerializeField] protected bool clearConvoWhenShowingOptions = false; /// /// Whether the conversation dispaly should be hidden and updated offscreen whenever the a character change is detected. /// [Tooltip("When set to 'true', if the character name changes during a conversation, the conversation display will be hidden, updated, and re-animated before " + "being shown. NOTE: The conversation panel will NOT be refreshed if the change is from/to a blank character name.")] [SerializeField] protected bool refreshConvoOnCharacterChange = true; /// /// Whether the conversation display should be hidden and updated offscreen whenever the dialogue text changes. /// [Tooltip("When set to 'true', the conversation display will be hidden, updated, and re-animated for each line of dialogue.")] [SerializeField] protected bool refreshConvoOnTextChange = false; /// /// Whether lines of dialogue can be skipped before their audio or display time is completed. /// [SerializeField] [Tooltip("When in AUTOPLAY mode, setting this to true allows the player to skip through dialogue using input controls.")] protected bool areLinesSkippable = false; /// /// The amount of time each word should count toward the total display time of a line of dialogue if there is no audio file. /// [SerializeField] [Tooltip("When in autoplay mode, if no audio clip is included, each line of dialogue will be analyzed to determine the word count. " + "That word count is multiplied by this value to determine how long the line should be displayed.")] protected float timePerWord = 0.2f; /// /// The minimum amount of time a line of dialogue will be shown when in AUTOPLAY playback mode. /// [SerializeField] [Tooltip("The minimum amount of time a line of dialogue will be shown when in AUTOPLAY mode.")] protected float minConvoTime = 1.0f; /// /// A delay which is added on top of the normal display time for a line of dialogue when in AUTOPLAY playback mode. /// [SerializeField] [Tooltip("How much additional time should be taken for each line of dialogue before continuing to the next line/node. (NOTE: This is " + "only applicable when the controller is set to AUTOPLAY mode.)")] protected float convoLineDelay = 1.0f; /// /// Whether the continue display should be used to let the player know when they can continue or skip ahead. /// [Tooltip("If set to 'true', the Continue Display will be shown to the player each time they are allowed to continue along to the next line in the conversation.")] [SerializeField] private bool useContinueDisplay = true; /// /// The continuation mode of the dialogue display. This determiens when the player is allowed to continue or skip ahead. /// [Tooltip("Indicates when the player is allowed to continue to the next line of dialogue." + "\nIMMEDIATE: As soon as a line is displayed the player can continue." + "\nAFTER_AUDIO: The player will be allowed to continue after the audio file assigned to the dialogue finishes playing." + "\nAFTER_DELAY: The player will be allowed to continue after the continuation delay has elapsed from the time the line of dialogue is shown." + "\nAFTER_AUDIO_AND_DELAY: The player will be allowed to continue after both audio and the continuation delay have completed." + "\nAFTER_AUDIO_OR_DELAY: The player will be allowed to continue after either the audio finishes, or the continuation delay, whichever occurs first.")] [SerializeField] private DialogueDelayMode continuationMode = DialogueDelayMode.IMMEDIATE; /// /// The minimum amount of time a line of dialogue will be shown before permitting the player to continue or skip ahead. /// [Tooltip("The amount of time (in seconds) to wait after showing a line of dialogue before allowing the player to continue.")] [SerializeField] private float continuationDelay = 1.0f; /// /// When set to true, the display will attempt to find a conversation display with a display ID matching the new (untranslated) character name and set the /// dialogue display to use that, if found. /// [SerializeField] [Tooltip("When set to true, whenever the character changes while showing dialogue lines, the display will attempt to find a " + "Conversation Display with the same Display ID as the character name and tell the Dialogue Display to use it.")] protected bool switchConvoDisplayOnCharacterChange = false; /// /// Whether options should be presented automatically after the prior line of dialogue. If this is false, then options won't be shown until Continue() is called. /// [SerializeField] [Tooltip("If set to true, options will be automatically presented after either the prior conversation line's audio clip has played, " + "or if there is no audio clip, after the configured option delay time. When set to false, options will not be shown until the player continues via input.")] private bool presentOptionsAutomatically = false; /// /// Determines how/when options are displayed when an option node is processed, either immediately, after a delay, or after a line of dialogue's audio is completed. /// [SerializeField] [Tooltip("When presenting options automatically, this will determine how quickly the options are displayed to the player when an option " + "node is encountered. Options can be displayed immediately, or they can be delayed after waiting on convo audio to finish, waiting on a delay, or both.")] private DialogueDelayMode optionDelayMode = DialogueDelayMode.IMMEDIATE; /// /// The delay to use when presenting options. /// [SerializeField] [Tooltip("How long the system should wait before showing options when options are to be presented. This is in addition to whatever time " + "is needed for transition animations.")] protected float optionDelay = 2.0f; /// /// Whether the dialogue display should automatically call Continue() on the Dialogue Controller when a story node is encountered. /// [Tooltip("When true, the Dialogue Display will automatically call Continue() on the Dialogue Controller whenever a story node is reached rather than waiting.")] [SerializeField] protected bool continueOnStory = true; /* /// /// Whether the display should allow dialogue to be skipped when it is generated by an AI server. /// [Tooltip("When true, the dialogue display will allow the player to skip dialogue which is being generated by AI.")] [SerializeField] protected bool allowAISkip = false;*/ [SerializeField] protected Image loadingIcon; /// /// The coroutine for delaying options after a certain amount of time. /// private Coroutine displayOptionsAfterDelayRoutine; /// /// The coroutine for automaticallly playing lines of dialogue. /// private Coroutine autoplayRoutine; /// /// The display ID of the conversation display currently being targeted. /// private string currentTarget = null; /// /// The line of dialogue currently being displayed. /// private ConversationLine currentLine = null; /// /// The List of dialogue options currently being presented. /// private List displayedOptions; /// /// A flag used to control whether automatic continuation is allowed when the controller is in Autoplay mode. /// (Prevents Continue() from being called when options are about to be shown). /// private bool allowAutoContinue = true; /// /// A mapping of Display IDs to Dialogue Panels for all subdisplays of the main Dialogue Display. /// protected Dictionary subDisplayMap = new Dictionary(); /// private void Awake() { Init(); } /// /// Initializes the dialogue display. /// protected override void Init() { base.Init(); InitializeOptionDisplay(); InitializeContinueDisplay(); InitializeCharacterDisplay(); InitializeIconDisplay(); IndexSubDisplays(); Reset(); } /// /// Called whenever a dialogue has begun playback. This will reset the dialogue display components to ready them for display. /// /// The name of the entry point where the playback began. public override void OnDialogueEntered(string entryPointName) { base.OnDialogueEntered(entryPointName); if (dialogueController.GetConversationDisplay() != null) { SetConversationDisplay(dialogueController.GetConversationDisplay()); } else if(dialogueController.GetConversationDisplayID() != null && dialogueController.GetConversationDisplayID().Length > 0) { UseConversationDisplayForTarget(dialogueController.GetConversationDisplayID()); } else if(defaultConvoDisplayID != null && defaultConvoDisplayID.Length > 0) { UseConversationDisplayForTarget(defaultConvoDisplayID); } Reset(); } /// /// Called whenever a dialogue exits. This will hide the display if hideDisplayOnExit is set to true; otherwise it just resets the display. /// /// The name of the exit point where the dialogue exited. public override void OnDialogueExited(string exitPointName) { base.OnDialogueExited(exitPointName); StopAllCoroutines(); if (hideDisplayOnExit) { Hide(); } Reset(); } /// /// Resets the display by disabling continuation and option selection, deactivating option buttons, and resetting the dialogue text. /// private void Reset() { this.DisableContinue(); this.DisableOptionSelection(); if (convoDisplay != null) { convoDisplay.Reset(); } if (optionDisplay != null) { optionDisplay.DeactivateButtons(); } } /// /// Hides the display components. /// public void Hide() { if (convoDisplay != null) { convoDisplay.Hide(); } if (optionDisplay != null) { optionDisplay.Hide(); } if (continueDisplay != null) { continueDisplay.Hide(); } } /// /// Displays the line of dialogue provided. /// /// The line of dialogue to display. public override void OnDisplayLine(ConversationLine currentLine) { base.OnDisplayLine(currentLine); if (autoplayRoutine != null) { StopAllCoroutines(); convoDisplay.ForceFinish(); autoplayRoutine = null; } ConversationLine oldLine = currentLine; this.currentLine = currentLine; if (currentLine.Target != null && currentTarget != currentLine.Target) { UseConversationDisplayForTarget(currentLine.Target); } if (dialogueController.GetPlaybackType() == PlaybackType.AUTOPLAY || currentLine.AutoPlay) { //Reset the allowAutoContinue flag. allowAutoContinue = true; //Display each line, and wait for a timer to finish or audio to complete before moving on to the next. autoplayRoutine = StartCoroutine(PlayAutoConversation(currentLine, oldLine)); } else { DisplayLine(currentLine); dialogueController.SwitchLineAudio(currentLine, oldLine); } } /*public override void OnAIPromptStarted() { base.OnAIPromptStarted(); loadingIcon.gameObject.SetActive(true); //If skipping AI conversations is allowed, allow continue. if(allowAISkip) { this.AllowContinue(); } } public override void OnAIPromptFinished() { base.OnAIPromptFinished(); loadingIcon.gameObject.SetActive(false); } public override void OnConversationClear() { base.OnConversationClear(); convoDisplay.Reset(); }*/ /// public override void OnAppendText(string text) { base.OnAppendText(text); foreach(DialogueListener listener in dialogueListeners) { listener.OnAppendText(text); } } /// /// Handles the logic to display the specified line of Dialogue. This method also calls OnDisplayLine() on all Dialogue Listeners. /// /// The line of dialogue to display. private void DisplayLine(ConversationLine currentLine) { //Call and callbacks that are registered to let them know that a line of dialogue is being handled/displayed. foreach (DialogueListener listener in dialogueListeners) { listener.OnDisplayLine(currentLine); } //If the convo display is hidden, we should wait until it's available for display to change the displayed text/character name //in case the display is in the middle of a transition. if (convoDisplay.IsHidden) { StartCoroutine(DisplayConversationLineAsync(currentLine)); } else { if (refreshConvoOnTextChange) { StartCoroutine(DisplayConversationLineAsync(currentLine, true)); } else { convoDisplay.Activate(); if (currentLine.TextDisplayMode == TextDisplayMode.REPLACE) { //Set the character name and text of the conversation display. convoDisplay.SetCharacterName(currentLine.TranslatedCharacterName, currentLine.OriginalCharacterName); convoDisplay.SetConversationText(currentLine); } else { convoDisplay.AppendText(currentLine); } if ((!currentLine.PrecedesOption || !PresentOptionsAutomatically) && ((dialogueController.GetPlaybackType() == PlaybackType.AUTOPLAY && areLinesSkippable) || (dialogueController.GetPlaybackType() == PlaybackType.WAIT_FOR_COMMAND))) { if (continuationMode == DialogueDelayMode.IMMEDIATE) { this.AllowContinue(); } else { StartCoroutine(WaitForContinue()); } } } } } /// /// Calls OnDisplayLine on all registered Dialogue Listeners to display the specified line of dialogue and continues automatically after a certain period of time, /// depending on any audio file attributed to the line of dialogue, timePerWord, convoLineDelay, and minConvoTime settings. After the necessary amount of time has elapsed, this method /// will trigger the OnContinue method of all registered Dialogue Listeners. /// /// The line of dialogue to start from. /// The previous line of dialogue. /// protected virtual IEnumerator PlayAutoConversation(ConversationLine lineToPlay, ConversationLine oldLine = null) { //Determine how long the line of dialogue should be shown for, then display it. lineToPlay.PlayTime = GetTextPlayTime(lineToPlay.Text, lineToPlay.AudioClip); lineToPlay.AutoPlay = true; DisplayLine(lineToPlay); float startTime = Time.time; yield return WaitForDialogueAudioOrReading(lineToPlay, oldLine); //Add an extra delay for how long the line of dialogue should be displayed before continuing. if (lineToPlay.OverrideAutoplayDelay) { //Use the setting from the "autoplay" tag. yield return new WaitForSeconds(lineToPlay.AutoPlayDelay); } else { //Use the setting from the display. yield return new WaitForSeconds(convoLineDelay); } //If the line doesn't override the delay time, we should also wait for the line delay and the minimum conversation time before continuing. if (!lineToPlay.OverrideAutoplayDelay) { //Wait for the minimum amount of time that a line of dialogue is meant to be displayed. if (Time.time - startTime < minConvoTime) { yield return new WaitForSeconds(minConvoTime - (Time.time - startTime)); } } if (allowAutoContinue) { dialogueController.Continue(); } else { allowAutoContinue = true; } } /// /// /// /// /// /// private IEnumerator WaitForDialogueAudioOrReading(ConversationLine lineToPlay, ConversationLine oldLine) { //Stop any dialogue audio clip that is already playing. AudioSource source = dialogueController.GetAudioSource(); if (source != null) { if (source.isPlaying) { source.Stop(); OnAudioCompleted(oldLine, true); } } //If there is an audio clip, play the audio clip and wait until it's over before continuing to the next line of dialogue. if (lineToPlay.AudioClip != null) { if (source != null) { source.clip = lineToPlay.AudioClip; source.Play(); OnAudioStarted(lineToPlay); } yield return new WaitForSeconds(lineToPlay.AudioClip.length); OnAudioCompleted(lineToPlay, false); } else { //Display the line of dialogue for a duration based on how many words are in the line. yield return new WaitForSeconds(lineToPlay.Text.Split(' ').Length * timePerWord); } } /// /// Asynchronously displays the line of dialogue provided, transitioning the conversation display to be shown if it is currently hidden. /// /// The line of dialogue to display. /// Whether the conversation display needs to be hidden prior to updating the dialogue text. /// private IEnumerator DisplayConversationLineAsync(ConversationLine currentLine, bool hideWhileUpdating = false) { if (hideWhileUpdating && !convoDisplay.IsHidden) { convoDisplay.Hide(); } yield return convoDisplay.WaitForAnimation(); convoDisplay.Activate(); if (currentLine.TextDisplayMode == TextDisplayMode.REPLACE) { convoDisplay.SetCharacterName(currentLine.TranslatedCharacterName, currentLine.OriginalCharacterName); convoDisplay.SetConversationText(currentLine); } else { convoDisplay.AppendText(currentLine); } convoDisplay.Show(); yield return convoDisplay.WaitForAnimation(); if ((!currentLine.PrecedesOption || !PresentOptionsAutomatically) && ((dialogueController.GetPlaybackType() == PlaybackType.AUTOPLAY && areLinesSkippable) || (dialogueController.GetPlaybackType() == PlaybackType.WAIT_FOR_COMMAND))) { if (continuationMode == DialogueDelayMode.IMMEDIATE) { this.AllowContinue(); } else { StartCoroutine(WaitForContinue()); } } } /// /// Searches for a conversation display with a Display ID the same as the target (if not null or empty) and sets the dialogue display to use that conversation /// display if found. This method will also tell the dialogue display to hide the current conversation display being displayed, if there is one. /// /// The display ID of the target conversation display. private void UseConversationDisplayForTarget(string target) { if (target == null || target.Length == 0) { return; } if(currentTarget == target) { return; } if(convoDisplay != null && target.Equals(convoDisplay.DisplayID)) { SetConversationDisplay(convoDisplay); return; } ConversationDisplay[] foundConvoDisplays = null; #if UNITY_2022_3_OR_NEWER foundConvoDisplays = GameObject.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); #else foundConvoDisplays = GameObject.FindObjectsOfType(true); #endif foreach (ConversationDisplay foundConvoDisplay in foundConvoDisplays) { if (foundConvoDisplay.DisplayID.ToLower().Equals(target.ToLower())) { SetConversationDisplay(foundConvoDisplay); break; } } } /// /// Determines the minimum recommended amount of time to display the specified dialogue text, based on the associated audio file, or if there is no associated audio /// file, based on the number of words in the line. /// /// The dialogue text to determine display time for. /// The audio clip associated with the text, if there is one. private float GetTextPlayTime(string text, AudioClip clip) { float displayTime = convoLineDelay; if (clip != null) { displayTime = clip.length; } else { displayTime = text.Split(' ').Length * timePerWord; } return displayTime; } /// public override void OnConversationEnding(ConversationLine line, Node nextNode) { base.OnConversationEnding(line, nextNode); //If the next node is an option node display the options. if (nextNode != null && nextNode.NodeType == NodeType.OPTION && presentOptionsAutomatically) { allowAutoContinue = false; if (displayOptionsAfterDelayRoutine == null) { float delay = (currentLine.AudioClip != null) ? currentLine.AudioClip.length : optionDelay; switch (optionDelayMode) { case DialogueDelayMode.IMMEDIATE: delay = 0.0f; break; case DialogueDelayMode.AFTER_AUDIO: break; case DialogueDelayMode.AFTER_DELAY: delay = optionDelay; break; case DialogueDelayMode.AFTER_AUDIO_AND_DELAY: delay = Mathf.Max(delay, optionDelay); break; case DialogueDelayMode.AFTER_AUDIO_OR_DELAY: delay = Mathf.Min(delay, optionDelay); break; } displayOptionsAfterDelayRoutine = StartCoroutine(dialogueController.GoToOptionsAfterDelay(delay, (OptionNode)nextNode)); } else { StopDelayedOptionDisplay(); } } } /// public override void OnNodeChanged(Node node) { base.OnNodeChanged(node); StopDelayedOptionDisplay(); } /// /// Waits to allow the player to continue based on the dialogue delay mode set on this display. /// /// private IEnumerator WaitForContinue() { float startTime = Time.time; yield return new WaitForEndOfFrame(); if (continuationMode == DialogueDelayMode.AFTER_AUDIO || continuationMode == DialogueDelayMode.AFTER_AUDIO_AND_DELAY) { //Wait for audio completion. while (dialogueController.IsAudioPlaying()) { yield return new WaitForEndOfFrame(); } } if (continuationMode == DialogueDelayMode.AFTER_DELAY || continuationMode == DialogueDelayMode.AFTER_AUDIO_AND_DELAY) { //Wait for timer completion. while (Time.time - startTime < continuationDelay) { yield return new WaitForEndOfFrame(); } } if (continuationMode == DialogueDelayMode.AFTER_AUDIO_OR_DELAY) { //Wait for audio or timer completion while (((currentLine != null && currentLine.AudioClip == null) || dialogueController.IsAudioPlaying()) && Time.time - startTime < continuationDelay) { yield return new WaitForEndOfFrame(); } } AllowContinue(); } /// /// Displays the List of dialogue options to the player. /// /// The List of dialogue options to display. public override void OnDisplayOptions(List options) { base.OnDisplayOptions(options); displayedOptions = new List(); foreach (DialogueOption option in options) { if (option.IsDisplayed) { displayedOptions.Add(option); } } if (displayedOptions.Count > 0) { foreach (DialogueListener listener in dialogueListeners) { listener.OnDisplayOptions(displayedOptions); } if (optionDisplay.IsHidden) { StartCoroutine(DisplayOptionsAsync(displayedOptions)); } if(clearConvoWhenShowingOptions) { convoDisplay.Reset(); } if (hideConvoWhenShowingOptions) { convoDisplay.Hide(); } } else { dialogueController.ExitDialogue(); } } /// /// Asynchronously displays the provided list of dialogue options to the player and enables option selection once the options are displayed. /// /// The list of dialogue options to display. /// private IEnumerator DisplayOptionsAsync(List options) { yield return optionDisplay.WaitForAnimation(); optionDisplay.Activate(); this.DisableContinue(); optionDisplay.SetOptions(options); optionDisplay.Show(); yield return optionDisplay.WaitForAnimation(); optionDisplay.ActivateButtons(); this.AllowOptionSelection(); } /// /// Stops an in-progress automatic option presentation from being triggered. /// private void StopDelayedOptionDisplay() { if (displayOptionsAfterDelayRoutine != null) { StopCoroutine(displayOptionsAfterDelayRoutine); displayOptionsAfterDelayRoutine = null; } } /// public override bool SelectOptionInDirection(Vector2 direction) { return optionDisplay.SelectOptionInDirection(direction); } /// public override void ChooseSelectedOption() { optionDisplay.Hide(); int selectedOptionIdx = optionDisplay.GetSelectedOption(); DialogueOption option = GetOptionWithIndex(selectedOptionIdx); dialogueController.ChooseOption(option); displayedOptions = null; optionDisplay.DeactivateButtons(); this.DisableOptionSelection(); } /// /// Returns the DialogueOption with the specified option index. NOTE: This is NOT the same as the order of options displayed, since some options may be hidden. /// Instead, it is the original option index assigned to the option prior to filtering. /// /// The option index to retrieve the DialogueOption of. /// The DialogueOption with the specified index. private DialogueOption GetOptionWithIndex(int optionIdx) { foreach (DialogueOption option in displayedOptions) { if (option.OptionIndex == optionIdx) { return option; } } return null; } /// public override bool SelectNextOption() { return optionDisplay.SelectNextOption(); } /// public override bool SelectPreviousOption() { return optionDisplay.SelectPreviousOption(); } /// /// This method is called whenever a character change is detected during dialogue playback. /// /// The name of the previous character. /// The name of the new character. public override void OnCharacterChanged(string oldCharacterName, string newCharacterName) { base.OnCharacterChanged(oldCharacterName, newCharacterName); if (switchConvoDisplayOnCharacterChange) { UseConversationDisplayForTarget(newCharacterName); } if (refreshConvoOnCharacterChange && oldCharacterName != null && newCharacterName != null && oldCharacterName.Length > 0 && newCharacterName.Length > 0) { this.DisableContinue(); convoDisplay.Hide(); } } /// public override void OnContinue() { base.OnContinue(); foreach (DialogueListener listener in dialogueListeners) { listener.OnContinue(); } if (!areLinesSkippable && dialogueController.GetPlaybackType() == PlaybackType.AUTOPLAY) { return; } //If we are auto-playing a conversation and allowing lines to be skipped, stop the auto-play. if (autoplayRoutine != null && areLinesSkippable) { StopAllCoroutines(); autoplayRoutine = null; } convoDisplay.ForceFinish(); } /// public override void OnStory(string storyText) { base.OnStory(storyText); if(continueOnStory && dialogueController != null) { dialogueController.Continue(); } } /// public override ConversationDisplay GetConversationDisplay() { return convoDisplay; } /// public override void SetConversationDisplay(ConversationDisplay convoDisplay) { if (this.convoDisplay != null && this.convoDisplay != convoDisplay) { this.convoDisplay.Hide(); } this.convoDisplay = convoDisplay; if (this.convoDisplay != null) { currentTarget = this.convoDisplay.DisplayID; UpdateFontsForLanguage(this.convoDisplay); } } /// public override OptionDisplay GetOptionDisplay() { return optionDisplay; } /// public override void SetOptionDisplay(OptionDisplay optionDisplay) { if (this.optionDisplay != null && this.optionDisplay != optionDisplay) { this.optionDisplay.Hide(); DeinitializeOptionDisplay(); } this.optionDisplay = optionDisplay; if (this.optionDisplay != null) { InitializeOptionDisplay(); UpdateFontsForLanguage(this.optionDisplay); } } /// public override ContinueDisplay GetContinueDisplay() { return continueDisplay; } /// public override void SetContinueDisplay(ContinueDisplay continueDisplay) { if (this.continueDisplay != null && this.continueDisplay != continueDisplay) { this.continueDisplay.Hide(); DeinitializeContinueDisplay(); } this.continueDisplay = continueDisplay; if (this.continueDisplay != null) { InitializeContinueDisplay(); UpdateFontsForLanguage(this.continueDisplay); } } /// public override TextInputDisplay GetTextInputDisplay() { return this.textInputDisplay; } /// public override void SetTextInputDisplay(TextInputDisplay textInputDisplay) { this.textInputDisplay = textInputDisplay; if (this.textInputDisplay != null) { UpdateFontsForLanguage(this.textInputDisplay); } } /// public override void OnExecuteAsyncNode(AsyncNode node) { base.OnExecuteAsyncNode(node); if (node is PlayerInputNode) { //Show the text input display and wait for the player to input text before continuing. textInputDisplay.SetInputNode(node as PlayerInputNode); textInputDisplay.Reset(); textInputDisplay.HideOnAwake = false; textInputDisplay.Show(); } else if(node is ShowNode) { //Find the display for each target and show them all before continuing. DisplayUtils.HandleShowNode(node, subDisplayMap, DialogueSettings); } else if(node is HideNode) { //Find the display for each target and hide them all before continuing. DisplayUtils.HandleHideNode(node, subDisplayMap, DialogueSettings); } } /// /// Sets up the option display to trigger the ChooseSelectedOption method whenever an option is chosen. /// private void InitializeOptionDisplay() { if (optionDisplay != null) { optionDisplay.onOptionChosen.AddListener(ChooseSelectedOption); } } /// /// Removes the ChooseSelectedOption method from being triggered by the current option display. /// private void DeinitializeOptionDisplay() { if (optionDisplay != null) { optionDisplay.onOptionChosen.RemoveListener(ChooseSelectedOption); } } /// /// Sets up the continue display to tell the dialogue display that it is ready for dialogue continuation when the continue display is shown. /// private void InitializeContinueDisplay() { if (continueDisplay != null) { continueDisplay.onShowComplete.AddListener(base.AllowContinue); } } /// /// Removes the listener which allows continuation after the continue display is shown. /// private void DeinitializeContinueDisplay() { if (continueDisplay != null) { continueDisplay.onShowComplete.RemoveListener(base.AllowContinue); } } /// /// Adds the character display to the dialogue display's list of dialogue listeners. /// private void InitializeCharacterDisplay() { if (characterDisplay != null) { dialogueListeners.Add(characterDisplay); } } /// /// Adds the icon display to the dialogue display's list of dialogue listeners, and adds it as a conversation display listener to the conversation display. /// private void InitializeIconDisplay() { if (iconDisplay != null) { dialogueListeners.Add(iconDisplay); if(convoDisplay != null) { IconConversationDisplayListener iconConvoListener = iconDisplay.GetComponent(); if(iconConvoListener != null) { convoDisplay.ConversationDisplayListeners.Add(iconConvoListener); } } } } /// /// Finds all Dialogue Panels which are children of the display and adds them to a Map for quick searching of sub displays. /// private void IndexSubDisplays() { DialoguePanel[] spritePanels = GetComponentsInChildren(true); foreach (DialoguePanel panel in spritePanels) { if (panel.DisplayID != null && panel.DisplayID.Length > 0 && !subDisplayMap.ContainsKey(panel.DisplayID)) { subDisplayMap.Add(panel.DisplayID, panel); } } } /// /// Finds and returns the Dialogue Display parent of the specified GameObject, if there is one. /// /// The GameObject to find the parent Dialogue Display of. /// The parent Dialogue Display of the specified GameObject. public static DialogueDisplay GetParentDialogueDisplay(GameObject obj) { return obj.GetComponentInParent(); } /// public override void OnPause(string signal) { base.OnPause(signal); if(hideOnPause) { convoDisplay.Hide(); } } /// public override void AllowContinue() { if (continueDisplay != null && useContinueDisplay) { continueDisplay.Show(); } else { base.AllowContinue(); } } /// public override void DisableContinue() { base.DisableContinue(); if(continueDisplay != null) { continueDisplay.Hide(false); } } /// /// Gets or sets the dialogue continuation mode to use. /// public DialogueDelayMode ContinuationMode { get { return continuationMode; } set { this.continuationMode = value; } } /// /// Gets or sets the dialogue continuation delay. /// public float ContinuationDelay { get { return this.continuationDelay; } set { this.continuationDelay = value; } } /// /// Gets or sets whether the dialogue display should use a continue display during dialogue playback. /// public bool UseContinueDisplay { get { return this.useContinueDisplay; } set { this.useContinueDisplay = value; } } /// /// Gets or sets whether the conversation display should be switched when a character change is detected. /// public bool SwitchConvoDisplayOnCharacterChange { get { return this.switchConvoDisplayOnCharacterChange; } set { this.switchConvoDisplayOnCharacterChange = value; } } /// /// Gets or sets whether options should be presented automatically as a conversation node is ending. /// public bool PresentOptionsAutomatically { get { return this.presentOptionsAutomatically; } set { this.presentOptionsAutomatically = value; } } /// /// Gets or sets the delay mode to use when presenting options. /// public DialogueDelayMode OptionDelayMode { get { return this.optionDelayMode; } set { this.optionDelayMode = value; } } } /// /// An enum defining various action delay modes for a Dialogue Display. /// public enum DialogueDelayMode { IMMEDIATE, AFTER_AUDIO, AFTER_DELAY, AFTER_AUDIO_AND_DELAY, AFTER_AUDIO_OR_DELAY } }