Showing active node in Quest HUD only when Quest is selected in Journal

Announcements, support questions, and discussion for Quest Machine.
Post Reply
jlhacode
Posts: 77
Joined: Fri Jul 03, 2020 6:23 am

Showing active node in Quest HUD only when Quest is selected in Journal

Post by jlhacode »

I want to show the Quest HUD Text only for the quest that I last selected in the Quest Journal. Is there already a built-in way to do this? If not, what would be the best-practice approach for doing so?
User avatar
Tony Li
Posts: 21926
Joined: Thu Jul 18, 2013 1:27 pm

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by Tony Li »

Hi,

Tick the Quest Journal component's UI Settings > Only Track One Quest At A Time.
jlhacode
Posts: 77
Joined: Fri Jul 03, 2020 6:23 am

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by jlhacode »

Hi there Tony,

Let me clear up my use case a little more.

I removed the background & clickable ui for the normal quest tracker toggle, so the only thing that shows is the tracking marker if a quest is tracked.

1. In my journal UI prefab, I have a single "Track Quest" button.
- When I select a quest that doesn't have any HUD text for its current state, I would like the "Track Quest" button to be disabled. If the quest has HUD text for its current state, then I'd like to enable it.
- When pressed, the track quest button should start tracking the quest that's selected.

2. When I'm assigned a new quest, it should get tracked only if another quest isn't already being tracked.

3. I would like to add indicators for unread quests in the Quest Selection Panel.

For #1. I think the way forward would be to override the UnityUIQuestJournalUI.SelectQuest method, but that's as far as I'm getting. I know that I need to call the selected ToggleTemplate's onToggleChanged.Invoke(value, m_data), but the only way I can think of doing that (without having the required dependencies) is... maybe with an event?

For #2 & #3, I'm not quite sure where to start.

Sorry for the questions. This area of the code is pretty difficult for me to read, but I'm certainly at fault since I'm not very accustomed to tracing delegates. My mother tongue is Java, and my code at work is written in Kotlin :?
User avatar
Tony Li
Posts: 21926
Joined: Thu Jul 18, 2013 1:27 pm

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by Tony Li »

Hi,

Quest Machine's UIs (journal, HUD, dialogue, alert) share a lot of functionality. That shared functionality is in their parent class, UnityUIBaseUI. Since we don't know ahead of time how much content the UIs will need to show, the UIs work by way of template UI elements (text, image, button, etc).

In addition, they use the MessageSystem to listen for messages such as "Refresh UIs" to know when to refresh their content, such as when the player accepts a new quest. When a UI refreshes itself, it gets a list of quests. For example, the UnityUIQuestJournalUI gets the QuestJournal's quest list. Then it goes through each quest and gets the quest's list of content to currently display. It starts with a container, which is just a UI subpanel to group UI elements. For each piece of content, it adds an instance of some type of template to the container.
jlhacode wrote: Mon Apr 05, 2021 8:40 pm 1. In my journal UI prefab, I have a single "Track Quest" button.
- When I select a quest that doesn't have any HUD text for its current state, I would like the "Track Quest" button to be disabled. If the quest has HUD text for its current state, then I'd like to enable it.
- When pressed, the track quest button should start tracking the quest that's selected.
The UnityUIQuestNameButtonTemplate class is a template for a quest name, icon, and tracking toggle. Make a subclass of UnityUIQuestNameButtonTemplate and override the Assign method:

Code: Select all

public override void Assign(Quest quest, ToggleChangedDelegate trackToggleDelegate)
{
    if (quest == null) return;
    base.Assign(quest, trackToggleDelegate);
    if ((quest.GetState() == QuestState.Active) && quest.isTrackable)
    {
        // If quest doesn't have HUD content, hide the tracking toggle:
        var hudContents = quest.GetContentList(QuestContentCategory.HUD);
        if (hudContents.Count == 0) 
        {  
            trackToggleTemplate.gameObject.SetActive(false);
        }
    }
}
Locate your quest journal UI's Active Quest Name Template GameObject. Replace the UnityUIQuestNameButtonTemplate script with your subclass. To replace it in place and keep the references, change the Inspector to Debug mode and drag your subclass script into the Script field.
jlhacode wrote: Mon Apr 05, 2021 8:40 pm2. When I'm assigned a new quest, it should get tracked only if another quest isn't already being tracked.
Make a subclass of QuestJournal or add a new script to the player. If you subclass QuestJournal, override the AddQuest method:

