コード例 #1
0
        public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
        {
            var characterName = dialogueLine.CharacterName;

            Color colorToUse = defaultColor;

            if (string.IsNullOrEmpty(characterName) == false)
            {
                foreach (var color in colorData)
                {
                    if (color.characterName.Equals(characterName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        colorToUse = color.displayColor;
                        break;
                    }
                }
            }

            foreach (var text in lineTexts)
            {
                text.color = colorToUse;
            }

            onDialogueLineFinished();
        }
コード例 #2
0
        /// <summary>
        /// Start playback of the associated voice over <see
        /// cref="AudioClip"/> of the given <see cref="LocalizedLine"/>.
        /// </summary>
        /// <param name="dialogueLine"></param>
        /// <returns></returns>
        public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
        {
            finishCurrentLine = false;

            if (!(dialogueLine is AudioLocalizedLine audioLine))
            {
                Debug.LogError($"Playing voice over failed because {nameof(RunLine)} expected to receive an {nameof(AudioLocalizedLine)}, but instead received a {dialogueLine.GetType()}. Is your {nameof(DialogueRunner)} set up to use a {nameof(AudioLineProvider)}?", gameObject);
                onDialogueLineFinished();
                return;
            }

            // Get the localized voice over audio clip
            var voiceOverClip = audioLine.AudioClip;

            if (!voiceOverClip)
            {
                Debug.Log("Playing voice over failed since the AudioClip of the voice over audio language or the base language was null.", gameObject);
                onDialogueLineFinished();
                return;
            }
            if (audioSource.isPlaying)
            {
                // Usually, this shouldn't happen because the
                // DialogueRunner finishes and ends a line first
                audioSource.Stop();
            }
            audioSource.PlayOneShot(voiceOverClip);

            StartCoroutine(DoPlayback(onDialogueLineFinished));
        }
コード例 #3
0
        public override void OnLineStatusChanged(LocalizedLine dialogueLine)
        {
            switch (dialogueLine.Status)
            {
            case LineStatus.Presenting:
                // Nothing to do here - continue running.
                break;

            case LineStatus.Interrupted:
                // The user wants us to wrap up the audio quickly. The
                // DoPlayback coroutine will apply the fade out defined
                // by fadeOutTimeOnLineFinish.
                interrupted = true;
                break;

            case LineStatus.FinishedPresenting:
                // The line has finished delivery on all views. Nothing
                // left to do for us, since the audio will have already
                // finished playing out.
                break;

            case LineStatus.Dismissed:
                // The line is being dismissed; ensure that we
                // interrupt the FMOD instance.
                interrupted = true;
                break;
            }
        }
コード例 #4
0
ファイル: DialogueUI.cs プロジェクト: Greentwip/Leana-Fire
        public override void OnLineStatusChanged(LocalizedLine dialogueLine)
        {
            switch (dialogueLine.Status)
            {
            case LineStatus.Running:
                // No-op; this line is running
                break;

            case LineStatus.Interrupted:
                // The line is now interrupted, and we need to hurry up
                // in our delivery
                finishCurrentLine = true;
                break;

            case LineStatus.Delivered:
                // The line has now finished its delivery across all
                // views, so we can signal call our UnityEvent for it
                onLineFinishDisplaying?.Invoke();
                break;

            case LineStatus.Ended:
                // The line has now Ended. DismissLine will be called
                // shortly.
                onLineEnd?.Invoke();
                break;
            }
        }
コード例 #5
0
        public override void OnLineStatusChanged(LocalizedLine dialogueLine)
        {
            switch (dialogueLine.Status)
            {
            case LineStatus.Running:
                // Nothing to do here - continue running.
                break;

            case LineStatus.Interrupted:
                // The user wants us to wrap up the audio quickly. The
                // DoPlayback coroutine will apply the fade out defined
                // by fadeOutTimeOnLineFinish.
                finishCurrentLine = true;
                break;

            case LineStatus.Delivered:
                // The line has finished delivery on all views. Nothing
                // left to do for us, since the audio will have already
                // finished playing out.
                break;

            case LineStatus.Ended:
                // The line is being dismissed; we should ensure that
                // audio playback has ended.
                audioSource.Stop();
                break;
            }
        }
コード例 #6
0
 public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
 {
     // Don't do anything with this line except note it and
     // immediately indicate that we're finished with it. RunOptions
     // will use it to display the text of the previous line.
     lastSeenLine = dialogueLine;
     onDialogueLineFinished();
 }
コード例 #7
0
        public override void RunLine(LocalizedLine dialogueLine, System.Action onDialogueDeliveryComplete)
        {
            StartCoroutine(DoRunLine(dialogueLine, onDialogueDeliveryComplete));

            IEnumerator DoRunLine(LocalizedLine dialogueLine, System.Action onDialogueDeliveryComplete)
            {
                interrupted = false;

                // Check if this instance is currently playing back another
                // voice over in which case we stop it
                if (lastVoiceOverEvent.isValid())
                {
                    lastVoiceOverEvent.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
                }

                // Create playback event
                FMOD.Studio.EventInstance dialogueInstance;
                try
                {
                    dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(fmodEvent);
                }
                catch (Exception)
                {
                    UnityEngine.Debug.LogWarning("FMOD: Voice over playback failed.", gameObject);
                    throw;
                }

                lastVoiceOverEvent = dialogueInstance;

                // Pin the key string in memory and pass a pointer through the
                // user data
                GCHandle stringHandle = GCHandle.Alloc(dialogueLine.TextID.Remove(0, 5), GCHandleType.Pinned);

                dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle));

                dialogueInstance.setCallback(dialogueCallback, FMOD.Studio.EVENT_CALLBACK_TYPE.ALL);
                dialogueInstance.start();
                dialogueInstance.release();

                while (!interrupted && dialogueInstance.isValid())
                {
                    yield return(null);
                }

                if (dialogueInstance.isValid())
                {
                    dialogueInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
                }
            }
        }
