Page 1 of 1

How can I? Disco Elysium Style Text Feed

Posted: Fri Jul 08, 2022 5:18 pm
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.

Re: How can I? Disco Elysium Style Text Feed

Posted: Fri Jul 08, 2022 5:53 pm
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.

Re: How can I? Disco Elysium Style Text Feed

Posted: Fri Jul 08, 2022 6:53 pm
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.

Re: How can I? Disco Elysium Style Text Feed

Posted: Fri Jul 08, 2022 8:28 pm
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);
    }
}

Re: How can I? Disco Elysium Style Text Feed

Posted: Fri Jul 08, 2022 8:40 pm
by GerPronouncedGrr
Ah! I understand now. Thank you very much.

Re: How can I? Disco Elysium Style Text Feed

Posted: Fri Jul 08, 2022 9:17 pm
by Tony Li
Happy to help!

Re: How can I? Disco Elysium Style Text Feed

Posted: Tue May 23, 2023 9:56 pm
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);
    }
}

Re: How can I? Disco Elysium Style Text Feed

Posted: Sat Jun 24, 2023 4:09 pm
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;
    }
}