Code: Select all

public override Quest AddQuest(Quest quest)
{
    base.AddQuest(quest);
    if (quest.isTrackable)
    {
        var currentTrackedQuest = questList.Find(x => x.showInTrackHUD);
        if (currentTrackedQuest == null)
        {
            quest.showInTrackHUD = true;
            RepaintUIs();
        }
    }
}
jlhacode wrote: Mon Apr 05, 2021 8:40 pm3. I would like to add indicators for unread quests in the Quest Selection Panel.
Each quest has a tag dictionary. This is normally used to record values such as {QUESTER} and {QUESTGIVER}. But you can also add your own tags to it. You can add a "READ" tag when the player has read a quest.

In your UnityUIQuestNameButtonTemplate subclass's overridden Assign method, add something like:

Code: Select all

public GameObject unreadIndicator; //<--Assign in inspector.

public override void Assign(Quest quest, ToggleChangedDelegate trackToggleDelegate)
{
    if (quest == null) return;
    base.Assign(quest, trackToggleDelegate);
    if (quest.GetState() == QuestState.Active) && quest.isTrackable)
    {
        // If quest doesn't have HUD content, hide the tracking toggle:
        var hudContents = quest.GetContentList(QuestContentCategory.HUD);
        if (hudContents.Count == 0) 
        {  
            trackToggleTemplate.gameObject.SetActive(false);
        }
    }
    var isUnread = !quest.tagDictionary.Contains("READ");
    unreadIndicator.SetActive(isUnread);
    if (isUnread)
    {
        // If unread, configure the button to add the "READ" tag when clicked:
        buttonTemplate.button.OnClick.AddListener(() => 
        {
            quest.tagDictionary.SetTag("READ", true);
        });
    }
}
(Note: I typed this code directly into the reply; it may have typos, but it should convey the gist of what you need to do.)
jlhacode
Posts: 77
Joined: Fri Jul 03, 2020 6:23 am

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by jlhacode »

So, there was a couple issues:

#1
So, I think there was a miscommunication. I don't want to use the tracking toggle next to the Quest Name button. I have one single button that lives by itself on the Journal UI (not on the individual Active Quest Name Template instance). I would like for that button to show the tracking icon that's next to the selected Active Quest Button. Preferably, the tracking toggle in the Active Quest Name Template should be able toggle quest tracking off, but not on - toggling on would be the independent tracking button's job


#2

Code: Select all

public override Quest AddQuest(Quest quest)
{
    base.AddQuest(quest);
    if (quest.isTrackable)
    {
        var currentTrackedQuest = questList.Find(x => x.showInTrackHUD);
        if (currentTrackedQuest == null)
        {
            quest.showInTrackHUD = true;
            RepaintUIs();
        }
    }
}
- For this, there needs to be a return statement. I modified your gist like so:

Code: Select all

    public override Quest AddQuest(Quest quest) {
        quest = base.AddQuest(quest);

        if (quest.isTrackable) {
            var currentTrackedQuest = questList.Find(x => x.showInTrackHUD);
            if (currentTrackedQuest == null) {
                quest.showInTrackHUD = true;
                RepaintUIs();
            }
        }

        return quest;
    }
but there was no difference in behavior :/

#3 Works well though!
User avatar
Tony Li
Posts: 21926
Joined: Thu Jul 18, 2013 1:27 pm

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by Tony Li »

Hi,

For #1, can you share a screenshot or mockup of the UI?