コード例 #8
0
        public override void DismissLine(Action onDismissalComplete)
        {
            currentLine = null;
            hasPresented.Clear();

            if (useFadeEffect)
            {
                StartCoroutine(Effects.FadeAlpha(canvasGroup, 1, 0, fadeOutTime, hasPresented, onDismissalComplete));
            }
            else
            {
                canvasGroup.interactable   = false;
                canvasGroup.alpha          = 0;
                canvasGroup.blocksRaycasts = false;
                onDismissalComplete();
            }
        }
コード例 #9
0
        public override void InterruptLine(LocalizedLine dialogueLine, Action onInterruptLineFinished)
        {
            currentLine = dialogueLine;
            StopAllCoroutines();
            hasPresented.Clear();

            // for now we are going to just immediately show everything
            // later we will make it fade in
            lineText.gameObject.SetActive(true);
            canvasGroup.gameObject.SetActive(true);

            int length;

            if (continueButton != null)
            {
                continueButton.SetActive(false);
            }
            if (characterNameText == null)
            {
                if (showCharacterNameInLineView)
                {
                    lineText.text = dialogueLine.Text.Text;
                    length        = dialogueLine.Text.Text.Length;
                }
                else
                {
                    lineText.text = dialogueLine.TextWithoutCharacterName.Text;
                    length        = dialogueLine.TextWithoutCharacterName.Text.Length;
                }
            }
            else
            {
                characterNameText.text = dialogueLine.CharacterName;
                lineText.text          = dialogueLine.TextWithoutCharacterName.Text;
                length = dialogueLine.TextWithoutCharacterName.Text.Length;
            }

            lineText.maxVisibleCharacters = length;

            canvasGroup.interactable   = true;
            canvasGroup.alpha          = 1;
            canvasGroup.blocksRaycasts = true;

            onInterruptLineFinished();
        }
コード例 #10
0
        public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
        {
            // Try and get the character name from the line
            var hasCharacterName = dialogueLine.Text.TryGetAttributeWithName("character", out var characterAttribute);

            // Did we find one?
            if (hasCharacterName)
            {
                // Then notify the rest of the scene about it. This
                // generally involves updating a text view and making it
                // visible.
                onNameUpdate?.Invoke(characterAttribute.Properties["name"].StringValue);
            }
            else
            {
                // Otherwise, notify the scene about not finding it. This
                // generally involves making the name text view not
                // visible.
                onNameNotPresent?.Invoke();
            }

            // Immediately mark this view as having finished its work
            onDialogueLineFinished();
        }
