[HOWTO] How To: Color Actor Name and Indent Text

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
User avatar
Tony Li
Posts: 20677
Joined: Thu Jul 18, 2013 1:27 pm

[HOWTO] How To: Color Actor Name and Indent Text

Post by Tony Li »

This script is a replacement for StandardUISubtitlePanel. It does the following:
  • Prepends the speaker's name using the actor's Node Color as set in the Dialogue Editor window. (You must set the actor's Node Color.)
  • Indents the text after the actor's name.
  • Combines sequential lines spoken by the same actor into the same paragraph instead of separating them with a newline.
  • Sets older lines' alpha color values to semitransparent.
It requires using TextMesh Pro, and you will probably need to fix a bug in TextMesh Pro as described in How To: Indent Text.

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;

public class ContinueParagraphSubtitlePanel : StandardUISubtitlePanel
{

    private int previousSpeakerID;
    private bool firstChange;
    private string originalWebColor;

    public override void OnConversationStart(Transform actor)
    {
        base.OnConversationStart(actor);
        previousSpeakerID = -1;
        addSpeakerName = false; // We'll do it manually.
        firstChange = true;
    }

    protected override void Awake()
    {
        base.Awake();
        originalWebColor = Tools.ToWebColor(subtitleText.color);
    }

    protected override void SetSubtitleTextContent(Subtitle subtitle)
    {
        // Change old text <color=#rrggbbff> tags to alpha aa: // Change "aa" to a lower hex number if you want darker.
        accumulatedText = accumulatedText.Replace("ff>", "aa>");

        if (subtitle.speakerInfo.id != previousSpeakerID &&
            !string.IsNullOrEmpty(subtitle.formattedText.text))
        {
            // This is a new speaker, so prepend actor name and indent:

            // Prepend actor name with color:
            var actor = DialogueManager.masterDatabase.GetActor(subtitle.speakerInfo.id);
            if (actor != null)
            {
                var nodeColor = DialogueLua.GetActorField(actor.Name, "NodeColor").asString;
                if (!string.IsNullOrEmpty(nodeColor))
                {
                    var richTextColor = Tools.ToWebColor(NodeColorStringToColor(nodeColor));
                    var closeIndent = (previousSpeakerID != -1) ? "</indent>\n" : (firstChange && previousSpeakerID != -1 ? "\n" : "");
                    if (previousSpeakerID != -1 && firstChange)
                    {
                        closeIndent += "\n";
                        firstChange = false;
                    }
                    subtitle.formattedText.text = $"{closeIndent}<color={richTextColor}>{subtitle.speakerInfo.Name}: </color><color={originalWebColor}><indent=10%> {subtitle.formattedText.text}</color>";
                }
            }
            base.SetSubtitleTextContent(subtitle);
        }
        else
        {
            // If the same speaker, add to paragraph.
            // This code is similar to the base SetContent() except it doesn't
            // add a line break.
            TypewriterUtility.StopTyping(subtitleText);
            var previousText = accumulateText ? accumulatedText : string.Empty;
            subtitle.formattedText.text = $"<color={originalWebColor}>{subtitle.formattedText.text}</color>";
            if (accumulateText && !string.IsNullOrEmpty(subtitle.formattedText.text))
            {
                if (numAccumulatedLines < maxLines)
                {
                    numAccumulatedLines += (1 + NumCharOccurrences('\n', subtitle.formattedText.text));
                }
                else
                {
                    // If we're at the max number of lines, remove the first line from the accumulated text:
                    previousText = RemoveFirstLine(previousText);
                }
            }
            var previousChars = accumulateText ? UITools.StripRPGMakerCodes(Tools.StripTextMeshProTags(Tools.StripRichTextCodes(previousText))).Length : 0;
            SetFormattedText(subtitleText, previousText, subtitle);
            if (accumulateText) 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);
            }
        }

        previousSpeakerID = subtitle.speakerInfo.id;
    }

    public static Color NodeColor_Orange = new Color(1f, 0.5f, 0);
    public static Color NodeColor_Gray = new Color(0.9f, 0.9f, 0.9f);
    public static Color NodeColor_Blue = new Color(0.4f, 0.6f, 1f);
    public static Color NodeColor_Green = new Color(0, 1f, 0);
    public static Color NodeColor_Red = new Color(1f, 0.1f, 0.1f);

    private Color NodeColorStringToColor(string s)
    {
        switch (s)
        {
            case "Aqua":
                return Color.cyan;
            case "Blue":
                return NodeColor_Blue;
            case "Gray":
                return NodeColor_Gray;
            case "Green":
                return NodeColor_Green;
            case "Grey":
                return Color.gray;
            case "Orange":
                return NodeColor_Orange;
            case "Red":
                return NodeColor_Red;
            case "Yellow":
                return Color.yellow;
            default:
                return Tools.WebColor(s);
        }
    }
}
User avatar
Tony Li
Posts: 20677
Joined: Thu Jul 18, 2013 1:27 pm

Re: [HOWTO] How To: Color Actor Name and Indent Text

Post by Tony Li »

If you want to do this and gray old text, here's another script and example:

DS_ContinueParagraph_2024-04-09.unitypackage
Eldritch_Horror
Posts: 28
Joined: Sun May 28, 2023 8:30 pm

Re: [HOWTO] How To: Color Actor Name and Indent Text

Post by Eldritch_Horror »

Where does this C# script go/attach as component?
Apologies if this is a daft question.
User avatar
Tony Li
Posts: 20677
Joined: Thu Jul 18, 2013 1:27 pm

Re: [HOWTO] How To: Color Actor Name and Indent Text

Post by Tony Li »

Hi,

