Page 1 of 1

Quest entries order?

Posted: Thu Nov 28, 2024 3:08 pm
by marafrass
Heya Tony!

Quick question about quest entries (subtasks) in the quest tracker UI. I've noticed that they're automatically arranged by number - is there any way to make them appear in the order which they're marked as active? For example, if I've got these entries in a quest;
1. The guy has asked you for cheese.
2. You gave the guy some cheese.
3. The guy wants blue cheese specifically.

Let's say I speak to the NPC and he asks for cheese, and I agree to the quest. (#1 is added to the tracker) I then ask in a subdialogue what kind of cheese he wants, and he specifies that he wants blue cheese. (#3 is added to the tracker) I finish the quest, and finally, #2 is added. If I check the tracker now, the entries will still be in the order in which I originally created them (1,2,3). Is there an existing way to make the tracker instead show 1,3,2?

Re: Quest entries order?

Posted: Thu Nov 28, 2024 3:16 pm
by Tony Li
Hi,

You'll either need to switch the order of the entries (so "wants blue cheese" is second) in the Dialogue Editor or do a bit of custom scripting. If it won't work to switch the order of the entries, let me know and I'll describe how to set up the scripting.

Re: Quest entries order?

Posted: Thu Nov 28, 2024 4:15 pm
by marafrass
I've already got tons of dialogues set up with the existing entries, so any advice on how to set up the custom scripting would be really helpful!

Re: Quest entries order?

Posted: Thu Nov 28, 2024 8:51 pm
by Tony Li
I'll put together an example script tomorrow and post it here.

Re: Quest entries order?

Posted: Thu Nov 28, 2024 9:16 pm
by marafrass
Much appreciated, take your time!

Re: Quest entries order?

Posted: Fri Nov 29, 2024 8:33 pm
by Tony Li
Hi,

Here's the scripts and an example scene:

DS_QuestEntryOrderExample_2024-11-29.unitypackage

The RecordQuestEntryOrder script goes on the Dialogue Manager and records the order in which quest entries were activated. It stores this in a DS variable that it creates at runtime.

The OrderedQuestTrackerHUD script replaces StandardUIQuestTracker, and OrderedQuestLogWindow replaces StandardUIQuestLogWindow on your UIs. You can replace them in-place.

I'll copy the scripts in the package here, too, for reference:

RecordQuestEntryOrder.cs

Code: Select all

using System.Collections.Generic;
using UnityEngine;

namespace PixelCrushers.DialogueSystem.Examples
{

    // Add this script to the Dialogue Manager.
    public class RecordQuestEntryOrder : MonoBehaviour
    {
        
        // For each quest, we'll store the order to show entries in this variable:
        public static string GetEntryOrderVariableName(string quest)
        {
            return $"EntryOrder.{DialogueLua.StringToTableIndex(quest)}";
        }

        // If a quest entry has become active, add it to the order variable:
        public void OnQuestEntryStateChange(QuestEntryArgs args)
        {
            var entryState = QuestLog.GetQuestEntryState(args.questName, args.entryNumber);
            if (entryState == QuestState.Active)
            {
                var orderVariableName = RecordQuestEntryOrder.GetEntryOrderVariableName(args.questName);
                var orderString = DialogueLua.GetVariable(orderVariableName).asString;
                if (!string.IsNullOrEmpty(orderString))
                {
                    // Make sure the entry isn't already in the order string:
                    var order = new List<string>(orderString.Split(';'));
                    if (order.Contains(args.entryNumber.ToString())) return;
                }
                // Add it to the order string:
                if (!string.IsNullOrEmpty(orderString)) orderString += ";";
                orderString += args.entryNumber;
                DialogueLua.SetVariable(orderVariableName, orderString);
            }
        }

    }

}
OrderedQuestTrackerHUD.cs

Code: Select all

namespace PixelCrushers.DialogueSystem.Examples
{

    // This subclass of StandardUIQuestTracker observes quests' entry order variables.
    public class OrderedQuestTrackerHUD : StandardUIQuestTracker
    {