コード例 #11
0
        public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
        {
            // Try and get the character name from the line
            string characterName = dialogueLine.CharacterName;

            // Did we find one?
            if (!string.IsNullOrEmpty(characterName))
            {
                // Then notify the rest of the scene about it. This
                // generally involves updating a text view and making it
                // visible.
                onNameUpdate?.Invoke(characterName);
            }
            else
            {
                // Otherwise, notify the scene about not finding it. This
                // generally involves making the name text view not
                // visible.
                onNameNotPresent?.Invoke();
            }

            // Immediately mark this view as having finished its work
            onDialogueLineFinished();
        }
コード例 #12
0
 public override void InterruptLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
 {
     interrupted = true;
     onDialogueLineFinished();
 }
コード例 #13
0
        /// <summary>
        /// Start playback of the associated voice over <see
        /// cref="AudioClip"/> of the given <see cref="LocalizedLine"/>.
        /// </summary>
        /// <param name="dialogueLine"></param>
        /// <returns></returns>
        public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
        {
            interrupted = false;

            if (!(dialogueLine is AudioLocalizedLine audioLine))
            {
                Debug.LogError($"Playing voice over failed because {nameof(RunLine)} expected to receive an {nameof(AudioLocalizedLine)}, but instead received a {dialogueLine?.GetType().ToString() ?? "null"}. Is your {nameof(DialogueRunner)} set up to use a {nameof(AudioLineProvider)}?", gameObject);
                onDialogueLineFinished();
                return;
            }

            // Get the localized voice over audio clip
            var voiceOverClip = audioLine.AudioClip;

            if (!voiceOverClip)
            {
                Debug.Log("Playing voice over failed since the AudioClip of the voice over audio language or the base language was null.", gameObject);
                onDialogueLineFinished();
                return;
            }

            if (audioSource.isPlaying)
            {
                // Usually, this shouldn't happen because the
                // DialogueRunner finishes and ends a line first
                audioSource.Stop();
            }

            StartCoroutine(DoPlayback(voiceOverClip, onDialogueLineFinished));

            IEnumerator DoPlayback(AudioClip clip, Action onFinished)
            {
                // If we need to wait before starting playback, do this now
                if (waitTimeBeforeLineStart > 0)
                {
                    yield return(new WaitForSeconds(waitTimeBeforeLineStart));
                }

                // Start playing the audio.
                audioSource.PlayOneShot(clip);

                // Wait until either the audio source finishes playing, or the
                // interruption flag is set.
                while (audioSource.isPlaying && !interrupted)
                {
                    yield return(null);
                }

                // If the line was interrupted, we need to wrap up the playback
                // as quickly as we can. We do this here with a fade-out to
                // zero over fadeOutTimeOnLineFinish seconds.
                if (audioSource.isPlaying && interrupted)
                {
                    // Fade out voice over clip
                    float lerpPosition    = 0f;
                    float volumeFadeStart = audioSource.volume;
                    while (audioSource.volume != 0)
                    {
                        lerpPosition      += Time.unscaledDeltaTime / fadeOutTimeOnLineFinish;
                        audioSource.volume = Mathf.Lerp(volumeFadeStart, 0, lerpPosition);
                        yield return(null);
                    }
                    audioSource.Stop();
                    audioSource.volume = volumeFadeStart;
                }
                else
                {
                    audioSource.Stop();
                }

                // We've finished our playback at this point, either by waiting
                // normally or by interrupting it with a fadeout. If we weren't
                // interrupted, and we have additional time to wait after the
                // audio finishes, wait now. (If we were interrupted, we skip
                // this wait, because the user has already indicated that
                // they're fine with things moving faster than sounds normal.)

                if (interrupted == false && waitTimeAfterLineComplete > 0)
                {
                    yield return(new WaitForSeconds(waitTimeAfterLineComplete));
                }

                // We can now signal that the line delivery has finished.
                onFinished();
            }
        }
