Custom Quest Log questions

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Custom Quest Log questions

Post by urrmurrmur »

Hi,

The game I am currently working on has some particular quest functionality that is not included in the default DSFU - or at least I don't think it is. Specifically, I want each quest to have a timestamp which is updated every time the user performs an action related to this quest, and only the two most recent quests should be shown in the tracker HUD. I've managed to include a timestamp and update it by adding custom delegate implementations for SetQuest(Entry)State, but that's not sufficient. I also want the quest timestamp to be updated when a variable related to that quest changes value, for instance.

So I've run into a few questions.
  1. What is the best approach for writing ones own QuestLog class? I can get part of the way with the provided delegate overrides, but not for everything I want. The QuestLog also doesn't seem to be designed with overriding the full class in mind, since it's essentially a collection of static methods that are being called from throughout DSFU. I've resorted to adapting the source code of the QuestLog class itself, which is fine as long as I don't need to upgrade to a newer version of DSFU.
  2. When are the AddQuest methods executed? I added some prints to those methods, but they never seem to run - unless these methods are triggered from the editor somehow.
  3. Is there a way (a trigger or something) to execute an action on variable value change? I've experimented with ConditionObserver, but it seems like that's meant to trigger actions when a variable becomes larger / smaller / equal than a certain value, rather than "on any variable change".
User avatar
Tony Li
Posts: 22161
Joined: Thu Jul 18, 2013 1:27 pm

Re: Custom Quest Log questions

Post by Tony Li »

Hi,
urrmurrmur wrote: Mon Jul 19, 2021 9:07 amWhat is the best approach for writing ones own QuestLog class? I can get part of the way with the provided delegate overrides, but not for everything I want. The QuestLog also doesn't seem to be designed with overriding the full class in mind, since it's essentially a collection of static methods that are being called from throughout DSFU. I've resorted to adapting the source code of the QuestLog class itself, which is fine as long as I don't need to upgrade to a newer version of DSFU.
One option is to ignore the QuestLog class entirely and implement your own quest system. (This is what the Dialogue System's Quest Machine integration does, for example.)

However, if you want all of the features of the Dialogue System's quest system (quest log window, quest tracker HUD, quest states in saved games, etc.), then you could write a wrapper class that adds your additional functionality. For example, say you track the quest timestamp in a custom field named "Timestamp". Then you could add a few methods such as:
  • UpdateQuestTimestamp(string quest)
  • UpdateQuest[Entry]State(string quest)
  • UpdateQuestVariable(string quest, string variable, int newValue)
that all update the timestamp.
urrmurrmur wrote: Mon Jul 19, 2021 9:07 amWhen are the AddQuest methods executed?
They're only executed if you call them manually to create a new quest at runtime.
urrmurrmur wrote: Mon Jul 19, 2021 9:07 amIs there a way (a trigger or something) to execute an action on variable value change? I've experimented with ConditionObserver, but it seems like that's meant to trigger actions when a variable becomes larger / smaller / equal than a certain value, rather than "on any variable change".

For the quest tracker, you can handle that in your quest system wrapper class or in a quest tracker class (e.g., a subclass of StandardUIQuestTracker). For the former, in UpdateQuestTimestamp() you can check the quests and make sure only the two most recently updated quests are tracked. For the latter, you can override the UpdateTracker() method to verify that only the two most recently updated quests are tracked, then call the base method.
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Re: Custom Quest Log questions

Post by urrmurrmur »

Thanks. If possible, I would indeed like to stick with a (lightly) modified version of the Dialogue System's quest system, as I'm using a number of elements from it.

Your answer helps me along, but the latter part still isn't entirely clear to me yet. I'm using the Dialogue System's built-in variables to track, for example, the amount of a certain type of item that have been picked up. I'm updating those variables through a subclass of IncrementOnDestroy. But that class doesn't know about the quests that the variable is involved in, which seems like good design, so I'd like to keep it that way.

But then somehow I need the QuestLog wrapper class to be notified when a variable has updated. Right now I use a Condition Observer to do that when a variable crosses a certain threshold, for instance, to change the quest state. Ideally, I'd have a similar system that can notify a quest to change its timestamp (using a custom method, as you describe) it observes a variable's state has changed. Is something like that present in DSFU, or do I need to write my own system for that?
User avatar
Tony Li
Posts: 22161
Joined: Thu Jul 18, 2013 1:27 pm

Re: Custom Quest Log questions

Post by Tony Li »

Hi,

Let's say you have a class called EnhancedQuestLog that has extra methods such as UpdateQuestTimestamp(). You could add another method UpdateQuestVariable(string variableName) that receives a variable name and updates any relevant quests.

In your subclass of IncrementOnDestroy, override Awake to configure the onIncrement UnityEvent to call EnhancedQuestLog.UpdateQuestVariable(). Example:

Code: Select all

public class MyIncrementOnDestroy : IncrementOnDestroy
{
    protected override void Awake()
    {
        base.Awake();
        onIncrement.AddListener(() => EnhancedQuestLog.UpdateQuestVariable(actualVariableName));
    }
}
I can suggest two ways to implement EnhancedQuestLog.UpdateQuestVariable():

1. Scan the text of all quests (e.g., the Description field and all "Entry #" fields) for [var=variable]] tags to identify variables, or

2. Add a custom field named "Variable" containing the quest's variable name.

In either case, if the quest uses the variable passed to UpdateQuestVariable(), you can call UpdateQuestTimestamp().
Post Reply