using System; using System.Collections.Generic; using Nullframes.Intrigues.Graph; using UnityEngine; using Object = UnityEngine.Object; namespace Nullframes.Intrigues.UI { /// /// Represents a dialogue with various functionalities including adding choices and managing visibility. /// /// /// The Dialogue class encapsulates the behavior and properties of a dialogue, including the ability to show, hide, and close the dialogue, /// as well as to add choices to it. It is associated with a DialoguePanel which is used to display the dialogue in the user interface. /// public class Dialogue { private readonly DialoguePanel dialoguePanel; public bool IsSchemeDialog { get; } public Action onTimeout; public Action onDialogueClose; // Event triggered when a dialogue is closed. public Action onDialogueShow; // Event triggered when a dialogue is shows. public Action onDialogueHide; // Event triggered when a dialogue is hides. public bool ShowedUp { get; private set; } private Dictionary soundSources = new(); private Dictionary voiceSources = new(); public Dialogue(DialoguePanel panel, bool isSchemeDialog) { dialoguePanel = panel; firstParent = dialoguePanel.transform.parent; IsSchemeDialog = isSchemeDialog; } /// /// Closes the dialogue and optionally performs additional actions. /// /// If set to true, closes the dialogue without triggering additional actions like playing sound or invoking close event. /// /// This method destroys the dialogue's associated panel. If 'withoutNotification' is false, it also triggers the onDialogueClose event /// and plays a closing sound effect. /// public void Close(bool withoutNotification = false) { if (dialoguePanel == null) return; NullUtils.StopCall(dialoguePanel.counterId); Object.Destroy(dialoguePanel.gameObject); if (!withoutNotification) { DialogueManager.Instance.onDialogueClose.Invoke(this); } onDialogueClose?.Invoke(); DialogueManager.Instance.onDialogueClose_Ignore?.Invoke(this); } private Transform firstParent; /// /// Hides the dialogue. /// /// /// This method sets the dialogue's associated panel as inactive and pauses any ongoing timers. /// A closing sound effect is played when the dialogue is hidden. /// public void Hide(bool withoutNotification = false) { if (dialoguePanel == null) return; dialoguePanel.transform.SetParent(firstParent.parent); dialoguePanel.gameObject.SetActive(false); NullUtils.PauseCall(dialoguePanel.counterId); if (!withoutNotification) { DialogueManager.Instance.onDialogueHide.Invoke(this); } onDialogueHide?.Invoke(); } /// /// Shows the dialogue. /// /// /// This method sets the dialogue's associated panel as active and resumes any paused timers. /// A closing sound effect is played when the dialogue is shown. /// public void Show(bool withoutNotification = false) { if (dialoguePanel == null) return; dialoguePanel.transform.SetParent(firstParent); dialoguePanel.gameObject.SetActive(true); NullUtils.ResumeCall(dialoguePanel.counterId); if (!withoutNotification) { DialogueManager.Instance.onDialogueShow.Invoke(this); } onDialogueShow?.Invoke(); } /// /// Adds a choice to the dialogue with various configurations. /// /// The text of the choice. /// Optional icon for the choice. /// Optional action to execute when the choice is selected. /// Optional condition to determine if the choice should be shown. /// Determines if the dialogue should close when the choice is selected. /// Determines if the choice should be hidden if the condition is not met. /// Additional data associated with the choice. /// The current Dialogue instance for chaining. /// /// This method allows adding a choice to the dialogue with various options like text, icon, action to execute, conditions for showing the choice, /// and whether the dialogue should close when the choice is selected. /// Overloads of this method provide simplified ways to add choices with fewer parameters. /// public Dialogue AddChoice(string text, Sprite icon, Action action, Func condition = null, bool closeWhenSelected = true, bool hideIfConditionNotMet = false, ChoiceData data = null) { dialoguePanel.AddButton(text, icon, action, condition, closeWhenSelected, hideIfConditionNotMet, data); return this; } /// /// Adds a choice to the dialogue with various configurations. /// /// The text of the choice. /// The current Dialogue instance for chaining. /// /// This method allows adding a choice to the dialogue with various options like text, icon, action to execute, conditions for showing the choice, /// and whether the dialogue should close when the choice is selected. /// Overloads of this method provide simplified ways to add choices with fewer parameters. /// public Dialogue AddChoice(string text) { dialoguePanel.AddButton(text, null, null); return this; } /// /// Adds a choice to the dialogue with various configurations. /// /// The text of the choice. /// Optional icon for the choice. /// The current Dialogue instance for chaining. /// /// This method allows adding a choice to the dialogue with various options like text, icon, action to execute, conditions for showing the choice, /// and whether the dialogue should close when the choice is selected. /// Overloads of this method provide simplified ways to add choices with fewer parameters. /// public Dialogue AddChoice(string text, Sprite icon) { dialoguePanel.AddButton(text, icon, null); return this; } /// /// Adds a choice to the dialogue with various configurations. /// /// The text of the choice. /// Optional action to execute when the choice is selected. /// The current Dialogue instance for chaining. /// /// This method allows adding a choice to the dialogue with various options like text, icon, action to execute, conditions for showing the choice, /// and whether the dialogue should close when the choice is selected. /// Overloads of this method provide simplified ways to add choices with fewer parameters. /// public Dialogue AddChoice(string text, Action action) { dialoguePanel.AddButton(text, null, action); return this; } public Dialogue SetBackground(Sprite background) { if (dialoguePanel.background == null) return this; dialoguePanel.background.sprite = background; return this; } public Dialogue SetNativeSize() { if (dialoguePanel.background == null) return this; dialoguePanel.background.SetNativeSize(); return this; } public Dialogue SetTypeWriterDuration(float seconds) { dialoguePanel.typewriter.seconds = seconds; return this; } public void Init(float time, bool typeWriter, Action onUpdate) { NullUtils.DelayedCall(new DelayedCallParams { WaitUntil = () => dialoguePanel == null || dialoguePanel.transform.parent == null || dialoguePanel.transform.GetSiblingIndex() == dialoguePanel.transform.parent.childCount - 1, Call = () => { if (dialoguePanel == null) { return; } if (time > 0) { dialoguePanel.counterId = NullUtils.GenerateID(); NullUtils.DelayedCall(new DelayedCallParams { DelayName = dialoguePanel.counterId, Delay = time, Call = () => { onTimeout?.Invoke(); Close(); }, OnUpdate = f => { dialoguePanel.counterLabel.text = Mathf.RoundToInt(f).ToString(); onUpdate?.Invoke(f); }, UnscaledTime = DialogueManager.Instance.unscaledTime }); // NullUtils.DelayedCall(dialoguePanel.counterId, null, time, () => { // onTimeout?.Invoke(); // Close(); // }, f => { // dialoguePanel.counterLabel.text = Mathf.RoundToInt(f).ToString(); // onUpdate?.Invoke(f); // }, DialogueManager.Instance.unscaledTime); dialoguePanel.hasTimer.Invoke(); } //Start TypeWriter Effect if (typeWriter) { dialoguePanel.typewriter.StartTypeWriter(); } foreach (var audioSource in soundSources) { audioSource.Value.Play(); } foreach (var audioSource in voiceSources) { audioSource.Value.Play(); } ShowedUp = true; } }); // NullUtils.DelayedCall(null, () => dialoguePanel == null || dialoguePanel.transform.parent == null || dialoguePanel.transform.GetSiblingIndex() == dialoguePanel.transform.parent.childCount - 1, () => { // if (dialoguePanel == null) { // return; // } // // if (time > 0) { // dialoguePanel.counterId // = NullUtils.GenerateID(); // NullUtils.DelayedCall(dialoguePanel.counterId, null, time, () => { // onTimeout?.Invoke(); // Close(); // }, f => { // dialoguePanel.counterLabel.text = Mathf.RoundToInt(f).ToString(); // onUpdate?.Invoke(f); // }, DialogueManager.Instance.unscaledTime); // // dialoguePanel.hasTimer.Invoke(); // } // // //Start TypeWriter Effect // if (typeWriter) { // dialoguePanel.typewriter.StartTypeWriter(); // } // // foreach (var audioSource in soundSources) { // audioSource.Value.Play(); // } // // foreach (var audioSource in voiceSources) { // audioSource.Value.Play(); // } // // ShowedUp = true; // }); } public (string, AudioSource) AddSound(SoundClassData soundClassData) { var soundId = NullUtils.GenerateID(); var soundSource = IM.SetupAudio(soundId, soundClassData.Clip, soundClassData.Volume); if (soundSource == null) return (null, null); soundSource.pitch = soundClassData.Pitch; soundSource.volume = soundClassData.Volume; soundSource.outputAudioMixerGroup = soundClassData.AudioMixerGroup; soundSource.loop = soundClassData.Loop; soundSources.Add(soundClassData, soundSource); return (soundId, soundSource); } public (string, AudioSource) AddSound(VoiceClassData voiceClassData) { var soundId = NullUtils.GenerateID(); var voiceSource = IM.SetupAudio(soundId, voiceClassData.Clip, voiceClassData.Volume); if (voiceSource == null) return (null, null); voiceSource.pitch = voiceClassData.Pitch; voiceSource.volume = voiceClassData.Volume; voiceSource.outputAudioMixerGroup = voiceClassData.AudioMixerGroup; voiceSources.Add(voiceClassData, voiceSource); return (soundId, voiceSource); } public void Update() { if (ShowedUp) { if (soundSources.Count > 0) { if (IsTop) { foreach (var audioSource in soundSources) { if(audioSource.Value != null) audioSource.Value.UnPause(); } } else { foreach (var audioSource in soundSources) { if(audioSource.Value != null) audioSource.Value.Pause(); } } } if (voiceSources.Count > 0) { if (IsTop) { foreach (var audioSource in voiceSources) { if(audioSource.Value != null) audioSource.Value.UnPause(); } } else { foreach (var audioSource in voiceSources) { if(audioSource.Value != null) audioSource.Value.Pause(); } } } } } public bool IsTop => dialoguePanel != null && dialoguePanel.transform.parent != null && dialoguePanel.transform.GetSiblingIndex() == dialoguePanel.transform.parent.childCount - 1; /// /// Adds a choice to the dialogue with various configurations. /// /// The text of the choice. /// Optional icon for the choice. /// Optional action to execute when the choice is selected. /// Determines if the dialogue should close when the choice is selected. /// The current Dialogue instance for chaining. /// /// This method allows adding a choice to the dialogue with various options like text, icon, action to execute, conditions for showing the choice, /// and whether the dialogue should close when the choice is selected. /// Overloads of this method provide simplified ways to add choices with fewer parameters. /// public Dialogue AddChoice(string text, Sprite icon, Action action, bool closeWhenSelected) { dialoguePanel.AddButton(text, icon, action, null, closeWhenSelected); return this; } } }