コード例 #14
0
ファイル: DialogueUI.cs プロジェクト: Greentwip/Leana-Fire
        /// <summary>
        /// Shows a line of dialogue, gradually.
        /// </summary>
        /// <param name="dialogueLine">The line to deliver.</param>
        /// <param name="onDialogueLineFinished">A callback to invoke when
        /// the text has finished appearing.</param>
        /// <returns></returns>
        protected IEnumerator DoRunLine(LocalizedLine dialogueLine, System.Action onDialogueLineFinished)
        {
            onLineStart?.Invoke();

            finishCurrentLine = false;

            // The final text we'll be showing for this line.
            string text;

            // Are we hiding the character name?
            if (showCharacterName == false)
            {
                // First, check to see if we have it
                var hasCharacterAttribute = dialogueLine.Text.TryGetAttributeWithName("character", out var characterAttribute);

                // If we do, remove it from the markup, and use the
                // resulting text
                if (hasCharacterAttribute)
                {
                    text = dialogueLine.Text.DeleteRange(characterAttribute).Text;
                }
                else
                {
                    // This line doesn't have a [character] attribute, so
                    // there's nothing to remove. We'll use the entire
                    // text.
                    text = dialogueLine.Text.Text;
                }
            }
            else
            {
                text = dialogueLine.Text.Text;
            }

            if (textSpeed > 0.0f)
            {
                // Display the line one character at a time
                var stringBuilder = new StringBuilder();

                foreach (char c in text)
                {
                    stringBuilder.Append(c);
                    onLineUpdate?.Invoke(stringBuilder.ToString());
                    if (finishCurrentLine)
                    {
                        // We've requested a skip of the entire line.
                        // Display all of the text immediately.
                        onLineUpdate?.Invoke(text);
                        break;
                    }
                    yield return(new WaitForSeconds(textSpeed));
                }
            }
            else
            {
                // Display the entire line immediately if textSpeed <= 0
                onLineUpdate?.Invoke(text);
            }


            // Indicate to the rest of the game that the text has finished
            // being delivered
            onTextFinishDisplaying?.Invoke();

            // Indicate to the dialogue runner that we're done delivering
            // the line here
            onDialogueLineFinished();
        }
コード例 #15
0
 public override void OnLineStatusChanged(LocalizedLine dialogueLine)
 {
     // We don't need to do anything when the line status changes
     // for this view
 }
コード例 #16
0
ファイル: DialogueUI.cs プロジェクト: Greentwip/Leana-Fire
 /// <inheritdoc/>
 public override void RunLine(LocalizedLine dialogueLine, System.Action onDialogueLineFinished)
 {
     StartCoroutine(DoRunLine(dialogueLine, onDialogueLineFinished));
 }
コード例 #17
0
 public override void RunLine(LocalizedLine dialogueLine, System.Action onDialogueDeliveryComplete)
 {
     StartCoroutine(DoRunLine(dialogueLine, onDialogueDeliveryComplete));
 }
コード例 #18
0
 /// <summary>
 /// Called by the <see cref="DialogueRunner"/> to signal that a line has
 /// been interrupted, and that the Dialogue View should finish
 /// presenting its line as quickly as possible.
 /// </summary>
 /// <remarks>
 /// <para>
 /// This method is called when Dialogue Runner wants to interrupt the
 /// presentation of the current line, in order to proceed to the next
 /// piece of content.
 /// </para>
 /// <para>
 /// When this method is called, the Dialogue View must finish presenting
 /// their line as quickly as it can. Depending on how this Dialogue View
 /// presents lines, this can mean different things: for example, a view
 /// that plays voice-over audio might stop playback immediately, or fade
 /// out playback over a short period of time; a view that displays text
 /// a letter at a time might display all of the text at once.
 /// </para>
 /// <para>
 /// The process of finishing the presentation can take time to complete,
 /// but should happen as quickly as possible, because this method is
 /// generally called when the user wants to skip the current line.
 /// </para>
 /// <para>
 /// When the line has finished presenting, the <paramref
 /// name="onDialogueLineFinished"/> method must be called, which
 /// indicates to the Dialogue Runner that this line is ready to be
 /// dismissed.
 /// </para>
 /// <para style="danger">
 /// When <see cref="InterruptLine"/> is called, you must not call the
 /// completion handler that <see cref="RunLine"/> has previously
 /// received - this completion handler is no longer valid. Call this method's <paramref name="onDialogueLineFinished"/> instead.
 /// </para>
 /// <para style="note">
 /// The default implementation of this method immediately calls the
 /// <paramref name="onDialogueLineFinished"/> method (that is, it
 /// reports that it has finished presenting the line the moment that it
 /// receives it), and otherwise does nothing.
 /// </para>
 /// </remarks>
 /// <param name="dialogueLine">The current line that is being
 /// presented.</param>
 /// <param name="onDialogueLineFinished">The method that should be
 /// called after the line has finished being presented.</param>
 /// <seealso cref="RunLine(LocalizedLine, Action)"/>
 /// <seealso cref="DismissLine(Action)"/>
 public virtual void InterruptLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
 {
     // the default implementation does nothing
     onDialogueLineFinished?.Invoke();
 }
