How can I? Disco Elysium Style Text Feed

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
GerPronouncedGrr
Posts: 6
Joined: Mon Sep 21, 2015 1:52 pm

How can I? Disco Elysium Style Text Feed

Post by GerPronouncedGrr »

I'm looking for some advice on how to get started on making my dialogue system resemble that of games like Disco Elysium or Citizen Sleeper. Mainly, I like how the current text is shown on the bottom of the "feed" and the previous text is shown above that in the feed, but slightly greyed out or with some other styling to denote that it's not current. I'm pretty new to the dialogue system so any pointers at all would be appreciated.
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: How can I? Disco Elysium Style Text Feed

Post by Tony Li »

Hi,

You can start with the Scrolling Dialogue UI prefab. Then add an OnConversationLine() method to the Dialogue Manager or dialogue UI that uses UITools.WrapTextInColor to wrap older text in a different color. When updating the older text, I recommend removing the old <color=gray>...</color> tags first to avoid a ridiculous amount of nested tags.
GerPronouncedGrr
Posts: 6
Joined: Mon Sep 21, 2015 1:52 pm

Re: How can I? Disco Elysium Style Text Feed

Post by GerPronouncedGrr »

Thank you, I didn't see that particular prefab. I was able to find the WrapTextInColor function you mentioned, but are you saying that I should modify the base DialogueManager.cs (PixelCrushers->DialogueSystem->Scripts->Manager)? Sorry, I am not particularly experienced with modifying other people's code so please forgive my confusion.
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: How can I? Disco Elysium Style Text Feed

Post by Tony Li »

No need to modify any Dialogue System source code. Just add a script like the one below. Here's an example scene with the script, which I added to the dialogue UI GameObject:

[NOTE: UPDATED PACKAGE AT END OF THREAD.]

DS_GrayAccumulatedTextExample_2022-07-08.unitypackage

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;

public class GrayAccumulatedText : MonoBehaviour
{

    public Color oldTextColor = Color.gray;

    public void OnConversationLine(Subtitle subtitle)
    {
        if (string.IsNullOrEmpty(subtitle.formattedText.text)) return;
        SetAccumulatedTextGray();
    }

    private void SetAccumulatedTextGray()
    { 
        var subtitlePanel = DialogueManager.standardDialogueUI.conversationUIElements.defaultNPCSubtitlePanel;
        // Remove color tags from old accumulated text:
        if (subtitlePanel.accumulatedText.StartsWith("<color="))
        {
            var tagLength = subtitlePanel.accumulatedText.IndexOf(">") + 1;
            subtitlePanel.accumulatedText = subtitlePanel.accumulatedText.Remove(0, tagLength);
            var endTagPos = subtitlePanel.accumulatedText.LastIndexOf("</color>");
            subtitlePanel.accumulatedText = subtitlePanel.accumulatedText.Remove(endTagPos, "</color>".Length);
        }
        // Wrap accumulated text in gray:
        subtitlePanel.accumulatedText = UITools.WrapTextInColor(subtitlePanel.accumulatedText, oldTextColor);
    }
}
GerPronouncedGrr
Posts: 6
Joined: Mon Sep 21, 2015 1:52 pm

Re: How can I? Disco Elysium Style Text Feed

Post by GerPronouncedGrr »

Ah! I understand now. Thank you very much.
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: How can I? Disco Elysium Style Text Feed

Post by Tony Li »

Happy to help!
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: How can I? Disco Elysium Style Text Feed

Post by Tony Li »

Here's an updated package and script that handles all cases, including color applied to prepended actor names:

DS_GrayAccumulatedTextExample_2023-05-23.unitypackage

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;
using System.Text.RegularExpressions;

public class GrayAccumulatedText : MonoBehaviour
{

    public Color oldTextColor = Color.gray;

    public void OnConversationLine(Subtitle subtitle)
    {
        if (string.IsNullOrEmpty(subtitle.formattedText.text)) return;
        SetAccumulatedTextGray();
    }

    private void SetAccumulatedTextGray()
    { 
        var subtitlePanel = DialogueManager.standardDialogueUI.conversationUIElements.defaultNPCSubtitlePanel;

        // Remove color tags from old accumulated text:
        const string pattern = @"<color=[#]?\w+>|</color>";
        subtitlePanel.accumulatedText = Regex.Replace(subtitlePanel.accumulatedText, pattern, string.Empty);

        // Wrap accumulated text in gray:
        subtitlePanel.accumulatedText = UITools.WrapTextInColor(subtitlePanel.accumulatedText, oldTextColor);
    }
}
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: How can I? Disco Elysium Style Text Feed

Post by Tony Li »

NOTE: For a more sophisticated version of the script below, see How To: Color Actor Name and Indent Text.


Alternatively, since someone asked elsewhere, you can use a subclass of StandardUISubtitlePanel that overrides the SetContent() method like below. This version also accumulates sequential lines of dialogue spoken by the same actor into a single paragraph without line breaks.

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;
using System.Text.RegularExpressions;

public class ContinueParagraphSubtitlePanel : StandardUISubtitlePanel
{

    private int previousSpeakerID;

    public override void OnConversationStart(Transform actor)
    {
        base.OnConversationStart(actor);
        previousSpeakerID = -1;
    }

    protected override void SetSubtitleTextContent(Subtitle subtitle)
    {
        if (subtitle.speakerInfo.id == previousSpeakerID && 
            !string.IsNullOrEmpty(accumulatedText) && 
            !string.IsNullOrEmpty(subtitle.formattedText.text))
        {
            // If the same speaker, add to paragraph.
            // This code is similar to the base SetContent() except it doesn't
            // add a line break.
            if (addSpeakerName)
            {
                // Also remove the prepended actor name since it's a repeat. Assumes "Name: Text".
                subtitle.formattedText.text = subtitle.formattedText.text.Substring(subtitle.speakerInfo.Name.Length + 2);
            }
            TypewriterUtility.StopTyping(subtitleText);
            var previousText = accumulatedText;
            if (!string.IsNullOrEmpty(previousText) && previousText.EndsWith('\n'))
            {
                previousText = previousText.Substring(0, previousText.Length - 1);
            }
            previousText += " ";
            var previousChars = accumulateText ? UITools.StripRPGMakerCodes(Tools.StripTextMeshProTags(Tools.StripRichTextCodes(previousText))).Length : 0;
            SetFormattedText(subtitleText, previousText, subtitle.formattedText);
            accumulatedText = UITools.StripRPGMakerCodes(subtitleText.text);
            if (scrollbarEnabler != null && !HasTypewriter())
            {
                scrollbarEnabler.CheckScrollbarWithResetValue(0);
            }
            else if (delayTypewriterUntilOpen && !hasFocus)
            {
                DialogueManager.instance.StartCoroutine(StartTypingWhenFocused(subtitleText, subtitleText.text, previousChars));
            }
            else
            {
                TypewriterUtility.StartTyping(subtitleText, subtitleText.text, previousChars);
            }
        }
        else
        {
            // When changing speakers, remove color tags from old accumulated text:
            const string pattern = @"<color=[#]?\w+>|</color>";
            accumulatedText = Regex.Replace(accumulatedText, pattern, string.Empty);
            if (!string.IsNullOrEmpty(accumulatedText) && !accumulatedText.EndsWith('\n'))
            {
                accumulatedText += '\n'; // Add line break.
            }

            // Wrap accumulated text in gray:
            accumulatedText = UITools.WrapTextInColor(accumulatedText, Color.gray);

            base.SetSubtitleTextContent(subtitle);
        }

        previousSpeakerID = subtitle.speakerInfo.id;
    }
}
Post Reply