        protected override void SetupQuestTrackInstance(StandardUIQuestTrackTemplate questTrack, string quest, string heading)
        {
            var orderVariableName = RecordQuestEntryOrder.GetEntryOrderVariableName(quest);
            var orderString = DialogueLua.GetVariable(orderVariableName).asString;

            // If there's no entry order variable, use the base method:
            if (string.IsNullOrEmpty(orderString))
            {
                base.SetupQuestTrackInstance(questTrack, quest, heading);
                return;
            }

            // Otherwise add entries in the order specified in the variable:
            if (questTrack == null) return;
            questTrack.Initialize();
            var questState = QuestLog.GetQuestState(quest);
            questTrack.SetDescription(heading, questState);
            int entryCount = QuestLog.GetQuestEntryCount(quest);
            var order = orderString.Split(';');
            foreach (string entryNumberString in order)
            {
                if (int.TryParse(entryNumberString, out var entryNum))
                {
                    if (!(1 <= entryNum && entryNum <= entryCount)) continue;
                    var entryState = QuestLog.GetQuestEntryState(quest, entryNum);
                    var entryText = FormattedText.Parse(GetQuestEntryText(quest, entryNum, entryState), DialogueManager.masterDatabase.emphasisSettings).text;
                    if (!string.IsNullOrEmpty(entryText))
                    {
                        questTrack.AddEntryDescription(entryText, entryState);
                    }
                }
            }
        }


    }

}
OrderedQuestLogWindow.cs

Code: Select all

namespace PixelCrushers.DialogueSystem.Examples
{

    // This subclass of StandardUIQuestLogWindow observes quests' entry order variables.
    public class OrderedQuestLogWindow : StandardUIQuestLogWindow
    {

        protected override void RepaintSelectedQuest(QuestInfo quest)
        {
            if (quest == null)
            {
                base.RepaintSelectedQuest(quest);
                return;
            }

            var orderVariableName = RecordQuestEntryOrder.GetEntryOrderVariableName(quest.Title);
            var orderString = DialogueLua.GetVariable(orderVariableName).asString;

            // If there's no entry order variable, use base method:
            if (string.IsNullOrEmpty(orderString))
            {
                base.RepaintSelectedQuest(quest);
                return;
            }

            // Otherwise show entries in the order specified in the variable:
            detailsPanelContentManager.Clear();

            // Title:
            var titleInstance = detailsPanelContentManager.Instantiate<StandardUITextTemplate>(questHeadingTextTemplate);
            titleInstance.Assign(quest.Heading.text);
            detailsPanelContentManager.Add(titleInstance, questDetailsContentContainer);

            // Description:
            var descriptionInstance = detailsPanelContentManager.Instantiate<StandardUITextTemplate>(questDescriptionTextTemplate);
            descriptionInstance.Assign(quest.Description.text);
            detailsPanelContentManager.Add(descriptionInstance, questDetailsContentContainer);

            // Entries:
            var order = orderString.Split(';');
            for (int i = 0; i < order.Length; i++)
            {
                if (int.TryParse(order[i], out var entryNum))
                {
                    if (!(1 <= entryNum && entryNum <= quest.Entries.Length)) continue;
                    var entryTemplate = GetEntryTemplate(quest.EntryStates[entryNum - 1]);
                    if (entryTemplate != null)
                    {
                        var entryInstance = detailsPanelContentManager.Instantiate<StandardUITextTemplate>(entryTemplate);
                        entryInstance.Assign(quest.Entries[entryNum - 1].text);
                        detailsPanelContentManager.Add(entryInstance, questDetailsContentContainer);
                    }
                }
            }

            // Abandon button:
            if (isShowingActiveQuests && QuestLog.IsQuestAbandonable(quest.Title))
            {
                var abandonButtonInstance = detailsPanelContentManager.Instantiate<StandardUIButtonTemplate>(abandonButtonTemplate);
                detailsPanelContentManager.Add(abandonButtonInstance, questDetailsContentContainer);
                abandonButtonInstance.button.onClick.AddListener(ClickAbandonQuestButton);
            }
        }

    }

}

Re: Quest entries order?

Posted: Sat Nov 30, 2024 12:58 am
by marafrass
Just finished implementing everything as you instructed, and it all works perfectly. Amazing stuff man, thank you so much! Going above and beyond as always. Sorry if I took time away from a day off, by the way - didn't realize most people were taking today and yesterday off!

Thanks so much once again, and have a great weekend.

Re: Quest entries order?

Posted: Sat Nov 30, 2024 6:36 am
by Tony Li
Glad to help! You have a great weekend, too!