コード例 #19
0
 /// <summary>
 /// Called by the DialogueRunner to indicate that the line that
 /// this view is delivering has changed state.
 /// </summary>
 /// <remarks>
 /// Subclasses of <see cref="DialogueViewBase"/> should override
 /// this method to be notified when a line has become interrupted,
 /// and when the line has finished being delivered by all views.
 ///
 /// The default implementation does nothing.
 /// </remarks>
 /// <param name="dialogueLine">The <see cref="LocalizedLine"/> that
 /// has changed state.</param>
 /// <seealso cref="LineStatus"/>
 public abstract void OnLineStatusChanged(LocalizedLine dialogueLine);
コード例 #20
0
        public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
        {
            currentLine = dialogueLine;
            hasPresented.Clear();

            // if we have auto advance on we just hand over the completion handler
            // if we don't have auto advance we send over no completion handler and store the completion handler
            // this way it can be called later by the user action
            var completionHandler = autoAdvance ? onDialogueLineFinished : null;

            dialogueFinishedAction = onDialogueLineFinished;

            lineText.gameObject.SetActive(true);
            canvasGroup.gameObject.SetActive(true);

            if (continueButton != null)
            {
                continueButton.SetActive(false);
            }

            if (characterNameText == null)
            {
                if (showCharacterNameInLineView)
                {
                    lineText.text = dialogueLine.Text.Text;
                }
                else
                {
                    lineText.text = dialogueLine.TextWithoutCharacterName.Text;
                }
            }
            else
            {
                characterNameText.text = dialogueLine.CharacterName;
                lineText.text          = dialogueLine.TextWithoutCharacterName.Text;
            }

            bool needsHold = autoAdvance && holdTime > 0;

            if (useFadeEffect)
            {
                if (useTypewriterEffect)
                {
                    // If we're also using a typewriter effect, ensure that
                    // there are no visible characters so that we don't
                    // fade in on the text fully visible
                    lineText.maxVisibleCharacters = 0;
                }
                else
                {
                    // Ensure that the max visible characters is effectively unlimited.
                    lineText.maxVisibleCharacters = int.MaxValue;
                }

                // if we are set to auto advance we want to hold for the
                // amount of time set in holdTime before calling the
                // completion handler to continue the dialogue
                if (needsHold)
                {
                    StartCoroutine(Effects.FadeAlpha(canvasGroup, 0, 1, fadeInTime, useTypewriterEffect ? null: hasPresented, () => FadeComplete(() => HoldAndContinue(completionHandler))));
                }
                else
                {
                    // Fade up and then call FadeComplete when done
                    StartCoroutine(Effects.FadeAlpha(canvasGroup, 0, 1, fadeInTime, useTypewriterEffect ? null: hasPresented, () => FadeComplete(completionHandler)));
                }
            }
            else
            {
                // Immediately appear
                canvasGroup.interactable   = true;
                canvasGroup.alpha          = 1;
                canvasGroup.blocksRaycasts = true;

                if (useTypewriterEffect)
                {
                    if (needsHold)
                    {
                        StartCoroutine(Effects.Typewriter(lineText, typewriterEffectSpeed, hasPresented, OnCharacterTyped, () => HoldAndContinue(completionHandler)));
                    }
                    else
                    {
                        StartCoroutine(Effects.Typewriter(lineText, typewriterEffectSpeed, hasPresented, OnCharacterTyped, completionHandler));
                    }
                }
                else
                {
                    if (needsHold)
                    {
                        Action hold = () => {
                            hasPresented.Set();
                            completionHandler();
                        };
                        HoldAndContinue(hold);
                    }
                    else
                    {
                        hasPresented.Set();
                        completionHandler();
                    }
                }
            }

            void FadeComplete(Action onFinished)
            {
                if (useTypewriterEffect)
                {
                    StartCoroutine(Effects.Typewriter(lineText, typewriterEffectSpeed, hasPresented, OnCharacterTyped, onFinished));
                }
                else
                {
                    onFinished();
                }
            }

            void HoldAndContinue(Action onFinished)
            {
                StartCoroutine(DelayAction(holdTime, onFinished));
            }
        }