It's a replacement for the StandardUISubtitlePanel component. For example, if you're starting with a copy of the Scrolling Dialogue UI prefab, you'd replace the Subtitle Panel Info GameObject's StandardUISubtitlePanel with this subclass. To replace it in-place and retain UI element assignments, see How To: Replace Script with Subclass and Keep Field Assignments.
mind creates
Posts: 3
Joined: Wed Apr 17, 2024 10:30 am

Re: [HOWTO] How To: Color Actor Name and Indent Text

Post by mind creates »

I am receiving a console error (outlined below) when following the workflow outlined here:
For example, if you're starting with a copy of the Scrolling Dialogue UI prefab, you'd replace the Subtitle Panel Info GameObject's StandardUISubtitlePanel with this subclass. To replace it in-place and retain UI element assignments, see How To: Replace Script with Subclass and Keep Field Assignments.
Console Error:
Assets/Test/ContinueParagraphSubtitlePanel.cs(25,29): error CS0115: 'ContinueParagraphSubtitlePanel.SetSubtitleTextContent(Subtitle)': no suitable method found to override


Notes:
  • TextMesh Pro is installed.
  • I copy/pasted the provided code from this thread and received the error.
  • I did assume user error on my part, so I downloaded the example package (it contains the error also).
  • (I haven't ruled out user error, but may need to be pointed in the correct direction.)

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;

public class ContinueParagraphSubtitlePanel : StandardUISubtitlePanel
{

    private int previousSpeakerID;
    private bool firstChange;
    private string originalWebColor;

    public override void OnConversationStart(Transform actor)
    {
        base.OnConversationStart(actor);
        previousSpeakerID = -1;
        addSpeakerName = false; // We'll do it manually.
        firstChange = true;
    }

    protected override void Awake()
    {
        base.Awake();
        originalWebColor = Tools.ToWebColor(subtitleText.color);
    }

    protected override void SetSubtitleTextContent(Subtitle subtitle)
    {
        // Change old text <color=#rrggbbff> tags to alpha aa: // Change "aa" to a lower hex number if you want darker.
        accumulatedText = accumulatedText.Replace("ff>", "aa>");

        if (subtitle.speakerInfo.id != previousSpeakerID &&
            !string.IsNullOrEmpty(subtitle.formattedText.text))
        {
            // This is a new speaker, so prepend actor name and indent:

            // Prepend actor name with color:
            var actor = DialogueManager.masterDatabase.GetActor(subtitle.speakerInfo.id);
            if (actor != null)
            {
                var nodeColor = DialogueLua.GetActorField(actor.Name, "NodeColor").asString;
                if (!string.IsNullOrEmpty(nodeColor))
                {
                    var richTextColor = Tools.ToWebColor(NodeColorStringToColor(nodeColor));
                    var closeIndent = (previousSpeakerID != -1) ? "</indent>\n" : (firstChange && previousSpeakerID != -1 ? "\n" : "");
                    if (previousSpeakerID != -1 && firstChange)
                    {
                        closeIndent += "\n";
                        firstChange = false;
                    }
                    subtitle.formattedText.text = $"{closeIndent}<color={richTextColor}>{subtitle.speakerInfo.Name}: </color><color={originalWebColor}><indent=10%> {subtitle.formattedText.text}</color>";
                }
            }
            base.SetSubtitleTextContent(subtitle);
        }
        else
        {
            // If the same speaker, add to paragraph.
            // This code is similar to the base SetContent() except it doesn't
            // add a line break.
            TypewriterUtility.StopTyping(subtitleText);
            var previousText = accumulateText ? accumulatedText : string.Empty;
            subtitle.formattedText.text = $"<color={originalWebColor}>{subtitle.formattedText.text}</color>";
            if (accumulateText && !string.IsNullOrEmpty(subtitle.formattedText.text))
            {
                if (numAccumulatedLines < maxLines)
                {
                    numAccumulatedLines += (1 + NumCharOccurrences('\n', subtitle.formattedText.text));
                }
                else
                {
                    // If we're at the max number of lines, remove the first line from the accumulated text:
                    previousText = RemoveFirstLine(previousText);
                }
            }
            var previousChars = accumulateText ? UITools.StripRPGMakerCodes(Tools.StripTextMeshProTags(Tools.StripRichTextCodes(previousText))).Length : 0;
            SetFormattedText(subtitleText, previousText, subtitle);
            if (accumulateText) 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);
            }
        }

        previousSpeakerID = subtitle.speakerInfo.id;
    }

    public static Color NodeColor_Orange = new Color(1f, 0.5f, 0);
    public static Color NodeColor_Gray = new Color(0.9f, 0.9f, 0.9f);
    public static Color NodeColor_Blue = new Color(0.4f, 0.6f, 1f);
    public static Color NodeColor_Green = new Color(0, 1f, 0);
    public static Color NodeColor_Red = new Color(1f, 0.1f, 0.1f);

    private Color NodeColorStringToColor(string s)
    {
        switch (s)
        {
            case "Aqua":
                return Color.cyan;
            case "Blue":
                return NodeColor_Blue;
            case "Gray":
                return NodeColor_Gray;
            case "Green":
                return NodeColor_Green;
            case "Grey":
                return Color.gray;
            case "Orange":
                return NodeColor_Orange;
            case "Red":
                return NodeColor_Red;
            case "Yellow":
                return Color.yellow;
            default:
                return Tools.WebColor(s);
        }
    }
}
[/list]
User avatar
Tony Li
Posts: 20677
Joined: Thu Jul 18, 2013 1:27 pm

Re: [HOWTO] How To: Color Actor Name and Indent Text

Post by Tony Li »

Hi,

Are you using a very old version of the Dialogue System? Can you back up your project and update to the current version?
Post Reply