For #2, in what way did it not work? Are your quests' Is Trackable checkboxes ticked?
jlhacode
Posts: 77
Joined: Fri Jul 03, 2020 6:23 am

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by jlhacode »

#1 The star indicates which quest is being tracked
Screen Shot 2021-04-06 at 2.19.04 PM.png
Screen Shot 2021-04-06 at 2.19.04 PM.png (34.54 KiB) Viewed 1538 times

For #2:
- 'Is Trackable' is enabled for the quests.

- For my test I have 2 quests that both have HUD text on the node that becomes active once the quest is assigned to the player. When I assign myself the first quest I begin auto tracking it - this is working as intended, because I'm not tracking any quests initially. I then assign myself the second quest, which changes the Quest HUD text (unintended since i'm already tracking another node). The tracking indicator shows that the tracked quest has switched from the first quest to the second one when I open the Quest Journal UI.

pseudocode for the intended behavior would spill out like this
- AssignQuestToPlayer(Quest quest) called
...
- if (selectedQuest.activeQuestNode.HasHUDText && !anyQuestBeingTrackedOnHUD) then trackQuestOnHUD(quest)
User avatar
Tony Li
Posts: 21926
Joined: Thu Jul 18, 2013 1:27 pm

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by Tony Li »

Hi,

The gist of the code is the same as my previous reply, but it needs a few tweaks/cleanup. Here's an example scene:

QM_CustomTrackingExample_2021-04-06.unitypackage (Unity 2020.1)

It uses these scripts:

CustomQuestJournal.cs: Subclass of QuestJournal

Code: Select all

using PixelCrushers.QuestMachine;

// When adding quest, only track if no other quest is being tracked.
public class CustomQuestJournal : QuestJournal
{
    public override Quest AddQuest(Quest quest)
    {
        var originalShowInTrackHUD = quest.showInTrackHUD;
        quest.showInTrackHUD = false;
        quest = base.AddQuest(quest);

        if (quest.isTrackable)
        {
            var currentTrackedQuest = questList.Find(x => x.showInTrackHUD);
            if (currentTrackedQuest == null)
            {
                quest.showInTrackHUD = true;
                RepaintUIs();
            }
            else
            {
                quest.showInTrackHUD = false;
            }
        }

        return quest;
    }
}
CustomQuestJournalUI.cs: Subclass of UnityUIQuestJournalUI. Hook up Track button to TrackSelectedQuest().

Code: Select all

using PixelCrushers.QuestMachine;

// Add method to track selected quest, for general Track button.
public class CustomQuestJournalUI : UnityUIQuestJournalUI
{
    public void TrackSelectedQuest()
    {
        if (selectedQuest != null) selectedQuest.showInTrackHUD = true;
    }
}
CustomQuestNameButtonTemplate.cs: Subclass of UnityUIQuestNameButtonTemplate. Assign a trackingIndicator GO.

Code: Select all

using UnityEngine;
using PixelCrushers.QuestMachine;

// Hide track toggle. Show tracking indicator for currently-tracked quest.
public class CustomQuestNameButtonTemplate : UnityUIQuestNameButtonTemplate
{
    public GameObject trackingIndicator;

    public override void Assign(Quest quest, ToggleChangedDelegate trackToggleDelegate)
    {
        base.Assign(quest, trackToggleDelegate);
        trackToggleTemplate.gameObject.SetActive(false);
        if (trackingIndicator != null) trackingIndicator.SetActive(quest.showInTrackHUD);
    }
}
Remember to tick the player's Quest Journal > UI Settings > Only Track One Quest At A Time.
jlhacode
Posts: 77
Joined: Fri Jul 03, 2020 6:23 am

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by jlhacode »

Sorry for the delay, I added this ticket to my current sprint and wrapped it up.

Your scripts worked like a charm. Thanks for the awesome support as always Tony!
User avatar
Tony Li
Posts: 21926
Joined: Thu Jul 18, 2013 1:27 pm

Re: Showing active node in Quest HUD only when Quest is selected in Journal

Post by Tony Li »

Glad to help!
Post Reply