コード例 #21
0
 /// <summary>
 /// Called by the <see cref="DialogueRunner"/> to signal that a line
 /// should be displayed to the user.
 /// </summary>
 /// <remarks>
 /// <para>
 /// When this method is called, the Dialogue View should present the
 /// line to the user. The content to present is contained within the
 /// <paramref name="dialogueLine"/> parameter, which contains
 /// information about the line in the user's current locale.
 /// </para>
 /// <para style="info">The value of the <paramref name="dialogueLine"/>
 /// parameter is produced by the Dialogue Runner's <see
 /// cref="LineProviderBehaviour"/>.
 /// </para>
 /// <para>
 /// It's up to the Dialogue View to decide what "presenting" the line
 /// may mean; for example, showing on-screen text, or playing voice-over
 /// audio.
 /// </para>
 /// <para>When the line has finished being presented, this method calls
 /// the <paramref name="onDialogueLineFinished"/> method, which signals
 /// to the Dialogue Runner that this Dialogue View has finished
 /// presenting the line. When all Dialogue Views have finished
 /// presenting the line, the Dialogue Runner calls <see
 /// cref="DismissLine(Action)"/> to signal that the views should get rid
 /// of the line.</para>
 /// <para>
 /// If you want to create a Dialogue View that waits for user input
 /// before continuing, either wait for that input before calling
 /// <paramref name="onDialogueLineFinished"/>, or don't call it at all
 /// and instead call <see cref="requestInterrupt"/> to tell the Dialogue
 /// Runner to interrupt the line.
 /// </para>
 /// <para style="danger">
 /// The <paramref name="onDialogueLineFinished"/> method should only be
 /// called when <see cref="RunLine"/> finishes its presentation
 /// normally. If <see cref="InterruptLine"/> has been called, you must
 /// call the completion handler that it receives, and not the completion
 /// handler that <see cref="RunLine"/> has received.
 /// </para>
 /// <para style="note">
 /// The default implementation of this method immediately calls the
 /// <paramref name="onDialogueLineFinished"/> method (that is, it
 /// reports that it has finished presenting the line the moment that it
 /// receives it), and otherwise does nothing.
 /// </para>
 /// </remarks>
 /// <param name="dialogueLine">The content of the line that should be
 /// presented to the user.</param>
 /// <param name="onDialogueLineFinished">The method that should be
 /// called after the line has finished being presented.</param>
 /// <seealso cref="InterruptLine(LocalizedLine, Action)"/>
 /// <seealso cref="DismissLine(Action)"/>
 /// <seealso cref="RunOptions(DialogueOption[], Action{int})"/>
 public virtual void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
 {
     // The default implementation does nothing, and immediately calls
     // onDialogueLineFinished.
     onDialogueLineFinished?.Invoke();
 }
コード例 #22
0
 /// <summary>
 /// Called by the <see cref="DialogueRunner"/> to signal that a
 /// line should be displayed to the user.
 /// </summary>
 /// <remarks>
 /// If this method returns <see
 /// cref="Dialogue.HandlerExecutionType.ContinueExecution"/>, it
 /// should not call the <paramref name="onDialogueLineFinished"/>
 /// method.
 /// </remarks>
 /// <param name="dialogueLine">The content of the line that should
 /// be presented to the user.</param>
 /// <param name="onDialogueLineFinished">The method that should be
 /// called after the line has been finished.</param>
 /// FIXME: If this method is expected to be called only from the
 /// DialogueRunner then this should be converted into a coroutine
 /// and merged with RunLineWithCallback();
 public abstract void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished);